
VERSIONSTRING equ "Program v1.01"

!
! Filename:     program.asm
! Module name:  Program
! Description:  chip and external EEPROM programmer
!
! Commands:
!   string QueryVersion () - retreive version string
!   EnableWrite (byte flag) - enable/disable writing
!   WriteChip (byte rezid) - reprogram on-chip EEPROM
!   WriteExternal (byte rezid) - reprogram external EEPROM
!   WriteBoth (byte chipRezID, byte externalRezID) - reprogram both
!
! Exports:
!   none
!
! Timers:
!   none
!
! Hooks:
!   none
!
! Comments:
!   The Write commands do a reset after a successful write.
!
! Hardware notes:
!   It currently assumes that Vpp for the external eeprom is tied to +12V. 
!
! History:
!   bv 6/8/99	- initial revision
!   bv 6/16/99	- updated for new response style

	include <coke/coke.inc>


; EntryPoint

EntryPoint	subroutine
	cmpa	#IPC_Coke_Hello
	beq	.init
	cmpa	#IPC_Coke_Goodbye
	beq	.free
	rts
.init
	ldx	#CommandTable
	jsr	Coke_InstallCommandTable
	rts		
.free
	ldx	#CommandTable
	jsr	Coke_RemoveCommandTable
	rts


; WriteChip writes a 512-byte block into the 68HC11F1's EEPROM.
; pointer to the data is in program_chipptr.

WriteChip subroutine
	ldx	#REGBASE
				; first, erase the eeprom
	ldab	#%00000110	; erase=1, eelat=1, eepgm=0
	stab	PPROG,x		; set eelat
	stab	CROMBASE	; "write" a byte in eeprom
	ldab	#%00000111	; erase=1, eelat=1, eepgm=1
	stab	PPROG,x		; turn on programming voltage
	jsr	Delay10ms	; wait for 10 ms
	clr	PPROG,x		; turn off programming mode

	jsr	Delay10ms

	ldx	program_chipptr	; get the pointer to the eeprom data
	ldy	#CROMBASE	; get pointer to start of eeprom
.loop
	ldab	#%00000010	; eelat=1, eepgm=0
	stab	PPROG+REGBASE	; set eelat
	ldab	0,x		; read byte from memory
	stab	0,y		; store byte to eeprom address
	ldab	#%00000011	; eelat=1, eepgm=1
	stab	PPROG+REGBASE	; turn on programming voltage
	jsr	Delay10ms	; wait for it
	clr	PPROG+REGBASE	; turn off programming mode
	jsr	Delay1ms	; wait a little
	inx			; next memory byte
	iny			; next eeprom byte
	bne	.loop		; if no roll-over to $0000, loop
	
	rts


; WriteExternal writes data into the external Am28F256A EEPROM.
; The command bytes are a little different than in the spec sheets
; in order to compensate for the "hardware flaw" (ie, Steve screwing
; up the data bus).
; pointer to the data is in program_extptr,
; length of data to write is in program_extlength.

WriteExternal subroutine
	ldaa	#$ff		; issue the reset command
	staa	ROMBASE		; twice
	staa	ROMBASE
	
	ldaa	#$60		; issue the erase command
	staa	ROMBASE
	staa	ROMBASE		; here we go!

	ldx	#ROMBASE
.erasecheck
	brclr	0,x ,#$01 ,.erasecheck	; if busy flag is clear, loop

	ldd	program_extptr		; get pointer to memory data
	addd	program_extlength	; add length
	xgdx				; put into x
	ldd	#ROMBASE		; get pointer to external ROM
	addd	program_extlength	; add length
	xgdy				; put into y
.loop
	dex			; previous memory byte
	dey			; previous eeprom byte
	cpy	#ROMBASE	; are we done?
	blo	.done		; if so, quit

	ldaa	#$a0		; issue the program byte command
	staa	ROMBASE
	ldaa	0,x		; read byte from memory
	staa	0,y		; store byte to eeprom
.programcheck
	ldaa	0,y		; read back byte from eeprom
	eora	0,x		; compare with real data
	lsra			; check the low bit (flag on rotated data bus)
	bcs	.programcheck	; if it's set, we're not done yet
	bra	.loop		; if it's not, go to next byte

.done
	ldaa	#$ff		; issue the reset command
	staa	ROMBASE		; twice
	staa	ROMBASE
	rts


Delay10ms subroutine
	pshx
	ldx	#3500
.loop
	dex
	bne	.loop
	pulx
	rts


