;=========================================================================
; Atari 810 revision E firmware disassembly
;
; Memory map:
;	A11 = 1 -> 2316 ROM
;	A11 = 0, A9 = 1, A8 = 1 -> 6532 RIOT registers
;	A11 = 0, A9 = 0, A8 = 1 -> 6532 RIOT memory (128 bytes)
;	A11 = 0, A8 = 0, A7 = 1 -> 6810 memory (128 bytes)
;	A11 = 0, A8 = 0, A7 = 0 -> FDC
;
;	1xxxxxxxxxxx 2316 ROM
;	0x11xxxxxxxx 6532 registers
;	0x01xxxxxxxx 6532 RAM
;	0xx01xxxxxxx 6810 memory
;	0xx00xxxxxxx 1771 FDC
;
; Canonical memory map:
;	$000-003	FDC
;	$080-0FF	6810 RAM
;	$180-1FF	6532 RAM
;	$380-3FF	6532 registers
;	$800-FFF	Firmware ROM
;
; RIOT port A ($0380)
;	bit 0	Drive code B sense
;	bit 1	Spindle motor control (output)
;	bit 2	Drive code A sense
;	bit 3	Not connected (output)
;	bit 4	Write protect sense (1 = write protected)
;	bit 5	Jumper
;	bit 6	FDC IRQ
;	bit 7	FDC DRQ
;
; RIOT port B ($0382)
;	bit 0	SIO data input (device to computer)
;	bit 1	SIO ready sense
;	bit 2	Stepper phase 1 (output)
;	bit 3	Stepper phase 2 (output)
;	bit 4	Stepper phase 3 (output)
;	bit 5	Stepper phase 4 (output)
;	bit	6	SIO command sense (1 = asserted)
;	bit 7	SIO data output, inverted (computer to device)
;
; $80-FF	sector buffer
; $01D0		command frame byte 1 (device ID)
; $01D1		command frame byte 2 (command)
; $01D2		command frame byte 3 (sector number lo)
; $01D3		command frame byte 4 (sector number hi)
; $01D4		command frame checksum
; $01D4		transmit byte
; $01D5		sector checksum
; $01D7		idle counter setting
; $01D8		step temp
; $01D9		current track number (inverted)
; $01DA		step counter
; $01DB		status byte 1 (drive status)
;	bit 0 = 1: last command frame invalid
;	bit 1 = 1: last data frame invalid
;	bit 2 = 1: unsuccessful PUT operation
;	bit 3 = 1: write protect related failure
;	bit 4 = 1: motor running
; $01DC		status byte 2 (FDC status)
; $01DD		status byte 3 (timeout)
; $01DE		status byte 4 (unused)
; $01DF		status checksum
; $01E0		inverted target track number (0-39)
; $01E1		inverted target sector number (1-18)
; $01E2		flags
;	bit 0 = 1: SIO not ready last time
;	bit 1 = 1: bad command frame checksum
;	bit 2 = 1: drive has been idled
;	bit 3 = 1: bad sector (format command), verify enabled (put/write commands)
;	bit 5 = 1: idle loop is active; otherwise, running cmd loop directly
;	bit 7 = 1: processing command
; $01E5		format command: verify retry counter
; $01E6		format command: current bad sector list index
; $01E7		format command: logical sector calc temp
; $01E8		format command: logical sector calc temp
; $01E9		format command: logical sector calc temp
; $01EA		idle counter (set to $01D7 by activity)
;

		opt		h-f+
		org		$0800

L0800	ldx		#$FF
		txs
		cld
		lda		#$02
		sta		$0381
		ldx		#$3C
		stx		$0383
		lda		#$00
		sta		$0380
		sta		$01DB
		lda		#$35
		sta		$01E2
		lda		#$1E
		sta		$01D7
		sta		$01EA
		lda		#$04
		sta		$01D6
L0828	jsr		L0886
		jmp		L0828

