For further development it might be good to have a minimal monitor program running on our computer system. In the first version i will only implement three commands. From here on one could write a full featured monitor with an assembler, disassembler, register and stack display, break points and single step, loading and saving programs...
m <address>
Display 16 bytes starting from the specified address as hexadecimal values and characters.
w <address> <byte>
Write the specified byte into the given address.
j <address>
Jump to the specified address. A RTS returns to monitor command loop.
Welcome to the 6502 monitor program!
> m 4000
4000 FF C0 F7 82 FF 10 FF 02 00 BF 21 BF 00 AF 00 FF |..........!.....|
> w 4000 a5
4000:A5
> m 4000
4000 A5 C0 F7 82 FF 10 FF 02 00 BF 21 BF 00 AF 00 FF |..........!.....|
>
Even a small program like this is too big to show it on a web site. Therefore here only the main command loop of the monitor is shown. The main take away for all my 6502 assembler code is: You won't find any fancy optimization for space or performance in it. My main concern was maintainability.
.setcpu "6502"
.include "zeropage.inc65"
.include "acia.inc65"
.include "string.inc65"
.include "tools.inc65"
.include "macros.inc65"
.segment "VECTORS"
.word nmi
.word reset
.word irq
.bss
BUFFER_LENGTH = 80
buffer: .res BUFFER_LENGTH + 1, 0
.code
reset: jmp main
nmi: rti
irq: rti
main: cld
ldx
txs
jsr acia_init
ld16 R0, msg_welcome
jsr acia_puts
loop: ld16 R0, prompt
jsr acia_puts
ld16 R0, buffer
lda #BUFFER_LENGTH
jsr acia_gets
lda buffer
@check_m: cmp #'m'
bne @check_w
jsr cmd_memory
jmp loop
@check_w: cmp #'w'
bne @check_j
jsr cmd_write
jmp loop
@check_j: cmp #'j'
bne @unknwon
jsr cmd_jump
jmp loop
@unknown: ld16 R0, msg_unknown_command
jsr acia_puts
jmp loop
prompt: .byte "> ", $00
assign_arrow: .byte " <- ", $00
msg_welcome: .byte $0a, $0a, "Welcome to the 6502 monitor program!", $0a, $00
msg_unknown_command: .byte "Unknown command", $0a, $00
cmd_memory: ...
cmd_write: ...
cmd_jump: ...