Delay1ms subroutine
	pshx
	ldx	#350
.loop
	dex
	bne 	.loop
	pulx
	rts


; Command_EnableWrite (byte enableflag)

Command_EnableWrite subroutine
	jsr	Coke_GetChar
	staa	program_enable
	ldaa	#COKE_ACK
	rts


; Command_WriteChip (byte rezid)

Command_WriteChip subroutine
	jsr	Coke_GetChar		; get resource id
	tab
	jsr	Resource_GetResource	; get resource ptr
	bcs	.badrez			; bad rez id?
	stx	program_chipptr		; if not, store it
	jsr	Resource_GetLength	; get the resource length
	cpd	#512			; is it exactly 512 bytes?
	bne	.badlength		; if not, fail

	ldaa	program_enable		; check enable flag
	cmpa	#1			; is it 1?
	beq	.enabled		; if not, report an error
	ldab	#ERROR_Program_WriteNotEnabled
.fail
	ldaa	#COKE_FAIL
	rts
.badrez
	ldab	#ERROR_Coke_BadResourceID
	bra	.fail
.badlength
	ldab	#ERROR_Program_BadDataLength
	bra	.fail

.enabled
	sei				; disable interrupts
	jsr	WriteChip		; do the write
	jmp	RESETVECTOR		; reset the system


; Command_WriteExternal (byte rezid)

Command_WriteExternal subroutine
	jsr	Coke_GetChar		; get resource id
	tab
	jsr	Resource_GetResource	; get resource ptr
	bcs	.badrez			; bad rez id?
	stx	program_extptr		; if not, store it
	jsr	Resource_GetLength	; get length
	cpd	#512			; is it exactly 512 bytes?
	beq	.badlength		; if so, it's probably wrong
	std	program_extlength	; if not, use it

	ldaa	program_enable		; check enable flag
	cmpa	#1			; is it 1?
	beq	.enabled		; if not, report an error
	ldab	#ERROR_Program_WriteNotEnabled
.fail
	ldaa	#COKE_FAIL
	rts
.badrez
	ldab	#ERROR_Coke_BadResourceID
	bra	.fail
.badlength
	ldab	#ERROR_Program_BadDataLength
	bra	.fail
	
.enabled
	sei				; disable interrupts
	jsr	WriteExternal		; do the write
	jmp	RESETVECTOR		; reset the system



; Command_WriteBoth (byte chip rezid, byte external rezid)

Command_WriteBoth subroutine
	jsr	Coke_GetChar		; get resource id
	tab
	jsr	Resource_GetResource	; get resource ptr
	bcs	.badrez			; bad rez id?
	stx	program_chipptr		; if not, store it
	jsr	Resource_GetLength	; get length
	cpd	#512			; is it exactly 512 bytes?
	bne	.badlength		; if not, fail

	jsr	Coke_GetChar		; get resource id
	tab
	jsr	Resource_GetResource	; get resource ptr
	bcs	.badrez			; bad rez id?
	stx	program_extptr		; if not, store it
	jsr	Resource_GetLength	; get length
	cpd	#512			; is it exactly 512 bytes?
	beq	.badlength		; if so, it's probably wrong
	std	program_extlength	; if not, use it

	ldaa	program_enable		; check enable flag
	cmpa	#1			; is it 1?
	beq	.enabled		; if not, report an error
	ldab	#ERROR_Program_WriteNotEnabled
.fail
	ldaa	#COKE_FAIL
	rts
.badrez
	ldab	#ERROR_Coke_BadResourceID
	bra	.fail
.badlength
	ldab	#ERROR_Program_BadDataLength
	bra	.fail

.enabled
	sei				; disable interrupts
	jsr	WriteExternal		; do the write
	jsr	WriteChip
	jmp	RESETVECTOR		; reset the system


; version stuff

	_versionstuff

; command table

CommandTable subroutine
	dc.b	CMD_Program_QueryVersion
	dc.w	Command_QueryVersion
	dc.b	CMD_Program_EnableWrite
	dc.w	Command_EnableWrite
	dc.b	CMD_Program_WriteChip
	dc.w	Command_WriteChip
	dc.b	CMD_Program_WriteExternal
	dc.w	Command_WriteExternal
	dc.b	CMD_Program_WriteBoth
	dc.w	Command_WriteBoth

	dc.b	0


; data segment

program_enable	dc.b 0
program_chipptr	dc.w 0
program_extptr	dc.w 0
program_extlength	dc.w 0