;=========================================================================
L082E	lda		#$E0
		sta		$01DD
		lda		#$00
		sta		$01DE
		ldx		#$FF
		txs
		jsr		L0F21
		lda		#$D8
		jsr		L0D2C
		sty		$01DA
L0846	lda		#$32
		sta		$039F
		lda		#$20
		jsr		L0DF3
L0850	jsr		L0886
		lda		$0395
		bpl		L0850
		dec		$01EA			;decrement idle counter
		bpl		L0846
L085D	ldx		#$80			;step toward track 39
		ldy		$01DA			;check if we still need to stop
		beq		L0874			;exit if we don't
		jsr		L0D3D			;step head
		sty		$01DA			;update track
L086A	jsr		L0886			;check for command
		lda		$0395			;read interrupt status
		bpl		L086A			;wait until timer expired
		bmi		L085D			;continue stepping

L0874	lda		#$00			;
		sta		$0380
		sta		$0382			;all stepper motor phases off
		lda		#$DF
		jsr		L0DFA
		lda		#$04
		jsr		L0DF3
		;fall through
		
;=========================================================================
L0886	lda		$0382			;check SIO ready signal
		and		#$02			; "
		bne		L08C0			;jump if not ready
		lda		$01E2			;load flags
		and		#$01			;check bit 0 (SIO was not ready)
		bne		L08B3			;jump if we're seeing not ready -> ready
		bit		$0382			;check command bit
		bvc		L08A8
		bit		$01E2
		bvc		L08C8
		lda		#$29
		jsr		L0DCC
		bit		$0382
		bvs		L08C8
L08A8	lda		$01E2
		and		#$60
		bne		L08B2
		jmp		L0886

L08B2	rts

L08B3	lda		#$29			;set 100ms delay
		jsr		L0DCC			;wait for SIO signals to stabilize
		lda		#$FE			;clear bit 0 (SIO not ready state)
		jsr		L0DFA			;do it
		jmp		L0886			;return to main loop

;=========================================================================
L08C0	lda		#$01
		jsr		L0DF3
		jmp		L08A8

;=========================================================================
L08C8	ldx		#$00
		lda		#$05
		sta		$01E3
		jsr		L0D94
		ldx		#$00
		dec		$01E3
		jsr		L0E4B
		bne		L08F5
		ldx		#$34
		lda		$0380
		and		#$05
		beq		L08EF
		cmp		#$04
		beq		L08EE
		cmp		#$01
		beq		L08F0
		dex
L08EE	dex
L08EF	dex
L08F0	cpx		$01D0
		beq		L0902
L08F5	bit		$0382
		bvs		L08F5
		lda		#$FD
		jsr		L0DFA
		jmp		L0886

;=========================================================================
L0902	jsr		L0908
		jmp		L0886

;=========================================================================
L0908	lda		$01D1
		ldx		#$07
L090D	cmp		$093B,X
		beq		L0917
		dex
		bpl		L090D
		bmi		L0924
L0917	lda		$0943,X
		sta		$FE
		lda		$094B,X
		sta		$FF
		jmp		($00FE)

;=========================================================================
L0924	lda		#$01
		jsr		L0DE9
		jsr		L0DD8
L092C	bit		$0382
		bvs		L092C
		lda		#$4E			;NAK
		jsr		L0E8C			;transmit byte
		lda		#$FD
		jmp		L0DFA

L093B	dta		$20, $21, $50, $52, $53, $54, $57, $FF
L0943	dta		<L0953, <L097C, <L0B20, <L0C04, <L0BD0, <L0C4D, <L0B1B, <$0180
L094B	dta		>L0953, >L097C, >L0B20, >L0C04, >L0BD0, >L0C4D, >L0B1B, >$0180

;=========================================================================
; Execute code ($20)
;
L0953	jsr		L0E85			;send command ACK
		jsr		L0E0A
		jsr		L0E63			;compute and compare checksums
		beq		L0961			;jump if checksum match
		jmp		L0B82			;send NAK

L0961	jsr		L0E8A			;send data frame ACK
		jsr		$0080			;execute received buffer
		jmp		L0B7D			;send complete

