HD6301V1
8bit microcontroller used for multiplayer communication in cartridges like League Bowling.
Clocked at 1Mhz using the 4MB signal (divided by 4 internally).
Datasheet
Official datasheet: [[1]]
Code
The HD6301 has an internal 4KB ROM section holding program data.
A dump is available, coming from a prototype Riding Hero cart: File:HD6301.zip (2x overdump) - Credits to NeoTurfMasta
Commented source code (still some work left...):
;Vectors:
;TRAP: F4D6 (error)
;SC1: F4BA (link receive)
;TOF: F4D6 (error)
;OCF: F4D6 (error)
;ICF: F4D6 (error)
;IRQ1: F4CB (CPU write)
;SWI: F4D6 (error)
;NMI: F4D6 (error)
;RESET: F000 (start)
;RAM:
;$C2 start of message buffer (14 bytes ?)
;$D0~$D1
;$D2~$D3
;$D4~$D5
;$D6~$D7
;$D8~$D9
;$DA~$DB
;$DC
;$E2 is an error counter ?
;$E3 some counter ? -----------------
;$E4 some bitmask ? -----------------
;$E5 is receive byte counter
;$E6 ?
;$E7 is the output code (read by CPU)
;$E8 related to $F3 ?
;$E9 is the input code (wrote by CPU)
;$EA another byte counter ?
;$EB bit 0 is CPU write flag ? (data ready in $E9), bit 1 is link receive flag
;$EC is TRCS register copy
;$ED is the received code (link)
;$EE~$EF buffer (FIFO ?) pointer
;$F0 receive timeout timer
;$F1 is status code/port1 mirror
;$F2 some bitmask ? -----------------
;$F3 is lower nibble of input code (parameter ?)
;$F4 start of some short buffer ?
;Status bit 0 (D8) is command error (D,E,F: wrong command)
;Status bit 2 (D10) is overrun receive error
org $F000
; RESET
LF000:
sei
lds #$00FF ; Clear RAM
ldx #$0080
LF007:
clr $7F,x
dex
bne LF007
ldaa #$40 ; Enable RAM (lol)
staa X0014
ldaa #$04 ; 62500bps internal clock
staa X0010
ldaa #$1A ; RIE, RXE, TXE
staa X0011
ldaa #$48 ; Port3 IS3/IRQ1 enable, latch enable
staa X000F
ldaa X0011 ; Clear TRCS flags
ldaa X0012 ; Receive register
ldaa #$F1 ; Port1 direction 11110001
staa X0000
ldaa #$00 ; Port1 data
staa X0002
ldaa #$00 ; Port3 direction (inputs)
staa X0004
ldaa #$FF ; Port4 direction (outputs)
staa X0005
ldaa X0006 ; Clear port3 latch
ldaa #$FF ; $FF to RAM $E9, $DE, $DF, $E0, $E1, $B4, $C2, $E9, $E7
staa X00E9 ; Input code
staa X00DE
staa X00DF
staa X00E0
staa X00E1
staa X00B4
staa X00C2
staa X00E9 ; Input code (again...)
staa X00E7 ; Output code
ldd #$0080
std X00EE ; RAM $EE = $0080
cli
LF056:
ldaa X0002 ; Read port1
bita #$02 ; P11 is nSLOTCS ($02 is a mask, not a bit number)
beq LF08F ; Slot is enabled ->
clra
staa X0002 ; Clear port1
staa X00E2 ; Clear error counter ?
staa X00E5 ; Reset byte counter
staa X00E8
staa X00EA
staa X00EB ; Clear flags
staa X00F1 ; Clear status ?
staa X00F2
staa X00F3
deca
staa X00B4 ; $FF in RAM...
staa X00C2
staa X00DE
staa X00DF
staa X00E0
staa X00E1
staa X00E9 ; Input code
bra LF056 ; Loop until slot is enabled
; Slot enabled
LF08F:
inc X00F0 ; $F0 starts at 0, now 1
ldaa X00EB ; Got a byte from CPU ?
bita #$01
bne LF09C ; Yup ->
jmp LF193 ; Nope ->
; Process CPU write
LF09C:
; AIM AND Immediate $FE with RAM $EB (clear CPU write flag)
; EIM XOR Immediate $80 with RAM $F1 (toggle status bit 3)
ldaa X00F2
bne LF0B7
ldab X00E9 ; Input code
andb #$F0 ; Upper nibble is index in jump table
ldx #$F4DA
lsrb ; 0BBBB000
lsrb ; 00BBBB00
lsrb ; 000BBBB0
abx ; B+X -> X
ldx $00,x
jmp $00,x ; Index jump
;
LF0B7:
bita #$01
beq LF0DE
ldab X00E8
cmpb X00F3
beq LF117
ldx #$00D0
abx ; B+X -> X
ldaa X00E9 ; Input code
staa $00,x
ldaa $01,x
staa X0007 ; Port4 data (output code)
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
inc X00E8
jmp LF193
;
LF0DE:
ldab X00E8
cmpb X00F3
beq LF0FC
ldx #$00D0
abx ; B+X -> X
ldaa $01,x
staa X0007 ; Port4 data (output code)
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
inc X00E8
jmp LF193
;
LF0FC:
ldx #$00D0
abx ; B+X -> X
ldaa $00,x
coma
staa X0007 ; Port4 data (output code)
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
clra
staa X00E8
staa X00F2
jmp LF193
;
LF117:
clra
staa X00F2
ldx #$00CF
abx ; B+X -> X
ldaa $00,x
coma
cmpa X00E9 ; Input code
beq LF13D
ldaa $01,x
coma
staa X0007 ; Port4 data (output code)
; OIM OR Immediate $20 with RAM $F1 (set status bit 1)
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
clr X00E8
jmp LF193
;
LF13D:
ldab X00E7 ; Output code
cmpb #$FF
bne LF159
ldaa $01,x
staa X0007 ; Port4 data (output code)
; OIM OR Immediate $20 with RAM $F1 (set status bit 1)
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
clr X00E8
jmp LF193
;
LF159:
ldaa $01,x
coma
staa X0007 ; Port4 data (output code)
clra
xgdx ?????
clr $DE,x
;
; AIM AND Immediate $CF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
clr X00E8
ldx X00EE
ldd X00D0
std $00,x
ldd X00D2
std $02,x
ldd X00D4
std $04,x
ldd X00D6
std $06,x
ldd X00D8
std $08,x
ldd X00DA
std $0A,x
ldaa X00DC
staa $0C,x
LF193:
ldaa X00EB ; Got a byte from link ?
bita #$02
bne LF19D ; Yup ->
jmp LF257 ; Nope ->
; Process link receive
LF19D:
; AIM AND Immediate $FD (11111101) with RAM $EB
ldab X00EC
bitb #$40 ; Overrun framing error ?
bne LF1AE ; Yup ->
bitb #$80 ; Receive data register full ?
bne LF1CE ; Yup ->
jmp LF257
; Overrun framing error
LF1AE:
clra
staa X00E5 ; Reset byte counter
staa X00EA
deca
staa X00C2
staa X00B4
inc X00E2 ; Error counter ?
ldaa X00F1 ; Status ?
oraa #$40 ; Set status bit 2
anda #$FE ; Mask out P10, just in case (transmit enable, not status)
staa X00F1 ; Status ?
staa X0002 ; Port1 data
jmp LF257
; Got byte ok
LF1CE:
ldab X00E5 ; Byte counter
cmpb #$0D
beq LF1E5 ; Already got 13 bytes ? ->
clra
xgdx ?????
ldaa X00ED ; Received code
staa $C2,x ; Store in list @ $C2+x
inc X00E5 ; Byte counter
; OIM OR Immediate $04 with RAM $EB
jmp LF257
; Got message OK
LF1E5:
; AIM AND Immediate $FE with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
clra
xgdx ?????
ldaa X00ED ; Received code
staa $C2,x ; Store 14th byte (the last)
clra
staa X00EA
staa X00E5 ; Reset byte counter
deca
staa X00B4
ldaa X00C2 ; RAM $C2 (first byte of message) & 3: 0~3 -> 1~4, gives B=$02,$04,$08,$10
anda #$03
inca
ldab #$01
LF207:
aslb
deca
bne LF207
lsrb ; B=$01,$02,$04,$08
orab X00E4
stab X00E4
ldab X00C2
andb #$03
ldx #$00F4
abx ; X = $00F4 + (RAM $C2 & 3)
clr $00,x
cmpb X00E7 ; Output code
beq LF252
ldx #$F4FA
abx ; B+X -> X
abx ; B+X -> X
incb
andb #$03
stab X00E3
ldx $00,x
ldd X00C3
std $00,x
ldd X00C5
std $02,x
ldd X00C7
std $04,x
ldd X00C9
std $06,x
ldd X00CB
std $08,x
ldd X00CD
std $0A,x
ldaa X00CF
staa $0C,x
LF252:
ldaa #$FF
staa X00C2
LF257:
ldaa X00F0
cmpa #$28
bcs LF296
ldx #$00F4
ldab X00E3
abx ; B+X -> X
ldaa $00,x
inca
cmpa #$0A
bne LF27C
ldaa #$01
incb
LF26F:
asla
decb
bne LF26F
lsra
coma
anda X00E4
staa X00E4
clra
LF27C:
staa $00,x
inc X00E3
; AIM AND Immediate $03 with RAM $E3
clra
staa X00E5 ; Reset byte counter
staa X00EA
staa X00F0
; AIM AND Immediate $FE with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
LF296:
ldaa X0011 ; Read TRCS
bita #$20 ; Transmit register empty ?
beq LF309 ; Nope ->
ldaa X00B4
cmpa #$FF
bne LF309
clra
ldab X00E7 ; Output code
cmpb #$FF
beq LF309
xgdx ?????
ldab $DE,x
bne LF309
orab X00EA
orab X00E5 ; Byte counter
bne LF309
xgdx ?????
eorb X00E3
bne LF309
ldx X00EE ; X=$00EE
ldd $00,x
std X00B5 ; RAM $B5 <- RAM $EE
ldd $02,x
std X00B7 ; RAM $B7 <- RAM $F0
ldd $04,x
std X00B9 ; RAM $B9 <- RAM $F2
ldd $06,x
std X00BB ; RAM $BB <- RAM $F4
ldd $08,x
std X00BD ; RAM $BD <- RAM $F6
ldd $0A,x
std X00BF ; RAM $BF <- RAM $F8
ldaa $0C,x
staa X00C1 ; RAM $C1 <- RAM $FA
ldaa X00E7 ; Output code
staa X00B4
; OIM OR Immediate $01 with RAM $F1 (P10 high, enable TX buffer in 75176)
ldab X00F1 ; Status ?
stab X0002 ; Port1 data
staa X0013 ; Transmit register
;
; AIM AND Immediate $FB with RAM $EB
inc X00EA
inc X00E3
; AIM AND Immediate $03 with RAM $E3
clra
ldab X00E7 ; Output code
xgdx ?????
ldaa #$FF
staa $DE,x
LF309:
ldaa X00EB
bita #$04
beq LF33F
ldaa X00F0
cmpa #$0F
bcs LF33F
ldaa X00B4
cmpa #$FF
beq LF33F
ldaa X0011 ; Read TRCS
bita #$20 ; Transmit register empty ?
beq LF33F ; Nope ->
ldab X00EA
cmpb #$0E
beq LF33F
;
; AIM AND Immediate $FB with RAM $EB
clra
xgdx ?????
ldaa $B4,x
inc X00EA
; OIM OR Immediate $01 with RAM $F1 (P10 high, enable TX buffer in 75176)
ldab X00F1 ; Status ?
stab X0002 ; Port1 data
staa X0013 ; Transmit register
LF33F:
jmp LF056
Command9:
sei
ldx #$0080
LF346:
clr $7F,x
dex
bne LF346
jmp LF000
Command0:
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
jmp LF193
Command2:
ldaa X00E7 ; Output code
staa X0007 ; Port4 data (output code)
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
jmp LF193
Command1:
ldaa X00E9 ; Input code
tab
anda #$0C ; Bits 2 and 3
bne LF3D6
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
andb #$03
stab X00E7 ; Output code
ldx #$F4FA
abx ; B+X -> X
abx ; B+X -> X
ldd $00,x
std X00EE ; RAM $EE = $F4FA + X*2
ldab #$01
ldaa X00E9 ; Input code
anda #$03
LF38F:
deca
bmi LF396
aslb
jmp LF38F
;
LF396:
orab X00E4
stab X00E4
jmp LF193
Command4:
ldaa X00E9 ; Input code
anda #$0F
staa X00F3 ; RAM $F3 is lower nibble of input code
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
ldaa #$FE
staa X00F2 ; RAM $F2 = $FE
jmp LF193
Command3/CommandA:
ldaa X00E7 ; Output code
cmpa #$FF
beq LF3D6 ; Is $FF ? ->
ldaa X00E9 ; Input code
anda #$0F
staa X00F3 ; RAM $F3 is lower nibble of input code
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
ldaa #$FF
staa X00F2 ; RAM $F2 = $FF
jmp LF193
CommandD/E/F:
; OIM OR Immediate $10 with RAM $F1 (set status bit 0)
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
jmp LF193
Command5: ; Similar to command 1
ldaa X00E9 ; Input code
tab
anda #$0C ; Bits 2 and 3
bne LF3D6
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
andb #$03
stab X00E6
ldx #$F4FA
abx ; B+X -> X
abx ; B+X -> X
ldx $00,x
ldd $00,x
std X00D1 ; RAM $D1 = $F4FA + X*2 (word)
ldd $02,x
std X00D3 ; RAM $D3 = $F4FA + X*2 + 2 (word)
ldd $04,x
std X00D5 ; RAM $D5 = $F4FA + X*2 + 4 (word)
ldd $06,x
std X00D7 ; RAM $D7 = $F4FA + X*2 + 6 (word)
ldd $08,x
std X00D9 ; RAM $D9 = $F4FA + X*2 + 8 (word)
ldd $0A,x
std X00DB ; RAM $DB = $F4FA + X*2 + A (word)
ldaa $0C,x
staa X00DD ; RAM $DD = $F4FA + X*2 + C (byte) always $FF ?
clr X00E8
jmp LF193
CommandC:
ldaa X00E7 ; Output code
cmpa #$FF
beq LF3D6
ldaa X00E9 ; Input code
tab
anda #$0C
bne LF3D6
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
andb #$03
ldx #$F4FA
abx ; B+X -> X
abx ; B+X -> X
ldx $00,x
ldd $00,x
std X00D1
ldd $02,x
std X00D3
ldd $04,x
std X00D5
ldd $06,x
std X00D7
ldd $08,x
std X00D9
ldd $0A,x
std X00DB
ldaa $0C,x
staa X00DD
clra
staa X00E8
deca
staa X00F2
ldaa #$0D
staa X00F3
jmp LF193
Command6:
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
ldaa X00E9 ; Input code
staa X00E8
jmp LF193
Command7:
XF48A:
ldaa X00E4
staa X0007 ; Port4 data (output code)
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
jmp LF193
Command8:
ldaa X00E2 ; Error counter ?
staa X0007 ; Port4 data (output code)
; AIM AND Immediate $EF with RAM $F1
ldaa X00F1 ; Status ?
staa X0002 ; Port1 data
jmp LF193
CommandB:
ldaa X00F1 ; Status ?
anda #$BF
; AIM AND Immediate $EF with RAM $F1
staa X00F1 ; Status ?
staa X0002 ; Port1 data
jmp LF193
SC1:
ldaa X0011 ; Read TRCS
staa X00EC ; Store
ldaa X0012 ; Receive register
staa X00ED ; Store received code
clr X00F0
; OIM OR Immediate $02 with RAM $EB (link receive flag)
rti
IRQ1:
ldaa X000F ; Clear port3 latch flag
ldaa X0006 ; Port3 data (input code)
staa X00E9 ; Input code
; OIM OR Immediate $01 with RAM $EB (CPU write flag)
rti
XF4D6:
inc X00E2 ; Error counter ?
rti
XF4DA:
; CPU command 0: $F34E Update status
; CPU command 1: $F369
; CPU command 2: $F359 Read output code
; CPU command 3: $F3B7
; CPU command 4: $F39F
; CPU command 5: $F3E1
; CPU command 6: $F479 Put $E9 in $E8 ?
; CPU command 7: $F48A
; CPU command 8: $F49A Read error counter
; CPU command 9: $F342 Reset
; CPU command A: $F3B7 Same as command 3
; CPU command B: $F4AA Ack something ?
; CPU command C: $F426
; CPU command D: $F3D6 Invalid
; CPU command E: $F3D6 Invalid
; CPU command F: $F3D6 Invalid
XF4FA:
;0080 008D 009A 00A7 00B4 00C2 FF...