--- /dev/null
+;
+; Probably belongs somewhere more general eventually
+;
+
+.equ porta, iobase + 0x00
+; reserved 0x01
+.equ pioc, iobase + 0x02
+.equ portc, iobase + 0x03
+.equ portb, iobase + 0x04
+.equ portcl, iobase + 0x05
+; reserved 0x06
+.equ ddrc, iobase + 0x07
+.equ portd, iobase + 0x08
+.equ ddrd, iobase + 0x09
+.equ porte, iobase + 0x0A
+.equ cforc, iobase + 0x0B
+.equ oc1m, iobase + 0x0C
+.equ oc1d, iobase + 0x0D
+.equ tcnth, iobase + 0x0E
+.equ tcntl, iobase + 0x0F
+.equ tic1h, iobase + 0x10
+.equ tic1l, iobase + 0x11
+.equ tic2h, iobase + 0x12
+.equ tic2l, iobase + 0x13
+.equ tic3h, iobase + 0x14
+.equ tic3l, iobase + 0x15
+.equ toc1h, iobase + 0x16
+.equ toc1l, iobase + 0x17
+.equ toc2h, iobase + 0x18
+.equ toc2l, iobase + 0x19
+.equ toc3h, iobase + 0x1a
+.equ toc3l, iobase + 0x1b
+.equ toc4h, iobase + 0x1c
+.equ toc4l, iobase + 0x1d
+.equ ti4o5h, iobase + 0x1e
+.equ ti405l, iobase + 0x1f
+.equ tctl1, iobase + 0x20
+.equ tctl2, iobase + 0x21
+.equ tmsk1, iobase + 0x22
+.equ tflg1, iobase + 0x23
+.equ tmsk2, iobase + 0x24
+.equ tflg2, iobase + 0x25
+.equ pactl, iobase + 0x26
+.equ pacnt, iobase + 0x27
+.equ spcr, iobase + 0x28
+.equ spsr, iobase + 0x29
+.equ spdr, iobase + 0x2A
+.equ baud, iobase + 0x2B
+.equ sccr1, iobase + 0x2C
+.equ sccr2, iobase + 0x2D
+.equ scsr, iobase + 0x2E
+.equ scdr, iobase + 0x2F
+.equ adctl, iobase + 0x30
+.equ adr1, iobase + 0x31
+.equ adr2, iobase + 0x32
+.equ adr3, iobase + 0x33
+.equ adr4, iobase + 0x34
+.equ bprot, iobase + 0x35
+.equ eprog, iobase + 0x36
+; reserved 0x37
+; reserved 0x38
+.equ option, iobase + 0x39
+.equ coprst, iobase + 0x3A
+.equ pprog, iobase + 0x3B
+.equ hprio, iobase + 0x3C
+.equ init, iobase + 0x3D
+; reserved 0x3E
+.equ config, iobase + 0x3F
+
--- /dev/null
+;
+; EEPROM firmware for the 68HC811E2
+;
+; TODO
+; - any debug/testing 8)
+;
+; Vector table for functions
+; Add functions for spi block copy to/from banks
+; Add description of SPI attached devices for OS
+; Make serial mode ask if you want serial or retry SD
+; Set up RTI timer and use interrupt to trap out of SPI layer
+; on a timeout
+;
+; Export outchar/outstr and friends so OS can use them (duplicated
+; right now). Ditto for inchar, inchar/wait type stuff
+;
+; Provide 'read block' 'write block' block device helpers so that
+; the boot block can be tighter ?
+;
+;
+ .globl _start
+
+ include "eeprom.def"
+
+ .sect .text
+;
+_start:
+ lds #0xF100 ; Stack in unbanked internal ram
+ ldaa #0xFF
+ staa init ; Move the internal RAM and I/O to Fxxx
+ stab porta ; clear output controls
+ ldaa #0x88
+ staa pactl ; Port A bit 7 and bit 3 to output
+;
+; Real RAM is now definitely in bank 0
+;
+ ldaa #0x30 ; 9600 baud
+ staa baud
+ ldy #boot1 ; say hello
+ jsr outstr
+ ldd #0xff55
+ ldy #0x1000
+ staa ,y ; arbitrary real RAM if we set up right
+ cmpa ,y ; should match
+ bne ramfucked
+ dec ,y ; zero
+ tst ,y ; check
+ bne ramfucked
+;
+; OK we seem to have RAM wired to do 00 and FF
+;
+ stab 1,y ; 0x55
+ ldaa ,y ; should be unchanged
+ cmpa #0xff ; address bus not working ?
+ bne ramfucked2
+;
+; Promising !
+;
+ clrb
+writepgs: ; write the page ident into each bank
+ stab ,x ; select this RAM bank
+ stab ,y
+ addb #0x08
+ cmpb #0xF8
+ bne writepgs
+ clrb
+readpgs: ; read the page ident from each bank
+ stab ,x ; select this RAM bank
+ cmpb ,y ; should match
+ bne ramfucked3 ; bank bits busted
+ addb #0x08
+ cmpb #0xF8
+ bne readpgs
+;
+; We could size the RAM if we needed to be flexible in future but
+; for now we don't so cheat
+;
+ ldy #boot2
+ jsr outstr
+
+ ldx #rambase
+ ldd #0xC0
+wipelow:
+ staa ,x
+ inx
+ deca
+ bne wipelow
+
+ ; Save RAM size (fixed for now)
+ ldd #512
+ std ramsize
+ ; Set for board (FIXME - .equ for this)
+ ldd #2048
+ std eclock
+;
+; Serial works, RAM seems to work, it's time to whack the SD card
+;
+ jsr sdboot
+;
+; If not then we try a serial boot
+;
+ jsr serboot
+ ldx #bootfail
+ jsr outstr
+ ldaa #0xA0
+ bra fail
+
+ramfucked:
+ ldaa #0x88
+ bra fail
+ramfucked2:
+ ldaa #0x90
+ bra fail
+ramfucked3:
+ ldaa #0x98
+fail:
+ jsr outcharhex ; print the hex code
+ staa ,x ; assert it on the bank control pins
+failloop:
+ staa 0xDEAD ; keep asserting DEAD on the address bus
+ bra failloop ; and the error on data
+
+outcharhex:
+ pshb
+ lsrb
+ lsrb
+ lsrb
+ lsrb
+ bsr outnibble
+ pulb
+ pshb
+ bsr outnibble
+ pulb
+ rts
+
+outnibble:
+ andb #0x0F
+ cmpb #0x0A
+ ble outh2
+ addb #0x07
+outh2: addb #0x30
+outchar:
+ psha
+outchar1:
+ ldaa scsr
+ anda #0x80
+ beq outchar1
+ stab scdr
+ pula
+outsdone:
+ rts
+
+outstr:
+ ldab ,x
+ beq outsdone
+ bsr outchar
+ inx
+ bra outstr
+
+;
+; Send an extended command - CMD 55 then the actual cmd. If the CMD55
+; is rejected the then ACMD is rejected
+;
+spi_send_acmdxy:
+ pshb
+ pshx
+ pshy
+ ldab #55
+ bsr spi_send_cmd
+ cmpb #1
+ bgt acmd_fail
+ puly
+ pulx
+ pulb
+ bra spi_send_cmd
+acmd_fail:
+ rts
+;
+; Read a byte, only uses B
+;
+spi_rx:
+ ldab #0xFF
+spi_tx:
+ stab spdr
+spi_rx_w:
+ ldab spsr
+ andb #0x80
+ beq spi_rx_w ; Fixme - timeout handling
+ ldab spdr
+ rts
+
+sd_spi_wait_ff: ; Timeouts!
+ bsr spi_rx
+ cmpb #0xff
+ beq sd_spi_wait_ff
+ rts
+
+sd_spi_wait: ; Ditto
+ bsr spi_rx
+ cmpb #0xff
+ bne sd_spi_wait
+ rts
+
+;
+; Chip selects for SD card
+;
+spi_cs_hi:
+ psha ; other bits are not write bits so be slack
+ ldaa #0x40
+ staa portd
+ pula
+ rts
+
+spi_cs_lo:
+ clr portd
+ rts
+
+spi_send_cmd:
+ ldx #0
+spi_send_cmdx:
+ ldy #0
+spi_send_cmdxy:
+ addb #0x40 ; command number to code
+ bsr spi_cs_hi
+ bsr spi_rx ; clocks
+ bsr spi_cs_lo
+ bsr sd_spi_wait_ff
+ tsta
+ bne sdfail
+ pshb
+ bsr spi_tx ; send acc B
+ xgdy
+ pshb
+ tab
+ bsr spi_tx
+ pulb
+ bsr spi_tx
+ xgdx
+ pshb
+ tab
+ bsr spi_tx
+ pulb
+ bsr spi_tx
+ pulb ; get the cmd back
+ pshb
+ ldaa #0x01 ; dummy + stop
+ cmpb #0x40 ; special cases
+ bne ncrc_cmd0
+ ldaa #0x95
+ bra tx_crc
+ncrc_cmd0:
+ cmpb #0x48
+ bne tx_crc
+ ldaa #0x87
+tx_crc: tab
+ bsr spi_tx
+ pulb
+ cmpb #0x4C
+ bne no_rx_dummy
+ bsr spi_rx
+no_rx_dummy:
+ ldaa #0x14
+rx_waitr:
+ bsr spi_rx
+ bitb #0x80
+ beq cmd_rx_done
+ deca
+ bne rx_waitr
+cmd_rx_done:
+ rts
+
+
+sdfail:
+ ldab #0xFF
+ rts
+sdboot:
+ ldd #0x523F
+ staa spcr ; SPI on, master, SPI(0,0), 125KHz
+ stab ddrd ; Port 5 is output (not !SS)
+ bsr spi_cs_hi
+ ldaa #0x20
+sdboot1:
+ bsr spi_rx ; send clocks
+ deca
+ bne sdboot1
+ clrb ; CMD 0
+ bsr spi_send_cmd
+ cmpa #1 ; 1 indicates OK
+ bne sdfail
+ ldx #spi_probe1
+ jsr outstr ; display indication of probing
+ ; as we have a card of some form
+ ldab #8
+ ldx #0x01AA
+ bsr spi_send_cmdx
+ cmpb #1 ; if CMD 8 fails it's not SDHC
+ bne try_mmc
+ ;
+ ; Looks like we are an SDHC card
+ ;
+ ldx #spibuf
+ ldab #4
+ jsr spi_rx ; should be four data bytes
+ ldd #0x01AA
+ cmpa spibuf+2 ; and should end with 0x01AA
+ bne bad_card_v ; bad voltage ?
+ cmpb spibuf+3
+ bne bad_card_v
+ ;
+ ; Ok looks good now see if it will wake up
+ ; FIXME: timeout needed
+ ;
+spinidle:
+ ldy #0x4000
+ ldx #0
+ ldab #41
+ jsr spi_send_acmdxy ; wait for the card to exit idle
+ tsta
+ bne spinidle
+ ldab #58
+ jsr spi_send_cmd
+ ldab #4
+ ldx #spibuf
+ jsr spi_rx
+ ldab spibuf
+ ldaa #BDEV_SD2
+ andb #0x40
+ beq notblock
+ oraa #BDEVF_LBA
+notblock:
+ staa blocktype
+ ldx #boot_sdhc
+ jsr outstr
+ bra sd_valid
+
+bad_card_v:
+ ldx #spi_badcardv
+ jmp outstr
+
+try_mmc:
+ ldab #41
+ ldx #0
+ ldy #0
+ jsr spi_send_acmdxy
+ cmpa #1
+ ble is_sdv1
+ ldx #boot_mmc
+ jsr outstr
+ ldaa #BDEV_MMC
+ bra det_ok
+is_sdv1:
+ ldx #boot_sdv1
+ jsr outstr
+ ldaa #BDEV_SD1
+det_ok:
+ staa blocktype
+sd_valid:
+ ldaa #0x50
+ staa spcr ; SPI to full speed
+
+ ldx #0 ; Block or byte 0 - we don't care about LBA!
+ ldy #0
+ ldab #17 ; Read
+ jsr spi_send_cmdxy
+ tsta ; Read command worked
+ bne spi_rx_fail
+ ldd #0xFE ; FIXME: check
+ jsr sd_spi_wait
+ tsta
+ bne spi_rx_fail
+ ldx #0xE000
+ ldab #0x00
+sd_rx_l:
+ staa spdr ; any value will do
+sd_rx_w:
+ ldaa spcr ; are we done yet
+ anda #0x80
+ beq sd_rx_w
+ ldaa spdr ; SPI data byte
+ staa ,x
+ inx
+ decb
+ bne sd_rx_l
+;
+; Success
+;
+ ldx 0xE000
+ cpx #0xC0DE
+ bne notbootable
+ ldx #sdbooting
+ jsr outstr
+ jmp 0xE002 ; jmp to boot block
+
+spi_rx_fail:
+ ldx #ioerror
+ bra sdretry
+
+notbootable:
+ ldx #notbootmedia
+sdretry:
+ jsr outstr
+ jsr hitnl
+ jmp sdboot ; try again
+
+
+;
+; Serial input
+;
+
+hitnl: bsr waitkey
+ cmpa #13
+ beq nlok
+ cmpa #10
+ bne hitnl
+nlok: rts
+
+waitkey:
+ ldab scsr
+ andb #0x20
+ beq waitkey
+ ldab scdr
+ rts
+
+serboot:
+ ldx #sergo
+ jsr outstr
+ ldx #0xE000
+serbootl:
+ bsr waitkey
+ stab ,x
+ inx
+ cmpx #0xE200
+ bne serbootl
+ ldd #0xE000
+ cmpa #0xC0
+ bne serbad
+ cmpb #0xDE
+ bne serbad
+ jmp 0xE002
+serbad:
+ rts
+
+;
+; Service Routines.
+;
+bankcomp:
+ ldab porta
+ pshb
+ andb #0xC0 ; preserve other controls
+ aba ; we know the bank in A will have the other
+ ; bits clear
+ pulb ; B gets us back
+ rts
+
+fargetw:
+ bsr bankcomp
+ staa porta ; switch bank
+ ldx ,x ; get the word
+ stab porta ; and back
+ xgdx ; result in D
+ rts
+
+fargetb:
+ bsr fargetw
+ tab ; big endian so we want high half in low
+ clra
+ rts
+
+farputw:
+ bsr bankcomp
+ staa porta
+ sty ,x
+ stab porta
+ rts
+
+farputb:
+ xgdy
+ bsr bankcomp
+ staa porta
+ xgdy ; b is now the value
+ stab ,x
+ xgdy ; b is now the bank restore
+ stab porta
+ rts
+
+; FIXME - optimise for 2 bytes at a time ?
+
+farzero:
+ bsr bankcomp
+ staa porta
+farzl:
+ clr ,x
+ inx
+ dey
+ cmpy #0
+ bne farzl
+ stab porta
+ rts
+
+;
+; FIXME: optimise!
+;
+farcopy:
+ ; FIXME: - set up bank regs
+
+copywl:
+ ldaa tmp2
+ staa porta
+ ldaa ,x
+ stab porta
+ staa ,y
+ inx
+ iny
+ dec tmp1
+ bne copywl
+ ldaa tmp3 ; saved original bank
+ staa porta
+ rts
+
+; FIXME: to do
+farzcopy:
+ rts
+
+
+farcall:
+ tpa
+ psha
+ sei ; interrupts off a minute
+ staa tmp2 ; save irq flags
+ sts tmp1 ; save stack
+ jsr farcall2 ; we need a helper on the return path
+ ; we come back on the new stack
+ puly ; old sp
+ pulb ; old bank
+ pula ; flags (irq state)
+ sei ; stack will be invalid for an instruction
+ tys ; back to old stack
+ stab porta ; and old bank
+ tap ; irq flags back to entry state
+ rts
+
+
+farcall2:
+ bsr bankcomp
+ staa porta
+ tys ; new stack now valid
+ ldy tmp1 ; old stack
+ ldaa tmp2 ; restore irq state
+ tap
+ psha
+ pshb ; save old bank code on new stack
+ pshy ; save old stack on new stack
+ pshx ; target address
+ ldy ret_y ; set up registers
+ ldx ret_x
+ ldd ret_d
+ rts
+
+
+farjump:
+ tap
+ sei
+ staa tmp2
+ bsr bankcomp
+ staa porta
+ tys ; new stack valid
+ ldaa tmp2
+ tap ; irq status back
+ pshx
+ ldy ret_y
+ ldx ret_x
+ ldd ret_d
+ rts
+
+reboot:
+ sei
+ jmp 0xF800
+
+;
+; Make a cross domain IRQ handler call (X = descriptor)
+;
+; We stack the registers on the current stack, then switch to bank 0
+; and invoke the handler (with interrupts still disabled) in bank 0.
+; Upon completion we switch back to the old stack and recover
+;
+interrupt:
+ tsy ; save old stack frame
+ ldab porta ; old bank
+ tba
+ andb #0x3F ; bank bits only
+ anda #0xC0 ; control bits
+ staa porta ; now in kernel bank
+ ;
+ ; Don't read the vectors until we switch bank. The vectors
+ ; can then live in bank 0 space, not precious
+ ;
+ lds 2,x ; IRQ stack vector (set by OS)
+ pshy ; save old stack
+ pshb ; save bank bits
+ ldx ,x ; vector is (func, stack)
+ jsr ,x ; call
+ pulb ; old bank
+ puly ; old stack pointer
+ ldaa porta
+ anda #0xC0
+ aba
+ staa porta ; back to calling bank
+ tys ; back to old stack
+ rti
+
+boot1: .ascii "68HC811 Bootware"
+ .byte 13,10,0
+boot2: .byte 13,10
+ .ascii "512Kb RAM"
+ .byte 13,10,0
+bootfail:
+ .byte 13,10
+ .ascii "No boot device found"
+ .byte 13,10,0
+spi_probe1:
+ .byte 13,10
+ .ascii "sd0: "
+ .byte 0
+spi_badcardv:
+ .ascii "Invalid voltage"
+ .byte 13,10,0
+ioerror:
+ .ascii "I/O error"
+ .byte 13,10,0
+boot_sdhc:
+ .ascii "SDHC"
+ .byte 0
+boot_sdv1:
+ .ascii "SD"
+ .byte 0
+boot_mmc:
+ .ascii "MMC"
+ .byte 0
+notbootmedia:
+ .ascii " - not bootable"
+ .byte 13,10,0
+sdbooting:
+ .ascii " - bootable",
+ .byte 13,10,13,10,0
+hitnewline:
+ .ascii "Hit newline to retry boot"
+newline:
+ .byte 13,10,0
+sergo:
+ .ascii "Serial boot: being download"
+ .byte 13,10
+ .ascii ">"
+ .byte 0
+
+