;=========================================================================
L096A	dta		$EF, $F1, $F3, $F5, $F7, $F9, $FB, $FD
		dta		$EE, $F0, $F2, $F4, $F6, $F8, $FA, $FC
		dta		$FE, $ED
		
;=========================================================================
; Format command ($21)
;
L097C	jsr		L0E85			;send command ACK
		lda		#$6A
		sta		$FA
		lda		#$09
		sta		$FB
		jsr		L0F32
		jsr		L0FCD
		lda		#$FF
		sta		$01E0
		jsr		L0CD2
		lda		$0380
		and		#$10
		beq		L09A4
		lda		#$08
		jsr		L0DE2
		jmp		L0A67

L09A4	lda		#$FF
		sta		$FD
		jsr		L09C6
L09AB	dec		$FD
		lda		$FD
		cmp		#$D7
		beq		L09BB
		ldx		#$80
		jsr		L09BE
		jmp		L09AB

L09BB	jmp		L0A77

L09BE	lda		#$02
		jsr		L0DCC
		jsr		L0D3D
L09C6	lda		#$11
		sta		$FC
		lda		$0394
		ldy		#$FF
		ldx		#$FF
		lda		#$0B
		sta		$00
		jsr		L0A5F
		lda		#$0D
		sta		$039F
		jsr		L0A52
		stx		$039F
		ldy		#$03
		jsr		L0A5F
		ldy		#$0B
		jsr		L0A52
L09ED	ldy		#$06
		jsr		L0A52
		ldy		#$01
		jsr		L0A5F
		ldy		$FD
		jsr		L0A5F
		ldy		#$FF
		jsr		L0A5F
		ldy		$FC
		lda		($FA),Y
		tay
		bit		$0380
		bmi		L0A12
L0A0B	bvs		L0A67
		bit		$0380
		bpl		L0A0B
L0A12	sty		$03
		ldy		#$FF
		jsr		L0A5F
		ldy		#$08
		jsr		L0A5F
		ldy		#$11
		jsr		L0A52
		ldy		#$04
		jsr		L0A5F
		ldy		#$80
		ldx		#$1A
		jsr		L0A52
		ldy		#$08
		jsr		L0A5F
		ldy		#$08
		ldx		#$FF
		jsr		L0A52
		jsr		L0A5F
		dec		$FC
		bmi		L0A4B
		jsr		L0A5F
		jsr		L0A5F
		jmp		L09ED

L0A4B	lda		#$2F
		sta		$00
		rts

L0A50	bvs		L0A67
L0A52	bit		$0380
		bpl		L0A50
		stx		$03
		dey
		bne		L0A52
		rts

L0A5D	bvs		L0A67
L0A5F	bit		$0380
		bpl		L0A5D
		sty		$03
		rts

L0A67	ldx		#$FF
		stx		$80
		stx		$81
		lda		$00
		eor		#$FF
		sta		$01DC			;store FDC status
		jmp		L0B13

L0A77	ldx		#$00
		stx		$01E6
L0A7C	lda		$01D9
		sta		$01
		lda		#$11
		sta		$FC
L0A85	ldy		$FC
		lda		($FA),Y
		sta		$02
		ldy		#$02
		sty		$01E5
L0A90	lda		$00
		eor		#$FF
		and		#$81
		bne		L0A90
		lda		#$77			;inverted $88 (read sector)
		sta		$00
		lda		#$FF
		sta		$039F
		ldx		#$7F
		jmp		L0AAB

L0AA6	bvs		L0AC0
		lda		$039C
L0AAB	bit		$0380
		bpl		L0AA6
		lda		$03
		dex
		bpl		L0AAB
		lda		$00
		eor		#$FF
		sta		$01DC
		and		#$1C
		beq		L0AD8
L0AC0	dec		$01E5
		bne		L0A90
		ldx		$01E6
		lda		#$08
		jsr		L0DF3
		jsr		L0F92
		inx
		stx		$01E6
		cpx		#$7A
		beq		L0AFA
