-
-
Save kalj/66b23c440557839b82728850555af283 to your computer and use it in GitHub Desktop.
W65C02SXB monitor code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define STATE_A $7e00 | |
#define STATE_Ahi $7e01 | |
#define STATE_X $7e02 | |
#define STATE_Xhi $7e03 | |
#define STATE_Y $7e04 | |
#define STATE_Yhi $7e05 | |
#define STATE_PClo $7e06 | |
#define STATE_PChi $7e07 | |
#define STATE_SP $7e0a | |
#define STATE_P $7e0c | |
#define STATE_ZP $7e14 | |
#define STATE_ZP0 $7e14 | |
#define STATE_ZP1 $7e15 | |
#define STATE_ZP2 $7e16 | |
#define STATE_ZP3 $7e17 | |
#define STATE_ZP4 $7e18 | |
;; Various irrelevant processor state bank etc | |
#define STATE_VAR08 $7e08 | |
#define STATE_VAR09 $7e09 | |
#define STATE_VAR0b $7e0b | |
#define STATE_VAR0d $7e0d | |
#define STATE_VAR0e $7e0e | |
#define STATE_VAR0f $7e0f | |
#define STATE_IS816 $7e10 | |
;; used to determine if inside the "kernel" | |
#define STATE_INKERNEL $7e11 | |
#define STATE_VAR12 $7e12 ; unused? | |
#define STATE_VAR13 $7e13 ; some temporary storage | |
#define STATE_VAR19 $7e19 ; some temporary storage | |
#define STATE_PCR $7e1c | |
#define STATE_DDRB $7e1d | |
#define STATE_DDRA $7e1e | |
#define IRQ_HANDLER_ADDRESS $7e70 | |
#define NMI_HANDLER_ADDRESS $7e72 | |
#define SHADOW_VECTOR_BASE $7efa | |
#define USR_NMI_HANDLER_ADDRESS $7efa | |
#define USR_RST_HANDLER_ADDRESS $7efc | |
#define USR_IRQ_HANDLER_ADDRESS $7efe | |
#define VIA_TIDE_PORTB $7fe0 | |
#define VIA_TIDE_PORTA $7fe1 | |
#define VIA_TIDE_DDRB $7fe2 | |
#define VIA_TIDE_DDRA $7fe3 | |
#define VIA_TIDE_ACR $7feb | |
#define VIA_TIDE_PCR $7fec | |
#define VIA_TIDE_STATCTRL VIA_TIDE_PORTB | |
#define VIA_TIDE_DATA_DIR VIA_TIDE_DDRA | |
#define VIA_TIDE_DATA VIA_TIDE_PORTA | |
#define VIA_TIDE_STATCTRL_TXEB %00000001 | |
#define VIA_TIDE_STATCTRL_RXFB %00000010 | |
#define VIA_TIDE_STATCTRL_WR %00000100 | |
#define VIA_TIDE_STATCTRL_RDB %00001000 | |
#define VIA_TIDE_STATCTRL_PWRENB %00100000 | |
.org $8000 | |
.ascii "WDC" | |
.byte $ff | |
.org $8004 | |
.byte $4c, $15, $81 | |
.byte $ff | |
.org $8008 | |
.asciiz "WDC65c02SK WDCMON Version = 2.0.4.3Version Date = Tue Jul 2 2013 16:24" | |
;; Q: what is this data?? | |
.org $8080 | |
.word $8004 | |
.word $8121 | |
.word $84b9 | |
.word $84cb | |
.word $84f0 | |
.word $7e11 | |
.word $8008 | |
.word $7e70 | |
.word $8404 | |
.word $841e | |
.word $8404 | |
.word $841e | |
.org $8100 | |
IRQ: | |
JMP (IRQ_HANDLER_ADDRESS) | |
NOP | |
.org $8104 | |
NMI: | |
JMP (NMI_HANDLER_ADDRESS) | |
NOP | |
;; unclear purpose of this section: | |
JMP (IRQ_HANDLER_ADDRESS) | |
NOP | |
JMP (NMI_HANDLER_ADDRESS) | |
NOP | |
;; at $8110 | |
infinite_wait: | |
JSR do_rts3 | |
BRA infinite_wait | |
.org $8115 | |
RST: | |
JSR initialize_state | |
JMP main_loop_with_zp_save | |
;; at $811b | |
initialize_state: | |
PHP | |
PHA | |
LDA #$01 | |
BRA @skip1 | |
;; can it start here too? ($8121) | |
PHP | |
PHA | |
@skip1: | |
SEI | |
CLD | |
STZ $7e1a | |
STZ $7e19 | |
STX STATE_X | |
STY STATE_Y | |
PLX | |
STX STATE_A | |
PLY | |
STY STATE_P | |
PHA | |
TSX | |
INX | |
INX | |
INX | |
STX STATE_SP | |
LDA #$01 | |
STA STATE_VAR0b | |
LDA #$00 | |
STA STATE_Ahi | |
STA STATE_Xhi | |
STA STATE_Yhi | |
STA STATE_VAR08 | |
STA STATE_VAR09 | |
STA STATE_VAR0e | |
STA STATE_VAR0f | |
LDA #$01 | |
STA $7e0d | |
SEC | |
.byte $fb ; INV/XCE | |
CLC | |
.byte $fb ; INV/XCE | |
LDX #$00 | |
BCC @not_has_xce | |
INX | |
@not_has_xce: | |
.byte $fb ; INV/XCE | |
STX STATE_IS816 | |
PLA | |
BEQ @skip_fill_shadow_vector | |
;; fill 7efe with $10, $81 = $8110 | |
;; fill 7efc | |
;; fill 7efa | |
LDA #<infinite_wait | |
LDX #$06 | |
@loop_low_byte: | |
STA SHADOW_VECTOR_BASE-2,X | |
DEX | |
DEX | |
BNE @loop_low_byte | |
LDA #>infinite_wait | |
LDX #$06 | |
@loop_high_byte: | |
STA SHADOW_VECTOR_BASE-1,X | |
DEX | |
DEX | |
BNE @loop_high_byte | |
@skip_fill_shadow_vector: | |
;; set up | |
LDA #$01 | |
STA STATE_INKERNEL | |
DEC A | |
STA STATE_VAR12 | |
LDA #<irq_handler | |
STA IRQ_HANDLER_ADDRESS | |
LDA #>irq_handler | |
STA IRQ_HANDLER_ADDRESS+1 | |
LDA #<nmi_handler | |
STA NMI_HANDLER_ADDRESS | |
LDA #>nmi_handler | |
STA NMI_HANDLER_ADDRESS+1 | |
JSR setup_via_tide | |
RTS | |
;; at $81a9 | |
main_loop_with_zp_save: | |
;; save zero page state (first 5 bytes) | |
;; copy 5 bytes from $00 to $7e14 | |
LDX #$04 | |
@loop_copy_5bytes: | |
LDA $00,X | |
STA STATE_ZP,X | |
DEX | |
BPL @loop_copy_5bytes | |
;; at $81b3 | |
main_loop_start: | |
JSR read_byte ; receive byte | |
@loop3: | |
CMP #$55 ; continue if received $55 | |
BNE main_loop_start | |
JSR read_byte ; receive another byte | |
CMP #$aa ; continue if $aa | |
BNE @loop3 ; else wait for another $55 | |
LDA #$cc | |
JSR write_byte ; send $cc byte | |
JSR read_byte ; receive byte | |
SEC | |
SBC #$00 | |
CMP #$0a | |
BCS main_loop_start | |
;; transform command into jump offset by doing *2 | |
ASL A | |
TAX | |
;; spoof return address as $81b2 (+1) == @loop2 above | |
LDA #>(main_loop_start-1) ; $81 | |
PHA | |
LDA #<(main_loop_start-1) ; $b2 | |
PHA | |
;; set read address to jump to from table, indexing with X | |
LDA (jumptable+1),X | |
PHA | |
LDA jumptable,X | |
PHA | |
RTS | |
jumptable: | |
.address handle_cmd_sync-1 ; 0 : cmd_sync | |
.address handle_cmd_echo-1 ; 1 : cmd_echo | |
.address handle_cmd_write-1 ; 2 : cmd_write | |
.address handle_cmd_read-1 ; 3 : cmd_read | |
.address handle_cmd_getinfo-1 ; 4 : cmd_getinfo | |
.address handle_cmd_exec-1 ; 5 : cmd_exec | |
.address do_rts-1 ; 6 : (do nothing) | |
.address do_rts-1 ; 7 : (do nothing) | |
.address complicated_write_null-1 ; 8 : jump do case below | |
.address read_byte_and_write_null-1 ; 9 : | |
;; at $81f5 | |
handle_cmd_sync: | |
LDA #$00 | |
JMP write_byte | |
;; at $81fa | |
handle_cmd_echo: | |
LDA #$00 ; read two bytes and set 3rd to 0 | |
STA $02 | |
JSR read_byte | |
STA $00 | |
JSR read_byte | |
STA $01 | |
ORA $00 ; check if received two 0's | |
BEQ @done ; then end | |
LDA $00 | |
BEQ @receive_next ; if lsb 0, | |
INC $01 ; then increment msb | |
@receive_next: | |
JSR read_byte | |
CMP $02 | |
BEQ @inc_and_write ; if | |
@hang: | |
JSR do_rts2 | |
BRA @hang | |
@inc_and_write: | |
INC A | |
JSR write_byte | |
INC $02 | |
DEC $00 | |
BNE @receive_next | |
DEC $01 | |
BNE @receive_next | |
@done: | |
RTS | |
;; at $822d | |
handle_cmd_write: | |
JSR read_byte | |
STA $00 | |
JSR read_byte | |
STA $01 | |
JSR read_byte | |
STA $02 | |
;; sanity check of address | |
LDA #$00 | |
CMP $02 | |
BCC @read_size ; continue if Bank > 0 | |
LDA #$80 | |
CMP $01 | |
BCC @read_size ; continue if MSB > $80 | |
LDA #$00 | |
CMP $00 | |
BCC @read_size ; continue if LSB > 0 | |
LDA #$01 | |
CMP $02 | |
BCS @read_size ; continue if Bank < 2 -- always true since Bank <= 0 | |
LDA #$01 | |
STA STATE_VAR19 | |
BRA @increment_address ; what is this case? | |
@read_size: | |
JSR read_byte | |
STA $03 | |
JSR read_byte | |
STA $04 | |
ORA $03 ; or msb and lsb of size | |
BEQ @done ; both are zero, then done | |
LDY #$00 | |
LDA $03 | |
BEQ @lbl2 ; increment size msb if lsb is !=0 | |
INC $04 | |
@lbl2: | |
LDA $01 | |
ORA $02 ; check if both bank and msb == 0, i.e. in zp | |
BNE @regular_store | |
LDA $00 ; if in zp, check if | |
CMP #$05 | |
BCS @regular_store ; branch if lsb >= 5 | |
; otherwise, we instead write to the zero page image. | |
; since the first 5 (0,..,4) zp entries should not be touched | |
TAY | |
JSR read_byte | |
STA STATE_ZP,Y | |
LDY #$00 | |
BEQ @increment_address | |
@regular_store: | |
JSR read_byte | |
LDX STATE_IS816 ; por que?? | |
BNE @increment_address | |
STA ($00),Y | |
BEQ @increment_address | |
@increment_address: | |
INC $00 ; increment address | |
BNE @addr_inc_done ; done if no carry | |
INC $01 ; increment msb if carry | |
BNE @addr_inc_done ; done if no carry | |
INC $02 ; increment bank if carry | |
@addr_inc_done: | |
DEC $03 ; decrement size | |
BNE @lbl2 ; if not zero continue loop | |
DEC $04 ; if zero decrement msb of size ?? | |
BNE @lbl2 ; if msb not zero continue loop | |
@done: | |
LDA STATE_VAR19 ; if not zero | |
BEQ @return | |
STZ STATE_VAR19 ; write zero | |
@return: | |
RTS | |
;; at $82af | |
handle_cmd_read: | |
JSR read_byte | |
STA $00 | |
JSR read_byte | |
STA $01 | |
JSR read_byte | |
STA $02 | |
JSR read_byte | |
STA $03 | |
JSR read_byte | |
STA $04 | |
ORA $03 | |
BEQ @done ; if size is all 0, then done | |
;; if lsb of size is 0, increment msb (?) | |
LDY #$00 | |
LDA $03 | |
BEQ @loop | |
INC $04 | |
@loop: | |
LDA $01 | |
ORA $02 ; if bank and msb are 0 (ie in zp) | |
BNE @regular_read | |
LDA $00 | |
CMP #$05 ; and if the first 5 bytes, | |
BCS @regular_read | |
TAY ; then read from state instead | |
LDA STATE_ZP,Y | |
LDY #$00 | |
BEQ @send_read_byte | |
@regular_read: | |
LDA STATE_IS816 ; weird stuff ... | |
BNE @send_read_byte ; if not 0, ie if 816, then skip reading | |
LDA ($00),Y | |
BRA @send_read_byte | |
@send_read_byte: | |
JSR write_byte | |
INC $00 ; increment address | |
BNE @addr_incr_done | |
INC $01 ; carry into msb | |
BNE @addr_incr_done | |
INC $02 ; carry into bank | |
@addr_incr_done: | |
DEC $03 ; decrement size | |
BNE @loop | |
DEC $04 | |
BNE @loop ; if both are 0, fall through to return | |
@done: | |
RTS | |
;; at $8307 | |
handle_cmd_getinfo: | |
LDA #$00 ; 00 - 00 | |
JSR write_byte | |
LDA #$7e ; 01 - 7e | |
JSR write_byte | |
LDA #$00 ; 02 - 00 | |
JSR write_byte | |
LDA STATE_IS816 ; 03 - whether has xce / is 65816 | |
JSR write_byte | |
LDA #$58 ; 04 - 58 == 'X' | |
JSR write_byte | |
LDA #$00 ; 05 - 00 | |
JSR write_byte | |
LDA #$7e ; 06 - 7e | |
JSR write_byte | |
LDA #$00 ; 07 - 00 | |
JSR write_byte | |
LDA #$00 ; 08 - 00 | |
JSR write_byte | |
LDA #$80 ; 09 - 80 | |
JSR write_byte | |
LDA #$00 ; 0a - 00 | |
JSR write_byte | |
LDA #$fa ; 0b - fa | |
JSR write_byte | |
LDA #$7e ; 0c - 7e | |
JSR write_byte | |
LDA #$00 ; 0d - 00 | |
JSR write_byte | |
LDA #$00 ; 0e - 00 | |
JSR write_byte | |
LDA #$7f ; 0f - 7f | |
JSR write_byte | |
LDA #$00 ; 10 - 00 | |
JSR write_byte | |
LDA #$fa ; 11 - fa | |
JSR write_byte | |
LDA #$ff ; 12 - ff | |
JSR write_byte | |
LDA #$00 ; 13 - 00 | |
JSR write_byte | |
LDA #$00 ; 14 - 00 | |
JSR write_byte | |
LDA #$7f ; 15 - 7f | |
JSR write_byte | |
LDA #$00 ; 16 - 00 | |
JSR write_byte | |
LDA #$ff ; 17 - ff | |
JSR write_byte | |
LDA #$7f ; 18 - 7f | |
JSR write_byte | |
LDA #$00 ; 19 - 00 | |
JSR write_byte | |
LDA #$ff ; 1a - ff | |
JSR write_byte | |
LDA #$ff ; 1b - ff | |
JSR write_byte | |
LDA #$ff ; 1c - ff | |
JMP write_byte | |
;; at $8399 | |
handle_cmd_exec: | |
JSR load_pcr | |
;; restore zp | |
LDX #$04 | |
@zp_restore_loop: | |
LDA STATE_ZP,X | |
STA $00,X | |
DEX | |
BPL @zp_restore_loop | |
LDA STATE_VAR0d | |
BEQ @label1 | |
@label2: | |
LDX STATE_SP | |
TXS | |
LDX STATE_X | |
LDY STATE_Y | |
LDA STATE_PChi ; prepare stack for RTI | |
PHA | |
LDA STATE_PClo | |
PHA | |
LDA STATE_P | |
PHA | |
LDA #$00 ; leave kernel by clearing | |
STA STATE_INKERNEL ; STATE_INKERNEL | |
LDA STATE_A | |
RTI | |
@label1: | |
BRA @label2 | |
;; at $83cc | |
do_rts: | |
RTS | |
;; Q: what is this? | |
;; at $83cd | |
dead_code_1: | |
JMP write_byte ;; 83cd 4c f0 84 JMP write_byte | |
LDA #$24 ;; 83d0 a9 24 LDA #$24 | |
JSR write_byte ;; 83d2 20 f0 84 JSR write_byte | |
LDA #$80 ;; 83d5 a9 80 LDA #$80 | |
JSR write_byte ;; 83d7 20 f0 84 JSR write_byte | |
LDA #$00 ;; 83da a9 00 LDA #$00 | |
JMP write_byte ;; 83dc 4c f0 84 JMP write_byte | |
;; at $83df | |
complicated_write_null: | |
JSR @clear_carry | |
BCC @write_null_case | |
LDA #$01 | |
JMP write_byte | |
@write_null_case: | |
LDA #$00 | |
JMP write_byte | |
@clear_carry: ; weird stuff... | |
CLC | |
RTS | |
;; at $83f0 | |
read_byte_and_write_null: | |
JSR read_byte | |
JSR @clear_carry | |
BCC @write_null_case | |
LDA #$01 | |
JMP write_byte | |
@write_null_case: | |
LDA #$00 | |
JMP write_byte | |
@clear_carry: | |
CLC | |
RTS | |
;; at $8404 | |
;; always increment var11. | |
;; if break was called, call int_save_state with A=2 | |
;; else zero var11 and call user interrupt handler | |
irq_handler: | |
INC STATE_INKERNEL | |
PHA | |
PHX | |
TSX | |
LDA $0103,X ; load P from stack | |
PLX | |
AND #$10 ; check bit 5 of P | |
BNE @broke | |
STZ STATE_INKERNEL | |
PLA | |
JMP (USR_IRQ_HANDLER_ADDRESS) ; jump to user-defined irq-handler | |
@broke: | |
LDA #$02 | |
JMP int_save_state | |
;; at $841e | |
;; if var11 is !=0 then we just do RTI | |
;; but if it is == 0, we increase it, and call int_save_state with A=7 | |
nmi_handler: | |
PHA | |
LDA STATE_INKERNEL | |
BNE @non_zero_case | |
INC STATE_INKERNEL | |
LDA #$07 | |
BRA int_save_state | |
@non_zero_case: | |
PLA | |
RTI | |
;; at $842d | |
;; saves the state, writes the input byte, and calls main_loop_with_zp_save | |
int_save_state: | |
STA STATE_VAR13 | |
PLA | |
STA STATE_A | |
STX STATE_X | |
STY STATE_Y | |
PLA ; pop P from stack | |
STA STATE_P | |
PLA ; pop pc lo byte | |
STA STATE_PClo | |
PLA ; pop pc hi byte | |
STA STATE_PChi | |
STZ STATE_VAR0e | |
STZ STATE_VAR0f | |
STZ STATE_VAR08 | |
STZ STATE_VAR09 | |
STZ STATE_Ahi | |
STZ STATE_Xhi | |
STZ STATE_Yhi | |
TSX | |
STX STATE_SP | |
LDA #$01 | |
STA STATE_VAR0b | |
STA STATE_VAR0d | |
JMP @dummy_jmp | |
@dummy_jmp: | |
JSR store_pcr | |
LDA STATE_VAR13 | |
JSR write_byte | |
JMP main_loop_with_zp_save | |
;; at $8476 | |
setup_via_tide: | |
LDA #$00 | |
STA VIA_TIDE_ACR | |
LDA #$00 | |
STA VIA_TIDE_PCR | |
STA STATE_PCR | |
LDA #%00011000 | |
STA VIA_TIDE_STATCTRL | |
LDA #%00011100 | |
STA VIA_TIDE_DDRB | |
STA STATE_DDRB | |
LDA #$00 | |
STA VIA_TIDE_DATA_DIR | |
STA STATE_DDRA | |
LDA VIA_TIDE_STATCTRL | |
PHA | |
AND #%11101111 ; why clear this random bit? | |
STA VIA_TIDE_STATCTRL | |
LDX #$5d | |
JSR sleep ; sleep for 93 = 0x5d iterations | |
PLA | |
STA VIA_TIDE_STATCTRL | |
;; wait for pwrenb to go low indicating the FT245RL has woken up | |
LDA #VIA_TIDE_STATCTRL_PWRENB | |
@loop1: | |
BIT VIA_TIDE_STATCTRL | |
BNE @loop1 | |
LDA VIA_TIDE_STATCTRL | |
AND #%01000000 ; Q: why check this random bit? | |
BEQ random_rts | |
RTS | |
;; Q: what is this stuff? | |
;; at $84b9 | |
dead_code_2: | |
LDA #$00 ;; 84b9 a9 00 LDA #$00 | |
STA VIA_TIDE_DATA_DIR ;; 84bb 8d e3 7f STA VIA_TIDE_DATA_DIR | |
LDA #$02 ;; 84be a9 02 LDA #$02 | |
BIT VIA_TIDE_STATCTRL ;; 84c0 2c e0 7f BIT VIA_TIDE_STATCTRL | |
BNE lbl84c8 ;; 84c3 d0 03 BNE 3 ; $84c8 | |
LDA #$01 ;; 84c5 a9 01 LDA #$01 | |
RTS ;; 84c7 60 RTS | |
lbl84c8: | |
LDA #$00 ;; 84c8 a9 00 LDA #$00 | |
RTS ;; 84ca 60 RTS | |
;; at $84cb | |
read_byte: | |
LDA #$00 ; set PORTA (USB Data) to input | |
STA VIA_TIDE_DATA_DIR | |
LDA #VIA_TIDE_STATCTRL_RXFB ; check RXFB bit (0 if rx data available) | |
@wait_for_input: | |
BIT VIA_TIDE_STATCTRL ; EQ/Z bit set if bit cleared | |
BNE @wait_for_input ; wait if bit was not zero | |
LDA VIA_TIDE_STATCTRL | |
ORA #VIA_TIDE_STATCTRL_RDB | |
TAX | |
AND #($ff - VIA_TIDE_STATCTRL_RDB) | |
STA VIA_TIDE_STATCTRL ; Set RDB low to enable output of next byte | |
NOP ; wait for data? | |
NOP | |
NOP | |
NOP | |
LDA VIA_TIDE_DATA ; read next byte | |
STX VIA_TIDE_STATCTRL ; Set RDB high to disable output again | |
RTS | |
;; wtf? | |
LDA #$ee | |
RTS | |
;; at $84f0 | |
write_byte: | |
LDX #$00 | |
STX VIA_TIDE_DATA_DIR ; set PORTA (USB Data) to input | |
STA VIA_TIDE_DATA ; write data to the port (although not set for output yet) | |
LDA #VIA_TIDE_STATCTRL_TXEB | |
@tx_fifo_full: | |
BIT VIA_TIDE_STATCTRL | |
BNE @tx_fifo_full ; loop if bit was not zero | |
LDA VIA_TIDE_STATCTRL | |
AND #($ff - VIA_TIDE_STATCTRL_WR) ; prepare cleared WR bit | |
TAX | |
ORA #VIA_TIDE_STATCTRL_WR | |
STA VIA_TIDE_STATCTRL ; set WR bit to accept data | |
LDA #$ff | |
STA VIA_TIDE_DATA_DIR ; set Data port to output | |
NOP | |
NOP | |
STX VIA_TIDE_STATCTRL ; clear WR bit to latch in data | |
LDA VIA_TIDE_DATA ; read data port ? perhaps to restore A | |
LDX #$00 | |
STX VIA_TIDE_DATA_DIR ; set data port to input again | |
RTS | |
random_rts: | |
RTS ; why extra return? | |
;; at $851e | |
sleep: | |
@outer_loop: | |
PHX | |
LDX #$00 | |
@inner_loop: | |
DEX | |
BNE @inner_loop | |
PLX | |
DEX | |
BNE @outer_loop | |
RTS | |
;; at $8529 | |
store_pcr: | |
LDA VIA_TIDE_PCR | |
STA STATE_PCR | |
RTS | |
;; at $8530 | |
load_pcr: | |
LDA STATE_PCR | |
STA VIA_TIDE_PCR | |
RTS | |
;; at $8537 | |
do_rts2: | |
RTS | |
;; at $8538 | |
do_rts3: | |
RTS | |
RTS | |
RTS | |
RTS | |
.org $fffa | |
.address $8104 ; NMI | |
.address $8115 ; RST | |
.address $8100 ; IRQ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment