		ORG #0000
		ld a,0
		out (#F8),a	; blank status LEDs
		ld sp, #700	; set stack pointer to something sensible
		jp ProgramRom

		; Blank space until some restart handlers are written
		; Fill all below NMI with NOPs

		ASSERT $ <= #66
		BLOCK #66 - 6, 0

NMI		retn	; do nothing

		; The meat of the program.
ProgramRom
		ld hl, #8000	; first ROM sector
		call EraseSector
		cp 0		; return code = 0 if all went OK
		jr z, ProgramRom.Write
		halt		; erk, it went horribly wrong
				; note: NMI will try and program anyway

ProgramRom.Write
		ld hl, TESTPROGRAM
		ld de, #8000
		ld b, TESTPROGRAMEND
		call WriteData

AllDone
		halt
		jp AllDone	; just in case of an NMI


; EraseSector subroutine erases a 16K Flash ROM sector.
; Only 32K of the 128K ROM is actually mapped in, so there's only two
; sector addresses we can choose from (0 or 1).
; Pass the sector address in HL
; Result is returned in A (0 = OK)
; Status LED = 1 = preparing to erase, 11 = Erasing, lights out = done
; 10 = borked
EraseSector
		ld a, 1
		out (#F8), a	; status LED = 0000 0001

		ld a, #AA	; unlock code 1
		ld (#8555), a	; unlock addr 1
		ld a, #55	; unlock code 2
		ld (#82AA), a	; unlock addr 2
		ld a, #80	; erase cmd 1
		ld (#8555), a	; erase cmd addr 1
		ld a, #AA	; erase cmd 2
		ld (#8555), a	; erase cmd addr 2
		ld a, #55	; erase cmd 3
		ld (#82AA), a	; erase cmd addr 3
		ld a, #30	; erase cmd 4
		ld (hl), a	; erase sector address

		ld a, 3		; status lights = 0000 0011
		out (#F8), a	; update lights

EraseSector.wait
		bit 7, (hl)	; test DQ7 - should be 1 when complete
		jr nz, EraseSector.complete
		bit 5, (hl)	; test DQ5 - should be 1 to continue
		jr z, EraseSector.wait
		bit 7, (hl)	; test DQ7 again
		jr z, EraseSector.borked

EraseSector.complete
		ld a,0		; status = OK
		out (#F8), a	; extinguish status LEDs
		ret

EraseSector.borked	
		ld a, #2	; 0000 0010
		out (#F8), a	; update LEDs
		ret

; WriteData
; Copy data pointed to by HL to Flash ROM at address DE, for B bytes.
; On return, A=0 means write OK
; Status LEDs: 0001 0000 = Writing
;              0011 0000 = Checking status
;              0000 0000 = Complete OK
;              0010 0000 = Borked

WriteData
		ld a, #10
		out (#F8), a	; status LED = 0001 0000

		ld a, #AA	; unlock 1
		ld (#8555), a	; unlock address 1
		ld a, #55	; unlock 2
		ld (#82AA), a	; unlock address 2
		ld a, #A0	; Program
		ld (#8555), a	; Program address
		ld a, (hl)	; Get byte to program
		ld (de), a	; program it

		push bc		; save BC for later
		ld c,a		; store A

		ld a, #30
		out (#F8), a	; status LED = 0011 0000
WriteData.wait
		ld a, (de)	; read programmed address
		ld b, a		; save status
		xor c		
		bit 7, a	; If bit 7 = 0 the bit 7 = data	
		jr z, writeData.byteComplete

		bit 5, b	; test DQ5
		jr nz, WriteData.wait

		ld a, (de)	; read programmed address
		xor c		
		bit 7, a	; Does DQ7 = programmed data? 0 if true
		jr nz, writeData.borked

writeData.byteComplete
		pop bc		; retrieve BC
		inc hl
		inc de
		djnz WriteData
		
		ld a, 0
		out (#F8), a	; extinguish status lights
		ret

writeData.borked
		ld a, #20	
		out (#F8), a	; status lights = 0010 0000
		ret

; A test program to load into ROM. To run from ROM, I swap the chip select
; lines (so that ROM maps in at 0x0000 - 0x7FFF, and the 2K static RAM
; gets mapped from 0x8000 to 0x87FF
TESTPROGRAM
                org #0000
start           di
                ld sp,#8400     ; Stack must be in RAM!
loop            ld a,#C0
rightwards      out (#f8),a
                rra
                cp 0
                jr nz,rightwards
                ld a,#07
leftwards       out (#f8),a
                rla
                cp 0
                jr nz,leftwards
                ld a,1
increment       out (#f8),a
                inc a
                cp #10
                jr nz,increment
shiftout        rla
                out (#f8),a
                cp 0
                jr nz,shiftout
                halt
		jp loop

                ASSERT $ <= #66
                BLOCK #66 - $, 0

testnmi         ex af,af'       ; save A and F registers
                ld a,#aa
                out (#f8),a
                ld a,#55
                out (#f8),a
                xor a
                out (#f8),a
                ex af,af'       ; restore AF
                retn
                nop
TESTPROGRAMEND