L0AD8	ldy		$FC
		beq		L0AE9
		dey
		dey
		sty		$FC
		bpl		L0A85
		ldy		#$10
		sty		$FC
		jmp		L0A85

L0AE9	lda		$01D9
		cmp		#$FF
		beq		L0AFA
		ldx		#$00
		ldy		#$01
		jsr		L0D11
		jmp		L0A7C

L0AFA	lda		#$FF
		ldx		$01E6
		sta		$80,X
		inx
		sta		$80,X
		lda		$01E2
		and		#$08
		bne		L0B0E
		jmp		L0C2F			;send Complete and data frame

L0B0E	lda		#$F7
		jsr		L0DFA
L0B13	lda		#$04
		jsr		L0DE2
		jmp		L0C45

;=========================================================================
; Write sector ($57)
; Put sector ($50)
;
L0B1B	lda		#$08
		jsr		L0DF3
L0B20	jsr		L0D76
		bcc		L0B28
		jmp		L0924

L0B28	jsr		L0E85			;send command ACK
		jsr		L0F32
		jsr		L0E0A			;receive data frame
		jsr		L0E63			;compute and compare checksums
		bne		L0B82			;jump if checksum error
		jsr		L0E8A			;send data frame ACK
		jsr		L0FCD
		jsr		L0CCF
		lda		$0380
		and		#$10
		bne		L0B8F
L0B46	lda		#$57
		sta		$00
L0B4A	bvs		L0B66
		lda		$039C
		bit		$0380
		bmi		L0B5E
		jmp		L0B4A

L0B57	bvs		L0B66
L0B59	bit		$0380
		bpl		L0B57
L0B5E	inx
		lda		$80,X			;read next data byte
		sta		$03				;write to FDC
		jmp		L0B59

L0B66	jsr		L0C74
		lda		#$45			;Error
		bcs		L0B99
		lda		$01E2
		and		#$08
		beq		L0B7D
		jsr		L0BA0
		bcc		L0B7D
		lda		#$45
		bcs		L0B89
L0B7D	lda		#$43			;Complete
		jmp		L0B89

L0B82	lda		#$12
		jsr		L0DE9
		lda		#$4E
L0B89	jsr		L0E8C			;transmit byte
		jmp		L082E

L0B8F	lda		#$0C
		jsr		L0DE2
		lda		#$45
		jmp		L0B89

L0B99	cpy		#$00
		beq		L0B89
		jmp		L0B46

L0BA0	jsr		L0CF8
		ldy		#$01
L0BA5	inx
		lda		#$77
		sta		$00
L0BAA	bvs		L0BBD
		lda		$039C
L0BAF	bit		$0380
		bpl		L0BAA
		lda		$03
		cmp		$80,X
		bne		L0BCA
		inx
		bne		L0BAF
L0BBD	jsr		L0C74
		bcc		L0BC4
		bpl		L0BA5
L0BC4	lda		#$F7
		jsr		L0DFA
		rts

L0BCA	jsr		L0CB9
		jmp		L0BC4

;=========================================================================
; Read status ($53)
;
L0BD0	jsr		L0E85			;send command ACK
		ldx		#$0B
		ldy		#$0F
		sty		$01E3
		jsr		L0E4B
		sta		$01DF			;set status frame checksum
		lda		#$43
		sta		$01D4
		jsr		L0E72
		ldx		#$7A
		jsr		L0ED2
L0BED	ldy		$0160,X
		sty		$01D4
		jsr		L0ED5
		bpl		L0BED
		jsr		L0F18
		jsr		L0E01
		jsr		L0DD8
		jmp		L082E

;=========================================================================
; Read sector ($52)
;
L0C04	jsr		L0D76			;check sector number
		bcs		L0C4A			;skip if invalid
		jsr		L0E85			;send command ACK
		jsr		L0F32			;turn motor on
		jsr		L0FCD			;wait for motor spin-up
		jsr		L0CCF			;seek to track and setup fake index pulse
L0C15	lda		#$77			;inverted: %10001000 -> read sector
		sta		$00				;write FDC command
L0C19	bvs		L0C2A			;exit if FDC error
		lda		$039C			;reset RIOT timer IRQ
L0C1E	bit		$0380			;read DRQ/IRQ status
		bpl		L0C19			;keep looping if no DRQ
		lda		$03				;read byte
		inx						;next byte
		sta		$80,X			;store byte in buffer
		bpl		L0C1E			;continue until 128 bytes read
L0C2A	jsr		L0C74			;check status
		bcs		L0C43			;jump if error
L0C2F	lda		#$43			;Complete
L0C31	sta		$01D4			;store status code
		jsr		L0E63			;compute checksum of sector buffer
		sta		$01D5			;store checksum
		jsr		L0E72			;start SIO transmission
		jsr		L0EFB			;transmit sector
		jmp		L082E			;end of command

L0C43	bne		L0C15			;retry if there are still entries left
L0C45	lda		#$45			;Error
		jmp		L0C31			;send sector buffer and exit

L0C4A	jmp		L0924			;NAK the command and exit

;=========================================================================
; T command ($54)
;
L0C4D	jsr		L0E85			;send command ACK
		lda		$01D2			;copy AUX1,AUX2 -> $FE,FF
		sta		$FE				; "
		lda		$01D3			; "
		sta		$FF				; "
		ldy		#$7D			; "
L0C5C	lda		($FE),Y			;copy byte from source to transfer buffer
		sta		$0080,Y			; "
		dey						; "
		bpl		L0C5C			; "
		ldy		#$7F			;copy last two bytes
		lda		($FE),Y			; "
		pha						; "
		dey						; "
		lda		($FE),Y			; "
		sta		$FE				; "
		pla						; "
		sta		$FF				; "
		jmp		L0C2F			;send Complete and data frame

;=========================================================================
L0C74	lda		$00				;3		read FDC status
		eor		#$FF			;2		uninvert
		sta		$01DC			;4		save
		bne		L0C88			;2/3	jump if there wre errors
		clc						;2
		lda		#$FB			;2
		jsr		L0E03			;20		reset bit
L0C83	jsr		L0CF8			;
		dey
		rts

L0C88	and		#$10			;record not found?
		beq		L0CB9			;no, retry operation
		tya						;save retry counter
		pha						; "
		jsr		L0CF8			;
		lda		#$3F			;inverted %11000000 -> read address
		sta		$00				;write FDC command
L0C95	bvs		L0CB1			;jump if error
		lda		$039C			;read RIOT timer (clear timer IRQ)
		bit		$0380			;read port A
		bpl		L0C95			;jump if no DRQ
		lda		$03				;read track field
		sta		$01D9			;stash it
		and		#$03			;mask to two low bits
		tax						;->index
		lda		$0382			;read port B
		and		#$3C			;mask to active phases
		cmp		$0CCB,X			;check if phase matches
		beq		L0CB4			;do retry if so
L0CB1	jsr		L0EAE			;on wrong track -- recalibrate
L0CB4	jsr		L0CC2			;
		pla
		tay
L0CB9	lda		#$04
		jsr		L0DE2			;set unsuccessful PUT operation status bit
		sec
		jmp		L0C83

L0CC2	lda		$01E0
		jsr		L0D2C
		jmp		L0D11

L0CCB	dta		$30, $18, $0C, $24

;=========================================================================
L0CCF	jsr		L0F4F			;convert virtual sector to physical track/sector
L0CD2	lda		$0382			;read port B
		and		#$3c			;check if any stepper phases set
		bne		L0CDE			;skip if so
		lda		#$30			;energize phases 2+3
		sta		$0382			;do it
L0CDE	jsr		L0CC2
		lda		$01E2
		and		#$04
		beq		L0CF0
		jsr		L0D26
		lda		#$FB
		jsr		L0DFA
L0CF0	lda		#$10
		jsr		L0DE9
		ldy		$01D6
L0CF8	lda		#$2F
		sta		$00
		ldx		#$FF
L0CFE	dex
		bne		L0CFE
		lda		$01E0
		sta		$01
		lda		$01E1
		sta		$02
		clv
		dex
		stx		$039F
		rts

;=========================================================================
L0D11	beq		L0D25
L0D13	jsr		L0D3D
		beq		L0D1D
		jsr		L0D26
		bmi		L0D13
L0D1D	lda		#$50
		sta		$039E
		jsr		L0D26
L0D25	rts

L0D26	lda		$0395
		bpl		L0D26
		rts

;=========================================================================
L0D2C	ldx		#$00
		sec
		sbc		$01D9
		bpl		L0D3B
		ldx		#$80
		eor		#$FF
		clc
		adc		#$01
L0D3B	tay
		rts

;=========================================================================
;Head stepping routine (single step)
;
; Inputs:
;	X = step direction (positive or negative); bit 7=1 means ascending tracks
;	Y = number of tracks left
;
; Outputs:
;	Y = number of tracks left, -1
;	P.NZ = status after decrementing Y
;
L0D3D	lda		#$29		;~2625 cycles @ 500KHz = ~5.3ms
		sta		$039E		;RIOT: write timer, divide by 64, enable interrupt
		lda		$0382
		and		#$3C		;isolate stepper motor phase bits
		inx
		bmi		L0D5C
		inc		$01D9		;decrement current track number (inverted)
		lsr					;rotate stepper motor phase outputs down
		sta		$01D8
		and		#$02		;check if we shifted out of phase 1
		beq		L0D6E
		lda		#$20		;activate phase 4
		ora		$01D8
		bpl		L0D71
L0D5C	dec		$01D9		;increment current track number (inverted)
		asl					;rotate stepper motor phase outputs up
		sta		$01D8
		and		#$40		;check if we shifted out of phase 4
		beq		L0D6E
		lda		#$04		;activate phase 1
		ora		$01D8
		bpl		L0D71
L0D6E	lda		$01D8
L0D71	sta		$0382
		dey
		rts

;=========================================================================
; Check sector number
;	(29 cycles including JSR if sector=0)
;	(29 cycles including JSR if sector>=768)
;
L0D76	ldx		$01D3		;4		X:A = sector #
		lda		$01D2		;4
		beq		L0D88		;2/3
L0D7E	cpx		#$03		;2		check for sector >= 720
		bcs		L0D8C		;2/3
		cmp		#$D1		;2
		bcs		L0D8E		;2/3
		clc					;2		sector# is OK
		rts					;6

L0D88	cpx		#$00		;2		sector# == 0?
		bne		L0D7E		;2/3
L0D8C	sec					;2		invalid sector number
		rts					;6

L0D8E	cpx		#$02		;2
		beq		L0D8C		;2/3
		clc					;2
		rts					;6

;=========================================================================
; Receive command/protocol bytes
;
L0D94	lda		$0382
		bpl		L0D94
		txa
		beq		L0DC6
		lda		$01CF,X
		eor		#$FF
		sta		$01CF,X
L0DA4	nop
		nop
		nop
		ldy		#$78
L0DA9	nop
		nop
		nop
		nop
		lda		$0382
		rol
		ror		$01D0,X
		iny
		bpl		L0DA9
		inx
		cpx		$01E3
		bne		L0D94
		lda		$01CF,X
		eor		#$FF
		sta		$01CF,X
		rts

L0DC6	nop
		nop
		nop
		jmp		L0DA4

;=========================================================================
; Delay routine
;	([28 to 1303] + 1288*(A-1) cycles including JSR)
;
L0DCC	sta		$01E4			;4
L0DCF	dey						;512xA
		bne		L0DCF			;767xA
		dec		$01E4			;6xA
		bne		L0DCF			;3xA-1
		rts						;6

;=========================================================================
; Set drive status from motor state
;
L0DD8	lda		$0380		;read port A
		lsr					;check bit 1 (spindle motor control)
		lsr					; cont'd
		lda		#$10		;set motor running bit
		bcs		L0DE2		;set bit if motor is running
		rts					;don't set motor running bit
L0DE2	ora		$01DB		;4		set drive status bit
		sta		$01DB		;4
		rts					;6

;=========================================================================
; Reset drive status
;
; Input:
;	A = new drive status
;
; Timing:
;	36 cycles including JSR
;
L0DE9	pha					;3
		lda		#$00		;2
		sta		$01DB		;4		clear all drive status bits
		pla					;4
		jmp		L0DE2		;3

;=========================================================================
L0DF3	ora		$01E2
		sta		$01E2
		rts

;=========================================================================
L0DFA	and		$01E2
		sta		$01E2
		rts

;=========================================================================
L0E01	lda		#$08
L0E03	and		$01DB
		sta		$01DB
		rts

;=========================================================================
; Receive frame
;
L0E0A	ldx		#$00
		ldy		#$06
		sty		$01E3
L0E11	lda		$0382
		bpl		L0E11
		txa
		beq		L0E45
		lda		$7F,X
		eor		#$FF
		sta		$7F,X
L0E1F	nop
		nop
		nop
		ldy		#$78
L0E24	nop						;2
		nop						;2
		nop						;2
		lda		$80				;3
		lda		$0382			;4
		rol						;2
		ror		$80,X			;6
		iny						;2
		bpl		L0E24			;2+1	26 cycles/bit
		inx
		bpl		L0E41
		ldx		#$05
		jsr		L0D94			;receive checksum
		lda		$F9,X
		eor		#$FF
		sta		$F9,X
		rts

L0E41	nop
		jmp		L0E11

L0E45	nop
		nop
		nop
		jmp		L0E1F

;=========================================================================
; Check command frame checksum
;
L0E4B	lda		#$00
		clc
L0E4E	adc		$01D0,X
		php
		inx
		cpx		$01E3
		beq		L0E5C
		plp
		jmp		L0E4E

L0E5C	plp
		adc		#$00
		cmp		$01D0,X
		rts

;=========================================================================
; Check data frame checksum
;
L0E63	lda		#$00
		tax
		clc
L0E67	adc		$80,X
		inx
		bpl		L0E67
		adc		#$00
		cmp		$01D5
		rts

;=========================================================================
L0E72	pha
		lda		$0382
		ora		#$01
		sta		$0382
		lda		$0383
		ora		#$01
		sta		$0383
		pla
		rts

;=========================================================================
L0E85	bit		$0382			;check command line
		bvs		L0E85			;wait to deassert
L0E8A	lda		#$41			;ACK
L0E8C	sta		$01D4
		jsr		L0E72
		jsr		L0ED2
		jsr		L0F18
		lda		$01E2
		and		#$10
		beq		L0ED1
		lda		#$02
		sta		$0380
		sta		$0384
		lda		#$2F
		sta		$00
		jsr		L0FCD
L0EAE	ldy		#$27
		ldx		#$24
		stx		$0382
L0EB5	jsr		L0D3D
		bmi		L0EBF
		jsr		L0D26
		bmi		L0EB5
L0EBF	sty		$01D9
		lda		#$14
		jsr		L0DCC
		lda		#$EF
		jsr		L0DFA
		lda		#$FF
		sta		$039F
L0ED1	rts

;=========================================================================
; Send byte
;
L0ED2	lda		$0382		;4		-- 21 cycles entry including JSR
L0ED5	and		#$FE		;2
		sta		$0382		;4
		ldy		#$78		;2
		bit		$80			;3
L0EDE	bit		$80			;3		-- 26 cycles/loop
		nop					;2
		nop					;2
		lsr					;2
		ror		$01D4		;6
		rol					;2
		sta		$0382		;4
		iny					;2
		bpl		L0EDE		;2+1	--
		lsr					;2
		sec					;2
		rol					;2
		nop					;2
		nop					;2
		nop					;2
		nop					;2
		nop					;2
		nop					;2
		sta		$0382		;4
		inx					;2
		rts					;6		-- 30 cycles exit

;=========================================================================
; Send data frame
;
L0EFB	bit		$0382
		bvs		L0EFB
		ldx		#$FF
		jsr		L0ED2
L0F05	ldy		$80,X			;4
		sty		$01D4			;4
		jsr		L0ED5			;254	send byte
		bpl		L0F05			;2+1
		ldy		$01D5
		sty		$01D4
		jsr		L0ED5
L0F18	lda		$0383
		and		#$FE
		sta		$0383
		rts

;=========================================================================
L0F21	lda		$0380
		and		#$10
		beq		L0F2D
		lda		#$08
		jmp		L0DE2

L0F2D	lda		#$F7
		jmp		L0E03

;=========================================================================
L0F32	lda		$0380
		and		#$02
		bne		L0F48
		lda		#$0A
		sta		$0380
		sta		$03
		lda		#$16
		sta		$01
		lda		#$EC
		sta		$00
L0F48	lda		$01D7
		sta		$01EA
		rts

;=========================================================================
; Track/sector division routine
;
; Splits logical sector number into track/sector.
;
; Inputs
;  $01D3:0182  Sector number
;
; Outputs
;  $01E0    Inverted sector number (1-18)
;  $01E1    Inverted track number (0-39)
;
; Timing:
;	168-360 cycles including JSR
;
; This routine does a division by 18 by dividing by 16 as a starting
; approximation and then adjusting the track as needed:
;
;	track = vsec / 16
;	tmp = vsec % 16
;
;	while(track*2 >= tmp) {
;		--track;
;		tmp += 16;
;	}
;
;	sector = tmp - track*2
;
; Propagating the sector calculation backward makes the algorithm
; more obvious:
;
;	track = vsec / 16
;	sector = vsec - track*18
;
;	while(sector <= 0) {
;		--track;
;		sector += 18;
;	}
;
; The algorithm requires 6 iterations at most, to adjust vsec 720
; from track 45 to track 39. Sadly, this algorithm is not really
; better than just a plain binary division routine specialized for
; a divisor of 18.
;
L0F4F	lda		$01D2
		ldx		#$04
L0F54	ror		$01D3
		ror
		dex
		bne		L0F54
		ror		$01D3
		ldx		#$04
L0F60	lsr		$01D3
		dex
		bne		L0F60
L0F66	asl
		cmp		$01D3
		bcs		L0F82
		sta		$01D2
		lsr
		eor		#$FF
		sta		$01E0
		sec
		lda		$01D3
		sbc		$01D2
		eor		#$FF
		sta		$01E1
		rts

;=========================================================================
L0F82	lsr
		tax
		dex
		lda		#$10
		clc
		adc		$01D3
		sta		$01D3
		txa
		jmp		L0F66

;=========================================================================
; Compute logical sector number for bad sector during format
;
L0F92	ldy		#$00
		sty		$01E9
		lda		$01E1
		eor		#$FF
		sta		$01E7
		lda		$01D9
		eor		#$FF
		asl						;x2
		sta		$01E8			;stash
		asl						;x4
		asl						;x8
		rol		$01E9			;cont.
		asl						;x16
		rol		$01E9			;cont.
		adc		$01E8			;x18
		tay
		lda		#$00
		adc		$01E9
		sta		$01E9
		tya
		clc
		adc		$01E7			;add sector
		sta		$80,X			;store logical sector number lo
		lda		#$00
		adc		$01E9			;add carry
		inx
		sta		$80,X			;store logical sector number hi
		rts

;=========================================================================
; Motor spin-up routine
;
L0FCD	lda		$01E2			;4
		and		#$04			;2
		beq		L0FD9			;2/3
		lda		#$50			;2
		jsr		L0DCC			;101780-103055  delay for ~200ms
L0FD9	rts						;6

;=========================================================================
		dta		' DAVE STAUGAS '

		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		brk
		
		org		$0ffc
		dta		a($0800)
		dta		a($0800)
