mirror of
https://github.com/simonowen/apple1emu.git
synced 2024-06-01 04:41:38 +00:00
400ebcf11b
- fixed resetting of key data on startup (1 byte out) - improved Shift-Esc to poke RET into main loop
2044 lines
66 KiB
NASM
2044 lines
66 KiB
NASM
; Apple 1 emulator for SAM Coupe v1.1, by Simon Owen
|
|
;
|
|
; WWW: http://simonowen.com/sam/apple1emu/
|
|
|
|
base: equ &b000 ; Spare-ish Apple 1 space
|
|
|
|
status: equ 249 ; Status and extended keyboard port
|
|
lmpr: equ 250 ; Low Memory Page Register
|
|
hmpr: equ 251 ; High Memory Page Register
|
|
vmpr: equ 252 ; Video Memory Page Register
|
|
keyboard: equ 254 ; Keyboard port
|
|
border: equ 254 ; Border port
|
|
rom0_off: equ %00100000 ; LMPR bit to disable ROM0
|
|
rom1_on: equ %01000000 ; LMPR bit to enable ROM1
|
|
vmpr_mode2: equ %00100000 ; Mode 2 select for VMPR
|
|
|
|
low_page: equ 3 ; LMPR during emulation
|
|
screen_page: equ 5 ; SAM display
|
|
file_page: equ 6 ; File import text page
|
|
|
|
bord_stp: equ 2 ; STP instruction halted CPU (red)
|
|
bord_wai: equ 6 ; WAI instruction waiting for interrupt (yellow)
|
|
|
|
m6502_nmi: equ &fffa ; nmi vector address
|
|
m6502_reset: equ &fffc ; reset vector address
|
|
m6502_int: equ &fffe ; int vector address (also for BRK)
|
|
|
|
getkey: equ &1cab ; SAM ROM key reading (NZ=got key in A, A=0 for no key)
|
|
|
|
|
|
; Apple 1 keyboard and display I/O locations
|
|
|
|
kbd_data: equ &d010 ; keyboard data
|
|
kbd_ctrl: equ &d011 ; keyboard control
|
|
dsp_data: equ &d012 ; display data
|
|
dsp_ctrl: equ &d013 ; display control
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
org base
|
|
dump $
|
|
autoexec
|
|
|
|
start: di
|
|
|
|
ld a,low_page+rom0_off
|
|
out (lmpr),a
|
|
ld a,vmpr_mode2+screen_page
|
|
out (vmpr),a
|
|
ld sp,stack_top
|
|
|
|
call reorder_decode ; optimise instruction decode table
|
|
call set_sam_attrs ; set the mode 2 attrs so the screen is visible
|
|
call setup_im2 ; enable IM 2
|
|
|
|
reset_loop: ld hl,0
|
|
ld (dsp_data),hl ; display ready
|
|
ld (kbd_data),hl ; no key available
|
|
|
|
ld hl,(m6502_reset) ; start from reset vector
|
|
ld (reg_pc),hl
|
|
|
|
ei
|
|
call execute ; GO!
|
|
jr reset_loop
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
; Utility functions
|
|
|
|
; Fill SAM mode 2 display attributes to make the screen visible
|
|
set_sam_attrs: ld a,screen_page+rom0_off
|
|
out (lmpr),a
|
|
|
|
ld hl,&2000
|
|
ld bc,&1844 ; 24 blocks of bright green on black
|
|
clear_lp: ld (hl),c
|
|
inc l
|
|
jr nz,clear_lp
|
|
inc h
|
|
djnz clear_lp
|
|
|
|
ld a,low_page+rom0_off
|
|
out (lmpr),a
|
|
ret
|
|
|
|
; Scroll the screen up 1 row and clear the bottom line
|
|
scroll_screen: ld hl,0
|
|
ld d,h
|
|
ld e,l
|
|
inc h
|
|
ld bc,&1700
|
|
scroll_lp: FOR 32, ldi ; 32 * LDI
|
|
jp pe,scroll_lp
|
|
dec h
|
|
scroll_clr: ld (hl),0
|
|
inc l
|
|
jp nz,scroll_clr
|
|
ret
|
|
|
|
; Advance the cursor 1 character, wrapping and scrolling if necessary
|
|
advance_chr: ld hl,(cursor_xy)
|
|
cp &5f
|
|
jr z,back_chr
|
|
cp &0a
|
|
jr z,advance_line
|
|
cp &0d
|
|
jr z,advance_line
|
|
ld a,l
|
|
add a,6
|
|
ld l,a
|
|
cp &f0
|
|
jr c,no_wrap
|
|
advance_line: ld l,0
|
|
inc h
|
|
ld a,h
|
|
cp &18
|
|
jr nz,no_wrap
|
|
dec h
|
|
exx
|
|
call scroll_screen
|
|
exx
|
|
no_wrap: ld (cursor_xy),hl
|
|
ret
|
|
back_chr: ld a,l
|
|
sub 6
|
|
ld l,a
|
|
jr nc,no_wrap
|
|
ld l,39*6
|
|
ld a,h
|
|
sub 1
|
|
adc a,0
|
|
ld h,a
|
|
jr no_wrap
|
|
|
|
; Map display character from SAM to Apple 1
|
|
map_chr: cp &20
|
|
jr c,invalid_chr
|
|
and %10111111
|
|
xor %01100000
|
|
ret
|
|
invalid_chr: xor a
|
|
ret
|
|
|
|
; Display character in A at current cursor position
|
|
display_chr: add a,a ; * 2
|
|
add a,a ; * 4
|
|
ld l,a
|
|
ld h,0
|
|
add hl,hl ; * 8
|
|
ld de,font_data
|
|
add hl,de
|
|
ld d,mask_data/256
|
|
exx
|
|
ld hl,(cursor_xy)
|
|
ld a,l
|
|
and %00000111
|
|
srl l
|
|
srl l
|
|
srl l
|
|
inc l
|
|
exx
|
|
ld e,a
|
|
exx
|
|
ld de,&0020
|
|
ld b,8
|
|
draw_lp: exx
|
|
ld c,(hl)
|
|
inc l
|
|
xor a
|
|
cp e
|
|
jr z,no_rot
|
|
ld b,e
|
|
rot_lp: srl c
|
|
rra
|
|
djnz rot_lp
|
|
no_rot: ld b,a
|
|
ld a,(de)
|
|
inc e
|
|
exx
|
|
and (hl)
|
|
inc l
|
|
exx
|
|
or c
|
|
ex af,af'
|
|
ld a,(de)
|
|
dec e
|
|
exx
|
|
and (hl)
|
|
exx
|
|
or b
|
|
exx
|
|
ld (hl),a
|
|
dec l
|
|
ex af,af'
|
|
ld (hl),a
|
|
add hl,de
|
|
djnz draw_lp
|
|
ret
|
|
|
|
; LSB=pixel position (0-240), MSB=display row (0-23)
|
|
cursor_xy: defw 0
|
|
|
|
; Map key symbols from SAM to Apple 1
|
|
map_key: cp &0c
|
|
jr z,del_key
|
|
cp &fc
|
|
jr z,tab_key
|
|
cp &80
|
|
jr nc,ignore_key
|
|
cp &61 ; 'a'
|
|
ret c
|
|
cp &7b ; 'z'+1
|
|
ret nc
|
|
and %11011111
|
|
ret
|
|
del_key: ld a,&5f ; Delete -> _
|
|
ret
|
|
tab_key: ld a,&09 ; standard tab
|
|
ret
|
|
invalid_key: ld a,&20 ; space for invalid
|
|
ret
|
|
ignore_key: xor a ; ignore
|
|
ret
|
|
|
|
; Get a type-in key from the imported file
|
|
get_filekey: ld a,file_page+rom0_off
|
|
out (lmpr),a
|
|
|
|
ld hl,(filepos)
|
|
ld a,h
|
|
or l
|
|
or (hl)
|
|
jr z,file_done ; jump if no file
|
|
|
|
file_skip: ld a,(hl) ; fetch next file character
|
|
inc hl
|
|
and a
|
|
jr z,clear_file2 ; clear file at end
|
|
cp &0d ; CR?
|
|
jr z,file_skip ; ignore CR in file
|
|
cp &0a ; LF?
|
|
jr nz,file_done
|
|
ld a,&0d ; convert LF to CR
|
|
file_done: ld (filepos),hl
|
|
ex af,af'
|
|
ld a,screen_page+rom0_off
|
|
out (lmpr),a
|
|
ex af,af'
|
|
and a
|
|
ret
|
|
filepos: defw 0
|
|
|
|
; Clear the file area to disable type-in
|
|
clear_file: ld a,file_page+rom0_off
|
|
out (lmpr),a
|
|
clear_file2: ld hl,0
|
|
ld c,l
|
|
clr_file_lp: ld (hl),c
|
|
inc l
|
|
jr nz,clr_file_lp
|
|
inc h
|
|
bit 7,h
|
|
jr nz,clr_file_lp
|
|
ld h,l
|
|
xor a ; no file character
|
|
jr file_done
|
|
|
|
update_io:
|
|
ld a,&f7
|
|
in a,(status)
|
|
and %00100000
|
|
jr nz,not_esc ; jump if Esc not pressed
|
|
|
|
call clear_file ; Esc cancels type-in mode
|
|
|
|
ld a,&fe
|
|
in a,(keyboard)
|
|
rra
|
|
jr c,not_reset ; unshifted gives chr
|
|
|
|
ld a,&c9 ; RET opcode
|
|
ld (main_loop),a ; return to reset on next instruction
|
|
not_reset:
|
|
jr c,got_key ; unshifted gives chr
|
|
|
|
still_esc: ld a,&f7
|
|
in a,(status)
|
|
and %00100000
|
|
jr z,still_esc ; wait until Esc released
|
|
|
|
ld a,&1b ; Esc character
|
|
jr got_key
|
|
not_esc:
|
|
ld a,&7f
|
|
in a,(keyboard)
|
|
bit 1,a
|
|
jr nz,not_sym
|
|
|
|
ld a,&f7
|
|
in a,(keyboard)
|
|
rra
|
|
ld c,&ff ; line interrupt disable
|
|
jr nc,got_line
|
|
rra
|
|
ld c,88 ; centre of display (312/2-68=88)
|
|
jr c,not_sym
|
|
got_line: ld a,c
|
|
out (status),a ; set or disable line interrupt
|
|
not_sym:
|
|
ld hl,kbd_ctrl
|
|
bit 7,(hl) ; key available?
|
|
jr nz,no_key ; no need to read more yet
|
|
|
|
call get_filekey ; got a type-in key from file?
|
|
jr nz,got_key ; jump if we have
|
|
|
|
skip_key: ld a,&1f+rom1_on
|
|
out (lmpr),a
|
|
call getkey
|
|
ex af,af'
|
|
ld a,screen_page+rom0_off
|
|
out (lmpr),a
|
|
ex af,af'
|
|
jr z,no_key
|
|
call map_key
|
|
and a
|
|
jr z,skip_key
|
|
got_key:
|
|
ld hl,kbd_data
|
|
ld (hl),a
|
|
set 7,(hl) ; bit 7 always set
|
|
inc l
|
|
set 7,(hl) ; key available
|
|
no_key:
|
|
ld hl,dsp_data
|
|
bit 7,(hl) ; display char available?
|
|
jr z,no_char
|
|
res 7,(hl) ; display ready
|
|
ld a,(hl) ; fetch character to display
|
|
and a
|
|
jr z,done_draw
|
|
cp &7f
|
|
jr z,done_draw
|
|
push af
|
|
ld a,&00 ; space
|
|
call display_chr ; erase cursor
|
|
pop af
|
|
cp &5f ; backspace? (underscore)
|
|
jr z,done_draw2 ; if so, no need to process further
|
|
|
|
push af
|
|
call map_chr ; map output from SAM->Apple 1
|
|
call display_chr ; show it
|
|
pop af
|
|
done_draw2: call advance_chr ; advance the cursor position
|
|
ld a,&3f ; cursor block
|
|
call display_chr ; show cursor
|
|
done_draw:
|
|
no_char:
|
|
ret
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
; Interrupt handling
|
|
|
|
setup_im2: ld hl,im2_table
|
|
ld a,im2_jp/256
|
|
im2_fill: ld (hl),a
|
|
inc l
|
|
jr nz,im2_fill
|
|
inc h
|
|
ld (hl),a ; complete the final entry
|
|
ld a,im2_table/256
|
|
ld i,a
|
|
im 2 ; set interrupt mode 2
|
|
ret
|
|
|
|
im2_handler: push af
|
|
push bc
|
|
push de
|
|
push hl
|
|
ex af,af'
|
|
exx
|
|
push af
|
|
push bc
|
|
push de
|
|
push hl
|
|
push ix
|
|
push iy
|
|
|
|
in a,(lmpr)
|
|
push af
|
|
ld a,screen_page+rom0_off
|
|
out (lmpr),a
|
|
|
|
call update_io
|
|
|
|
pop af
|
|
out (lmpr),a
|
|
|
|
pop iy
|
|
pop ix
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
pop af
|
|
exx
|
|
ex af,af'
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
pop af
|
|
ei
|
|
reti
|
|
end_1:
|
|
|
|
; IM 2 table must be aligned to 256-byte boundary
|
|
defs -$\256
|
|
im2_table: defs 257
|
|
|
|
; IM 2 vector must have LSB==MSB
|
|
defs $/256-1
|
|
stack_top: ; stack fits nicely in the slack space
|
|
im2_jp: jp im2_handler
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
; 65C02 emulation
|
|
|
|
execute: ld a,&1a ; LD A,(DE)
|
|
ld (main_loop),a
|
|
call load_state
|
|
jr main_loop
|
|
|
|
read_write_loop:
|
|
write_loop: ld a,h
|
|
cp &d0
|
|
jr z,io_write
|
|
|
|
zwrite_loop:
|
|
zread_write_loop:
|
|
main_loop: ld a,(de) ; fetch opcode
|
|
inc de ; PC=PC+1
|
|
ld l,a
|
|
ld h,decode_table/256
|
|
ld a,(hl) ; handler low
|
|
inc h
|
|
ld h,(hl) ; handler high
|
|
ld l,a
|
|
jp (hl) ; execute!
|
|
|
|
; I/O write
|
|
io_write: ld a,l
|
|
cp &12 ; display char?
|
|
jr nz,main_loop
|
|
set 7,(hl) ; display busy
|
|
jp main_loop
|
|
|
|
read_loop:
|
|
zread_loop: ld a,h
|
|
cp &d0
|
|
jr z,io_read
|
|
|
|
ld a,(de) ; fetch opcode
|
|
inc de ; PC=PC+1
|
|
ld l,a
|
|
ld h,decode_table/256
|
|
ld a,(hl) ; handler low
|
|
inc h
|
|
ld h,(hl) ; handler high
|
|
ld l,a
|
|
jp (hl) ; execute!
|
|
|
|
io_read: ld a,l
|
|
cp &10 ; key read?
|
|
jr nz,main_loop
|
|
inc l
|
|
res 7,(hl) ; key not available
|
|
jp main_loop
|
|
|
|
|
|
; 6502 addressing modes, shared by logical and arithmetic
|
|
; instructions, but inlined into the load and store.
|
|
|
|
a_indirect_x: ld a,(de) ; indirect pre-indexed with X
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a
|
|
jp (ix)
|
|
|
|
a_zero_page: ld a,(de) ; zero-page
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
jp (ix)
|
|
|
|
a_absolute: ex de,hl ; absolute (2-bytes)
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
jp (ix)
|
|
|
|
a_indirect_y: ld a,(de) ; indirect post-indexed with Y
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,iyl ; Y
|
|
add a,(hl)
|
|
inc l ; (may wrap in zero page)
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld a,0
|
|
adc a,h
|
|
ld h,a
|
|
jp (ix)
|
|
|
|
a_zero_page_x: ld a,(de) ; zero-page indexed with X
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
jp (ix)
|
|
|
|
a_zero_page_y: ld a,(de) ; zero-page indexed with Y
|
|
inc de
|
|
add a,iyl ; add Y (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
jp (ix)
|
|
|
|
a_absolute_y: ex de,hl ; absolute indexed with Y
|
|
ld a,iyl ; Y
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
jp (ix)
|
|
|
|
a_absolute_x: ex de,hl ; absolute indexed with X
|
|
ld a,iyh ; X
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
jp (ix)
|
|
|
|
a_indirect_z: ld a,(de) ; indirect zero-page [65C02]
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
inc l ; (may wrap in zero page)
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a
|
|
jp (ix)
|
|
|
|
; Instruction implementations
|
|
|
|
i_nop: equ main_loop
|
|
i_undoc_1: equ main_loop
|
|
i_undoc_3: inc de ; 3-byte NOP
|
|
i_undoc_2: inc de ; 2-byte NOP
|
|
jp main_loop
|
|
|
|
i_clc: exx ; clear carry
|
|
ld c,0
|
|
exx
|
|
jp main_loop
|
|
i_sec: exx ; set carry
|
|
ld c,1
|
|
exx
|
|
jp main_loop
|
|
i_cli: exx ; clear interrupt disable
|
|
res 2,d
|
|
exx
|
|
jp main_loop
|
|
i_sei: exx ; set interrupt disable
|
|
set 2,d
|
|
exx
|
|
jp main_loop
|
|
i_clv: exx ; clear overflow
|
|
ld b,0
|
|
exx
|
|
jp main_loop
|
|
i_cld: exx ; clear decimal mode
|
|
res 3,d
|
|
exx
|
|
xor a ; NOP
|
|
ld (adc_daa),a ; use binary mode for adc
|
|
ld (sbc_daa),a ; use binary mode for sbc
|
|
jp main_loop
|
|
i_sed: exx
|
|
set 3,d
|
|
exx
|
|
ld a,&27 ; DAA
|
|
ld (adc_daa),a ; use decimal mode for adc
|
|
ld (sbc_daa),a ; use decimal mode for sbc
|
|
jp main_loop
|
|
|
|
i_bpl: ld a,(de)
|
|
inc de
|
|
ex af,af'
|
|
ld l,a ; copy N
|
|
ex af,af'
|
|
bit 7,l ; test N
|
|
jr z,i_branch ; branch if plus
|
|
jp main_loop
|
|
i_bmi: ld a,(de)
|
|
inc de
|
|
ex af,af'
|
|
ld l,a ; copy N
|
|
ex af,af'
|
|
bit 7,l ; test N
|
|
jr nz,i_branch ; branch if minus
|
|
jp main_loop
|
|
i_bvc: ld a,(de) ; V in bit 6
|
|
inc de ; V set if non-zero
|
|
exx
|
|
bit 6,b
|
|
exx
|
|
jr z,i_branch ; branch if V clear
|
|
jp main_loop
|
|
i_bvs: ld a,(de) ; V in bit 6
|
|
inc de
|
|
exx
|
|
bit 6,b
|
|
exx
|
|
jr nz,i_branch ; branch if V set
|
|
jp main_loop
|
|
i_bcc: ld a,(de) ; C in bit 1
|
|
inc de
|
|
exx
|
|
bit 0,c
|
|
exx
|
|
jr z,i_branch ; branch if C clear
|
|
jp main_loop
|
|
i_bcs: ld a,(de)
|
|
inc de
|
|
exx
|
|
bit 0,c
|
|
exx
|
|
jr nz,i_branch ; branch if C set
|
|
jp main_loop
|
|
i_beq: ld a,(de)
|
|
inc de
|
|
inc c
|
|
dec c ; zero?
|
|
jr z,i_branch ; branch if zero
|
|
jp main_loop
|
|
i_bne: ld a,(de)
|
|
inc de
|
|
inc c
|
|
dec c ; zero?
|
|
jp z,main_loop ; no branch if not zero
|
|
i_branch: ld l,a ; offset low
|
|
rla ; set carry with sign
|
|
sbc a,a ; form high byte for offset
|
|
ld h,a
|
|
add hl,de ; PC=PC+e
|
|
ex de,hl
|
|
jp main_loop
|
|
i_bra: ld a,(de) ; unconditional branch [65C02]
|
|
inc de
|
|
jr i_branch
|
|
|
|
i_bbr_0: ld a,%00000001 ; BBRn [65C02]
|
|
jp i_bbr
|
|
i_bbr_1: ld a,%00000010
|
|
jp i_bbr
|
|
i_bbr_2: ld a,%00000100
|
|
jp i_bbr
|
|
i_bbr_3: ld a,%00001000
|
|
jp i_bbr
|
|
i_bbr_4: ld a,%00010000
|
|
jp i_bbr
|
|
i_bbr_5: ld a,%00100000
|
|
jp i_bbr
|
|
i_bbr_6: ld a,%01000000
|
|
jp i_bbr
|
|
i_bbr_7: ld a,%10000000
|
|
i_bbr: ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,0
|
|
ex de,hl
|
|
and (hl)
|
|
ld a,(de)
|
|
inc de
|
|
jr z,i_branch ; ToDo: read_loop after branch
|
|
jp read_loop
|
|
|
|
i_bbs_0: ld a,%00000001 ; BBSn [65C02]
|
|
jp i_bbs
|
|
i_bbs_1: ld a,%00000010
|
|
jp i_bbs
|
|
i_bbs_2: ld a,%00000100
|
|
jp i_bbs
|
|
i_bbs_3: ld a,%00001000
|
|
jp i_bbs
|
|
i_bbs_4: ld a,%00010000
|
|
jp i_bbs
|
|
i_bbs_5: ld a,%00100000
|
|
jp i_bbs
|
|
i_bbs_6: ld a,%01000000
|
|
jp i_bbs
|
|
i_bbs_7: ld a,%10000000
|
|
i_bbs: ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,0
|
|
ex de,hl
|
|
and (hl)
|
|
ld a,(de)
|
|
inc de
|
|
jr nz,i_branch ; ToDo: read_loop after branch
|
|
jp read_loop
|
|
|
|
i_jmp_a: ex de,hl ; JMP nn
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
jp main_loop
|
|
|
|
i_jmp_i: ex de,hl ; JMP (nn)
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
ld e,(hl)
|
|
; inc l ; 6502 bug wraps within page, *OR*
|
|
inc hl ; 65C02 spans pages correctly
|
|
ld d,(hl)
|
|
jp main_loop
|
|
|
|
i_jmp_ax: ex de,hl ; JMP (nn,X) [65C02]
|
|
ld a,iyh ; X
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl) ; carry spans page
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
jp main_loop
|
|
|
|
i_jsr: ex de,hl ; JSR nn
|
|
ld e,(hl) ; subroutine low
|
|
inc hl ; only 1 inc - we push ret-1
|
|
ld d,(hl) ; subroutine high
|
|
ld a,h ; PCh
|
|
exx
|
|
ld (hl),a ; push ret-1 high byte
|
|
dec l ; S--
|
|
exx
|
|
ld a,l ; PCl
|
|
exx
|
|
ld (hl),a ; push ret-1 low byte
|
|
dec l ; S--
|
|
exx
|
|
jp main_loop
|
|
|
|
i_brk: inc de ; return to BRK+2
|
|
ld a,d
|
|
exx
|
|
ld (hl),a ; push return MSB
|
|
dec l ; S--
|
|
exx
|
|
ld a,e
|
|
exx
|
|
ld (hl),a ; push return LSB
|
|
dec l ; S--
|
|
ld a,d
|
|
or %00010000 ; set B flag (temp)
|
|
ld (hl),a ; push flags with B set
|
|
dec l ; S--
|
|
set 2,d ; set I flag
|
|
exx
|
|
ld de,(m6502_int) ; fetch interrupt handler
|
|
jp main_loop
|
|
|
|
i_rts: exx ; RTS
|
|
inc l ; S++
|
|
ld a,(hl) ; PC LSB
|
|
exx
|
|
ld e,a
|
|
exx
|
|
inc l ; S++
|
|
ld a,(hl) ; PC MSB
|
|
exx
|
|
ld d,a
|
|
inc de ; PC++ (strange but true)
|
|
jp main_loop
|
|
|
|
i_rti: exx ; RTI
|
|
inc l ; S++
|
|
ld a,(hl) ; pop P
|
|
or %00110000 ; set T and B flags
|
|
call split_p_exx ; split P into status+flags (already exx)
|
|
exx
|
|
inc l ; S++
|
|
ld a,(hl) ; pop return LSB
|
|
exx
|
|
ld e,a
|
|
exx
|
|
inc l ; S++
|
|
ld a,(hl) ; pop return MSB
|
|
exx
|
|
ld d,a
|
|
jp main_loop
|
|
|
|
i_php: call make_p ; make P from status+flags
|
|
or %00010000 ; B always pushed as 1
|
|
exx
|
|
ld (hl),a
|
|
dec l ; S--
|
|
exx
|
|
jp main_loop
|
|
i_plp: exx ; PLP
|
|
inc l ; S++
|
|
ld a,(hl) ; P
|
|
or %00110000 ; set T and B flags
|
|
exx
|
|
call split_p ; split P into status+flags
|
|
jp main_loop
|
|
i_pha: ld a,b ; PHA
|
|
exx
|
|
ld (hl),a
|
|
dec l ; S--
|
|
exx
|
|
jp main_loop
|
|
i_pla: exx ; PLA
|
|
inc l ; S++
|
|
ld a,(hl)
|
|
exx
|
|
ld b,a ; set A
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_phx: ld a,iyh ; PHX [65C02]
|
|
exx
|
|
ld (hl),a
|
|
dec l ; S--
|
|
exx
|
|
jp main_loop
|
|
i_plx: exx ; PLX [65C02]
|
|
inc l ; S++
|
|
ld a,(hl)
|
|
exx
|
|
ld iyh,a ; set X
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_phy: ld a,iyl ; PHY [65C02]
|
|
exx
|
|
ld (hl),a
|
|
dec l ; S--
|
|
exx
|
|
jp main_loop
|
|
i_ply: exx ; PLY [65C02]
|
|
inc l ; S++
|
|
ld a,(hl)
|
|
exx
|
|
ld iyl,a ; set Y
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
|
|
i_dex: dec iyh ; X--
|
|
ld a,iyh ; X
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_dey: dec iyl ; Y--
|
|
ld a,iyl ; Y
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_inx: inc iyh ; X++
|
|
ld a,iyh ; X
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_iny: inc iyl ; Y++
|
|
ld a,iyl ; Y
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
|
|
i_txa: ld a,iyh ; X
|
|
ld b,a ; A=X
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_tya: ld a,iyl ; Y
|
|
ld b,a ; A=Y
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_tax: ld iyh,b ; X=A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_tay: ld iyl,b ; Y=A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_txs: ld a,iyh ; X
|
|
exx
|
|
ld l,a ; set S (no flags set)
|
|
exx
|
|
jp main_loop
|
|
i_tsx: exx ; TSX
|
|
ld a,l ; fetch S
|
|
exx
|
|
ld iyh,a ; X=S
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
|
|
|
|
; For speed, LDA/LDX/LDY instructions have addressing inlined
|
|
|
|
i_lda_ix: ld a,(de) ; LDA ($nn,X)
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld b,(hl) ; set A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp zread_loop
|
|
i_lda_z: ld a,(de) ; LDA $nn
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld b,(hl) ; set A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp zread_loop
|
|
i_lda_a: ex de,hl ; LDA $nnnn
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
ld b,(hl) ; set A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
i_lda_iy: ld a,(de) ; LDA ($nn),Y
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,iyl ; Y
|
|
add a,(hl)
|
|
inc l ; (may wrap in zero page)
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld a,0
|
|
adc a,h
|
|
ld h,a
|
|
ld b,(hl) ; set A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
i_lda_zx: ld a,(de) ; LDA $nn,X
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld b,(hl) ; set A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp zread_loop
|
|
i_lda_ay: ex de,hl ; LDA $nnnn,Y
|
|
ld a,iyl ; Y
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
ld b,(hl) ; set A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
i_lda_ax: ex de,hl ; LDA $nnnn,X
|
|
ld a,iyh ; X
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
ld b,(hl) ; set A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
i_lda_i: ld a,(de) ; LDA #$nn
|
|
inc de
|
|
ld b,a ; set A
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_lda_iz: ld a,(de) ; LDA ($nn) [65C02]
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
inc l ; (may wrap in zero page)
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld b,(hl) ; set A
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
|
|
i_ldx_z: ld a,(de) ; LDX $nn
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
ld iyh,a ; set X
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp zread_loop
|
|
i_ldx_a: ex de,hl ; LDX $nnnn
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
ld a,(hl)
|
|
ld iyh,a ; set X
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
i_ldx_zy: ld a,(de) ; LDX $nn,Y
|
|
inc de
|
|
add a,iyl ; add Y (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
ld iyh,a ; set X
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp zread_loop
|
|
i_ldx_ay: ex de,hl ; LDX $nnnn,Y
|
|
ld a,iyl ; Y
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
ld a,(hl)
|
|
ld iyh,a ; set X
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
i_ldx_i: ld a,(de) ; LDX #$nn
|
|
inc de
|
|
ld iyh,a ; set X
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
|
|
i_ldy_z: ld a,(de) ; LDY $nn
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
ld iyl,a ; set Y
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp zread_loop
|
|
i_ldy_a: ex de,hl ; LDY $nnnn
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
ld a,(hl)
|
|
ld iyl,a ; set Y
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
i_ldy_zx: ld a,(de) ; LDY $nn,X
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
ld iyl,a ; set Y
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp zread_loop
|
|
i_ldy_ax: ex de,hl ; LDY $nnnn,X
|
|
ld a,iyh ; X
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
ld a,(hl)
|
|
ld iyl,a ; set Y
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
i_ldy_i: ld a,(de) ; LDY #$nn
|
|
inc de
|
|
ld iyl,a ; set Y
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
|
|
|
|
; For speed, STA/STX/STY instructions have addressing inlined
|
|
|
|
i_sta_ix: ld a,(de) ; STA ($xx,X)
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld (hl),b
|
|
jp zwrite_loop
|
|
i_sta_z: ld a,(de) ; STA $nn
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld (hl),b
|
|
jp zwrite_loop
|
|
i_sta_iy: ld a,(de)
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,iyl ; Y
|
|
add a,(hl)
|
|
inc l
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld a,0
|
|
adc a,h
|
|
ld h,a
|
|
ld (hl),b
|
|
jp write_loop
|
|
i_sta_zx: ld a,(de)
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld (hl),b
|
|
jp zwrite_loop
|
|
i_sta_ay: ex de,hl
|
|
ld a,iyl ; Y
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
ld (hl),b
|
|
jp write_loop
|
|
|
|
i_sta_ax: ex de,hl
|
|
ld a,iyh ; X
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
ld (hl),b
|
|
jp write_loop
|
|
i_sta_a: ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
ld (hl),b
|
|
jp write_loop
|
|
i_sta_iz: ld a,(de) ; STA ($nn) [65C02]
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,(hl)
|
|
inc l ; (may wrap in zero page)
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld (hl),b ; store A
|
|
jp write_loop
|
|
|
|
i_stx_z: ld a,(de)
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,iyh ; X
|
|
ld (hl),a
|
|
jp zwrite_loop
|
|
i_stx_zy: ld a,(de)
|
|
inc de
|
|
add a,iyl ; add Y (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld a,iyh ; X
|
|
ld (hl),a
|
|
jp zwrite_loop
|
|
i_stx_a: ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
ld a,iyh ; X
|
|
ld (hl),a
|
|
jp write_loop
|
|
|
|
i_sty_z: ld a,(de)
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld a,iyl ; Y
|
|
ld (hl),a
|
|
jp zwrite_loop
|
|
i_sty_zx: ld a,(de)
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld a,iyl ; Y
|
|
ld (hl),a
|
|
jp zwrite_loop
|
|
i_sty_a: ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
ld a,iyl ; Y
|
|
ld (hl),a
|
|
jp write_loop
|
|
|
|
i_stz_z: ld a,(de) ; STZ $nn [65C02]
|
|
inc de
|
|
ld l,a
|
|
ld h,0
|
|
ld (hl),h
|
|
jp zwrite_loop
|
|
i_stz_zx: ld a,(de)
|
|
inc de
|
|
add a,iyh ; add X (may wrap in zero page)
|
|
ld l,a
|
|
ld h,0
|
|
ld (hl),h
|
|
jp zwrite_loop
|
|
i_stz_ax: ex de,hl
|
|
ld a,iyh ; X
|
|
add a,(hl)
|
|
ld e,a
|
|
inc hl
|
|
ld a,0
|
|
adc a,(hl)
|
|
ld d,a
|
|
inc hl
|
|
ex de,hl
|
|
ld (hl),0
|
|
jp write_loop
|
|
i_stz_a: ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ex de,hl
|
|
ld (hl),0
|
|
jp write_loop
|
|
|
|
i_adc_ix: ld ix,i_adc
|
|
jp a_indirect_x
|
|
i_adc_z: ld ix,i_adc
|
|
jp a_zero_page
|
|
i_adc_a: ld ix,i_adc
|
|
jp a_absolute
|
|
i_adc_zx: ld ix,i_adc
|
|
jp a_zero_page_x
|
|
i_adc_ay: ld ix,i_adc
|
|
jp a_absolute_y
|
|
i_adc_ax: ld ix,i_adc
|
|
jp a_absolute_x
|
|
i_adc_iy: ld ix,i_adc
|
|
jp a_indirect_y
|
|
i_adc_iz: ld ix,i_adc ; [65C02]
|
|
jp a_indirect_z
|
|
i_adc_i: ld h,d
|
|
ld l,e
|
|
inc de
|
|
i_adc: exx
|
|
ld a,c ; C
|
|
exx
|
|
rra ; set up carry
|
|
ld a,b ; A
|
|
adc a,(hl) ; A+M+C
|
|
adc_daa: nop
|
|
ld b,a ; set A
|
|
; jp set_nvzc
|
|
; fall through to set_nvzc...
|
|
|
|
set_nvzc: ld c,a ; set Z
|
|
rla ; C in bit 0, no effect on V
|
|
exx
|
|
ld c,a ; set C
|
|
jp pe,set_v
|
|
ld b,%00000000 ; V clear
|
|
exx
|
|
ld a,c
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
set_v: ld b,%01000000 ; V set
|
|
exx
|
|
ld a,c
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
|
|
i_sbc_ix: ld ix,i_sbc
|
|
jp a_indirect_x
|
|
i_sbc_z: ld ix,i_sbc
|
|
jp a_zero_page
|
|
i_sbc_a: ld ix,i_sbc
|
|
jp a_absolute
|
|
i_sbc_zx: ld ix,i_sbc
|
|
jp a_zero_page_x
|
|
i_sbc_ay: ld ix,i_sbc
|
|
jp a_absolute_y
|
|
i_sbc_ax: ld ix,i_sbc
|
|
jp a_absolute_x
|
|
i_sbc_iy: ld ix,i_sbc
|
|
jp a_indirect_y
|
|
i_sbc_iz: ld ix,i_sbc ; [65C02]
|
|
jp a_indirect_z
|
|
i_sbc_i: ld h,d
|
|
ld l,e
|
|
inc de
|
|
i_sbc: exx
|
|
ld a,c ; C
|
|
exx
|
|
rra ; set up carry
|
|
ld a,b ; A
|
|
ccf ; uses inverted carry
|
|
sbc a,(hl) ; A-M-(1-C)
|
|
sbc_daa: nop
|
|
ccf ; no carry for overflow
|
|
ld b,a ; set A
|
|
jp set_nvzc
|
|
|
|
i_and_ix: ld ix,i_and
|
|
jp a_indirect_x
|
|
i_and_z: ld ix,i_and
|
|
jp a_zero_page
|
|
i_and_a: ld ix,i_and
|
|
jp a_absolute
|
|
i_and_zx: ld ix,i_and
|
|
jp a_zero_page_x
|
|
i_and_ay: ld ix,i_and
|
|
jp a_absolute_y
|
|
i_and_ax: ld ix,i_and
|
|
jp a_absolute_x
|
|
i_and_iy: ld ix,i_and
|
|
jp a_indirect_y
|
|
i_and_iz: ld ix,i_and ; [65C02]
|
|
jp a_indirect_z
|
|
i_and_i: ld h,d
|
|
ld l,e
|
|
inc de
|
|
i_and: ld a,b ; A
|
|
and (hl) ; A&x
|
|
ld b,a ; set A
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
|
|
i_eor_ix: ld ix,i_eor
|
|
jp a_indirect_x
|
|
i_eor_z: ld ix,i_eor
|
|
jp a_zero_page
|
|
i_eor_a: ld ix,i_eor
|
|
jp a_absolute
|
|
i_eor_zx: ld ix,i_eor
|
|
jp a_zero_page_x
|
|
i_eor_ay: ld ix,i_eor
|
|
jp a_absolute_y
|
|
i_eor_ax: ld ix,i_eor
|
|
jp a_absolute_x
|
|
i_eor_iy: ld ix,i_eor
|
|
jp a_indirect_y
|
|
i_eor_iz: ld ix,i_eor ; [65C02]
|
|
jp a_indirect_z
|
|
i_eor_i: ld h,d
|
|
ld l,e
|
|
inc de
|
|
i_eor: ld a,b ; A
|
|
xor (hl) ; A^x
|
|
ld b,a ; set A
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
|
|
i_ora_ix: ld ix,i_ora
|
|
jp a_indirect_x
|
|
i_ora_z: ld ix,i_ora
|
|
jp a_zero_page
|
|
i_ora_a: ld ix,i_ora
|
|
jp a_absolute
|
|
i_ora_zx: ld ix,i_ora
|
|
jp a_zero_page_x
|
|
i_ora_ay: ld ix,i_ora
|
|
jp a_absolute_y
|
|
i_ora_ax: ld ix,i_ora
|
|
jp a_absolute_x
|
|
i_ora_iy: ld ix,i_ora
|
|
jp a_indirect_y
|
|
i_ora_iz: ld ix,i_ora ; [65C02]
|
|
jp a_indirect_z
|
|
i_ora_i: ld h,d
|
|
ld l,e
|
|
inc de
|
|
i_ora: ld a,b ; A
|
|
or (hl) ; A|x
|
|
ld b,a ; set A
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
|
|
i_cmp_ix: ld ix,i_cmp
|
|
jp a_indirect_x
|
|
i_cmp_z: ld ix,i_cmp
|
|
jp a_zero_page
|
|
i_cmp_a: ld ix,i_cmp
|
|
jp a_absolute
|
|
i_cmp_zx: ld ix,i_cmp
|
|
jp a_zero_page_x
|
|
i_cmp_ay: ld ix,i_cmp
|
|
jp a_absolute_y
|
|
i_cmp_ax: ld ix,i_cmp
|
|
jp a_absolute_x
|
|
i_cmp_iy: ld ix,i_cmp
|
|
jp a_indirect_y
|
|
i_cmp_iz: ld ix,i_cmp ; [65C02]
|
|
jp a_indirect_z
|
|
i_cmp_i: ld h,d
|
|
ld l,e
|
|
inc de
|
|
i_cmp: ld a,b ; A
|
|
sub (hl) ; A-x (result discarded)
|
|
ccf
|
|
exx
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
|
|
i_cpx_z: ld ix,i_cpx
|
|
jp a_zero_page
|
|
i_cpx_a: ld ix,i_cpx
|
|
jp a_absolute
|
|
i_cpx_i: ld h,d
|
|
ld l,e
|
|
inc de
|
|
i_cpx: ld a,iyh ; X
|
|
sub (hl) ; X-x (result discarded)
|
|
ccf
|
|
exx
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
|
|
i_cpy_z: ld ix,i_cpy
|
|
jp a_zero_page
|
|
i_cpy_a: ld ix,i_cpy
|
|
jp a_absolute
|
|
i_cpy_i: ld h,d
|
|
ld l,e
|
|
inc de
|
|
i_cpy: ld a,iyl ; Y
|
|
sub (hl) ; Y-x (result discarded)
|
|
ccf
|
|
exx
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp read_loop
|
|
|
|
|
|
i_dec_z: ld ix,i_dec_zp
|
|
jp a_zero_page
|
|
i_dec_zx: ld ix,i_dec_zp
|
|
jp a_zero_page_x
|
|
i_dec_a: ld ix,i_dec
|
|
jp a_absolute
|
|
i_dec_ax: ld ix,i_dec
|
|
jp a_absolute_x
|
|
i_dec: dec (hl) ; mem--
|
|
ld c,(hl) ; set Z
|
|
ld a,c
|
|
ex af,af' ; set N
|
|
jp read_write_loop
|
|
i_dec_zp: dec (hl) ; zero-page--
|
|
ld c,(hl) ; set Z
|
|
ld a,c
|
|
ex af,af' ; set N
|
|
jp zread_write_loop
|
|
i_dec_ac: dec b ; A-- [65C02]
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
|
|
i_inc_z: ld ix,i_inc_zp
|
|
jp a_zero_page
|
|
i_inc_zx: ld ix,i_inc_zp
|
|
jp a_zero_page_x
|
|
i_inc_a: ld ix,i_inc
|
|
jp a_absolute
|
|
i_inc_ax: ld ix,i_inc
|
|
jp a_absolute_x
|
|
i_inc: inc (hl) ; mem++
|
|
ld c,(hl) ; set Z
|
|
ld a,c
|
|
ex af,af' ; set N
|
|
jp read_write_loop
|
|
i_inc_zp: inc (hl) ; zero-page++
|
|
ld c,(hl) ; set Z
|
|
ld a,c
|
|
ex af,af' ; set N
|
|
jp zread_write_loop
|
|
i_inc_ac: inc b ; A++ [65C02]
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
|
|
i_asl_z: ld ix,i_asl
|
|
jp a_zero_page
|
|
i_asl_zx: ld ix,i_asl
|
|
jp a_zero_page_x
|
|
i_asl_a: ld ix,i_asl
|
|
jp a_absolute
|
|
i_asl_ax: ld ix,i_asl
|
|
jp a_absolute_x
|
|
i_asl_acc: sla b ; A << 1
|
|
exx
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_asl: ld a,(hl) ; x
|
|
add a,a ; x << 1
|
|
ld (hl),a ; set memory
|
|
exx
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp write_loop
|
|
|
|
i_lsr_z: ld ix,i_lsr
|
|
jp a_zero_page
|
|
i_lsr_zx: ld ix,i_lsr
|
|
jp a_zero_page_x
|
|
i_lsr_a: ld ix,i_lsr
|
|
jp a_absolute
|
|
i_lsr_ax: ld ix,i_lsr
|
|
jp a_absolute_x
|
|
i_lsr_acc: srl b ; A >> 1
|
|
exx
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld c,b ; set Z
|
|
ld a,b
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_lsr: ld a,(hl) ; x
|
|
srl a ; x >> 1
|
|
ld (hl),a ; set memory
|
|
exx
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp write_loop
|
|
|
|
i_rol_z: ld ix,i_rol
|
|
jp a_zero_page
|
|
i_rol_zx: ld ix,i_rol
|
|
jp a_zero_page_x
|
|
i_rol_a: ld ix,i_rol
|
|
jp a_absolute
|
|
i_rol_ax: ld ix,i_rol
|
|
jp a_absolute_x
|
|
i_rol_acc: ld a,b
|
|
exx
|
|
rr c ; set up carry
|
|
rla ; A << 1
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld b,a ; set A
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_rol: ld a,(hl) ; x
|
|
exx
|
|
rr c ; set up carry
|
|
rla ; x << 1
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld (hl),a ; set memory
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp write_loop
|
|
|
|
i_ror_z: ld ix,i_ror
|
|
jp a_zero_page
|
|
i_ror_zx: ld ix,i_ror
|
|
jp a_zero_page_x
|
|
i_ror_a: ld ix,i_ror
|
|
jp a_absolute
|
|
i_ror_ax: ld ix,i_ror
|
|
jp a_absolute_x
|
|
i_ror_acc: ld a,b
|
|
exx
|
|
rr c ; set up carry
|
|
rra ; A >> 1
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld b,a ; set A
|
|
ld c,b ; set Z
|
|
ex af,af' ; set N
|
|
jp main_loop
|
|
i_ror: ld a,(hl) ; x
|
|
exx
|
|
rr c ; set up carry
|
|
rra ; x >> 1
|
|
rl c ; retrieve carry
|
|
exx
|
|
ld (hl),a ; set memory
|
|
ld c,a ; set Z
|
|
ex af,af' ; set N
|
|
jp write_loop
|
|
|
|
|
|
i_bit_z: ld ix,i_bit
|
|
jp a_zero_page
|
|
i_bit_zx: ld ix,i_bit
|
|
jp a_zero_page_x
|
|
i_bit_a: ld ix,i_bit
|
|
jp a_absolute
|
|
i_bit_ax: ld ix,i_bit
|
|
jp a_absolute_x
|
|
i_bit_i: ld h,d ; BIT #$nn
|
|
ld l,e
|
|
inc de
|
|
i_bit: ld c,(hl) ; x
|
|
ld a,c
|
|
ex af,af' ; set N
|
|
ld a,c
|
|
and %01000000 ; V flag set from bit 6
|
|
exx
|
|
ld b,a ; set V
|
|
exx
|
|
ld a,b ; A
|
|
and c ; perform BIT test
|
|
ld c,a ; set Z
|
|
jp read_loop
|
|
|
|
i_tsb_z: ld ix,i_tsb ; TSB [65C02]
|
|
jp a_zero_page
|
|
i_tsb_a: ld ix,i_tsb
|
|
jp a_absolute
|
|
i_tsb: ld c,(hl) ; x
|
|
ld a,c
|
|
or b ; set bits from A
|
|
ld (hl),a
|
|
ld a,c
|
|
and b ; test bits against A
|
|
ld c,a ; set Z
|
|
jp write_loop
|
|
|
|
i_trb_z: ld ix,i_trb ; TRB [65C02]
|
|
jp a_zero_page
|
|
i_trb_a: ld ix,i_trb
|
|
jp a_absolute
|
|
i_trb: ld c,(hl) ; x
|
|
ld a,b ; A
|
|
cpl ; ~A
|
|
and c ; reset bits from A
|
|
ld (hl),a
|
|
ld a,c
|
|
and b ; test bits against A
|
|
ld c,a ; set Z
|
|
jp write_loop
|
|
|
|
i_smb_0: ld a,%00000001 ; SMBn [65C02]
|
|
jp i_smb
|
|
i_smb_1: ld a,%00000010
|
|
jp i_smb
|
|
i_smb_2: ld a,%00000100
|
|
jp i_smb
|
|
i_smb_3: ld a,%00001000
|
|
jp i_smb
|
|
i_smb_4: ld a,%00010000
|
|
jp i_smb
|
|
i_smb_5: ld a,%00100000
|
|
jp i_smb
|
|
i_smb_6: ld a,%01000000
|
|
jp i_smb
|
|
i_smb_7: ld a,%10000000
|
|
i_smb: ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,0
|
|
ex de,hl
|
|
or (hl)
|
|
ld (hl),a
|
|
jp zwrite_loop
|
|
|
|
i_rmb_0: ld a,%11111110 ; RMBn [65C02]
|
|
jp i_smb
|
|
i_rmb_1: ld a,%11111101
|
|
jp i_smb
|
|
i_rmb_2: ld a,%11111011
|
|
jp i_smb
|
|
i_rmb_3: ld a,%11110111
|
|
jp i_smb
|
|
i_rmb_4: ld a,%11101111
|
|
jp i_smb
|
|
i_rmb_5: ld a,%11011111
|
|
jp i_smb
|
|
i_rmb_6: ld a,%10111111
|
|
jp i_smb
|
|
i_rmb_7: ld a,%01111111
|
|
i_rmb: ex de,hl
|
|
ld e,(hl)
|
|
inc hl
|
|
ld d,0
|
|
ex de,hl
|
|
and (hl)
|
|
ld (hl),a
|
|
jp zwrite_loop
|
|
|
|
i_stp: dec de ; STP [65C02]
|
|
ld a,bord_stp
|
|
out (border),a
|
|
jp main_loop
|
|
|
|
i_wai: dec de ; WAI [65C02]
|
|
ld a,bord_wai
|
|
out (border),a
|
|
jp main_loop
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
make_p: ex af,af'
|
|
and %10000000 ; keep N
|
|
ld l,a ; N
|
|
ex af,af'
|
|
ld a,c ; Z
|
|
sub 1 ; set carry if zero
|
|
rla
|
|
rla
|
|
and %00000010 ; keep 6510 Z bit
|
|
or l ; N+Z
|
|
exx
|
|
or b ; N+V+Z
|
|
ld e,a
|
|
ld a,c
|
|
and %00000001 ; keep C
|
|
or e ; N+V+Z+C
|
|
exx
|
|
ret
|
|
|
|
split_p: exx
|
|
split_p_exx: ld e,a ; save P
|
|
and %00111100 ; keep CPU bits
|
|
ld d,a ; set status
|
|
ld a,e
|
|
ex af,af' ; set N
|
|
ld a,e
|
|
and %01000000 ; keep V
|
|
ld b,a ; set V
|
|
ld a,e
|
|
and %00000001 ; keep C
|
|
ld c,a ; set C
|
|
ld a,e
|
|
cpl
|
|
and %00000010 ; Z=0 NZ=2
|
|
exx
|
|
ld c,a ; set NZ
|
|
ret
|
|
|
|
load_state: ld a,(reg_a)
|
|
ld b,a ; set A
|
|
ld a,(reg_x)
|
|
ld iyh,a ; set X to IYh
|
|
ld a,(reg_y)
|
|
ld iyl,a ; set Y to IYl
|
|
exx
|
|
ld a,(reg_s)
|
|
ld l,a ; set S
|
|
ld h,&01 ; MSB for stack pointer
|
|
exx
|
|
ld a,(reg_p)
|
|
call split_p ; set P and flags
|
|
ld de,(reg_pc) ; set PC
|
|
ret
|
|
|
|
save_state: ld a,b ; get A
|
|
ld (reg_a),a
|
|
ld a,iyh ; get X from IYh
|
|
ld (reg_x),a
|
|
ld a,iyl ; get Y from IYl
|
|
ld (reg_y),a
|
|
exx
|
|
ld a,l ; get S
|
|
ld (reg_s),a
|
|
exx
|
|
call make_p ; get P
|
|
ld (reg_pc),de
|
|
ret
|
|
|
|
; While running we have the 6502 registers in Z80 registers
|
|
; These are used only to hold the state before/afterwards
|
|
reg_a: defb 0
|
|
reg_p: defb 0
|
|
reg_x: defb 0
|
|
reg_y: defb 0
|
|
reg_s: defb 0
|
|
reg_pc: defw 0
|
|
|
|
|
|
; Reordering the decode table to group low and high bytes means
|
|
; we avoid any 16-bit arithmetic for the decode stage, saving
|
|
; 12T on the old method (cool tip from Dave Laundon)
|
|
|
|
reorder_256: equ im2_table
|
|
|
|
reorder_decode:ld hl,decode_table
|
|
ld d,h
|
|
ld e,l
|
|
ld bc,reorder_256 ; 256-byte temporary store
|
|
reorder_lp: ld a,(hl) ; low byte
|
|
ld (de),a
|
|
inc l
|
|
inc e
|
|
ld a,(hl) ; high byte
|
|
ld (bc),a
|
|
inc hl
|
|
inc c
|
|
jr nz,reorder_lp
|
|
dec h ; back to 2nd half (high bytes)
|
|
reorder_lp2: ld a,(bc)
|
|
ld (hl),a
|
|
inc c
|
|
inc l
|
|
jr nz,reorder_lp2
|
|
ld a,&c9 ; RET
|
|
ld (reorder_decode),A
|
|
ret
|
|
|
|
defs -$\256 ; align table to 256-byte boundary
|
|
|
|
decode_table: DEFW i_brk,i_ora_ix,i_undoc_1,i_undoc_2 ; 00
|
|
DEFW i_tsb_z,i_ora_z,i_asl_z,i_rmb_0 ; 04
|
|
DEFW i_php,i_ora_i,i_asl_acc,i_undoc_2 ; 08
|
|
DEFW i_tsb_a,i_ora_a,i_asl_a,i_bbr_0 ; 0C
|
|
|
|
DEFW i_bpl,i_ora_iy,i_ora_iz,i_undoc_2 ; 10
|
|
DEFW i_trb_z,i_ora_zx,i_asl_zx,i_rmb_1 ; 14
|
|
DEFW i_clc,i_ora_ay,i_inc_ac,i_undoc_3 ; 18
|
|
DEFW i_trb_a,i_ora_ax,i_asl_ax,i_bbr_1 ; 1C
|
|
|
|
DEFW i_jsr,i_and_ix,i_undoc_1,i_undoc_2 ; 20
|
|
DEFW i_bit_z,i_and_z,i_rol_z,i_rmb_2 ; 24
|
|
DEFW i_plp,i_and_i,i_rol_acc,i_undoc_2 ; 28
|
|
DEFW i_bit_a,i_and_a,i_rol_a,i_bbr_2 ; 2C
|
|
|
|
DEFW i_bmi,i_and_iy,i_and_iz,i_undoc_2 ; 30
|
|
DEFW i_bit_zx,i_and_zx,i_rol_zx,i_rmb_3 ; 34
|
|
DEFW i_sec,i_and_ay,i_dec_ac,i_undoc_3 ; 38
|
|
DEFW i_bit_ax,i_and_ax,i_rol_ax,i_bbr_3 ; 3C
|
|
|
|
DEFW i_rti,i_eor_ix,i_undoc_1,i_undoc_2 ; 40
|
|
DEFW i_undoc_2,i_eor_z,i_lsr_z,i_rmb_4 ; 44
|
|
DEFW i_pha,i_eor_i,i_lsr_acc,i_undoc_2 ; 48
|
|
DEFW i_jmp_a,i_eor_a,i_lsr_a,i_bbr_4 ; 4C
|
|
|
|
DEFW i_bvc,i_eor_iy,i_eor_iz,i_undoc_2 ; 50
|
|
DEFW i_undoc_2,i_eor_zx,i_lsr_zx,i_rmb_5 ; 54
|
|
DEFW i_cli,i_eor_ay,i_phy,i_undoc_3 ; 58
|
|
DEFW i_undoc_3,i_eor_ax,i_lsr_ax,i_bbr_5 ; 5C
|
|
|
|
DEFW i_rts,i_adc_ix,i_undoc_1,i_undoc_2 ; 60
|
|
DEFW i_stz_z,i_adc_z,i_ror_z,i_rmb_6 ; 64
|
|
DEFW i_pla,i_adc_i,i_ror_acc,i_undoc_2 ; 68
|
|
DEFW i_jmp_i,i_adc_a,i_ror_a,i_bbr_6 ; 6C
|
|
|
|
DEFW i_bvs,i_adc_iy,i_adc_iz,i_undoc_2 ; 70
|
|
DEFW i_stz_zx,i_adc_zx,i_ror_zx,i_rmb_7 ; 74
|
|
DEFW i_sei,i_adc_ay,i_ply,i_undoc_3 ; 78
|
|
DEFW i_jmp_ax,i_adc_ax,i_ror_ax,i_bbr_7 ; 7C
|
|
|
|
DEFW i_bra,i_sta_ix,i_undoc_2,i_undoc_2 ; 80
|
|
DEFW i_sty_z,i_sta_z,i_stx_z,i_smb_0 ; 84
|
|
DEFW i_dey,i_bit_i,i_txa,i_undoc_2 ; 88
|
|
DEFW i_sty_a,i_sta_a,i_stx_a,i_bbs_0 ; 8C
|
|
|
|
DEFW i_bcc,i_sta_iy,i_sta_iz,i_undoc_2 ; 90
|
|
DEFW i_sty_zx,i_sta_zx,i_stx_zy,i_smb_1 ; 94
|
|
DEFW i_tya,i_sta_ay,i_txs,i_undoc_2 ; 98
|
|
DEFW i_stz_a,i_sta_ax,i_stz_ax,i_bbs_1 ; 9C
|
|
|
|
DEFW i_ldy_i,i_lda_ix,i_ldx_i,i_undoc_2 ; A0
|
|
DEFW i_ldy_z,i_lda_z,i_ldx_z,i_smb_2 ; A4
|
|
DEFW i_tay,i_lda_i,i_tax,i_undoc_2 ; A8
|
|
DEFW i_ldy_a,i_lda_a,i_ldx_a,i_bbs_2 ; AC
|
|
|
|
DEFW i_bcs,i_lda_iy,i_lda_iz,i_undoc_2 ; B0
|
|
DEFW i_ldy_zx,i_lda_zx,i_ldx_zy,i_smb_3 ; B4
|
|
DEFW i_clv,i_lda_ay,i_tsx,i_undoc_3 ; B8
|
|
DEFW i_ldy_ax,i_lda_ax,i_ldx_ay,i_bbs_3 ; BC
|
|
|
|
DEFW i_cpy_i,i_cmp_ix,i_undoc_2,i_undoc_2 ; C0
|
|
DEFW i_cpy_z,i_cmp_z,i_dec_z,i_smb_4 ; C4
|
|
DEFW i_iny,i_cmp_i,i_dex,i_wai ; C8
|
|
DEFW i_cpy_a,i_cmp_a,i_dec_a,i_bbs_4 ; CC
|
|
|
|
DEFW i_bne,i_cmp_iy,i_cmp_iz,i_undoc_2 ; D0
|
|
DEFW i_undoc_2,i_cmp_zx,i_dec_zx,i_smb_5 ; D4
|
|
DEFW i_cld,i_cmp_ay,i_phx,i_stp ; D8
|
|
DEFW i_undoc_3,i_cmp_ax,i_dec_ax,i_bbs_5 ; DC
|
|
|
|
DEFW i_cpx_i,i_sbc_ix,i_undoc_2,i_undoc_2 ; E0
|
|
DEFW i_cpx_z,i_sbc_z,i_inc_z,i_smb_6 ; E4
|
|
DEFW i_inx,i_sbc_i,i_nop,i_undoc_2 ; E8
|
|
DEFW i_cpx_a,i_sbc_a,i_inc_a,i_bbs_6 ; EC
|
|
|
|
DEFW i_beq,i_sbc_iy,i_sbc_iz,i_undoc_2 ; F0
|
|
DEFW i_undoc_2,i_sbc_zx,i_inc_zx,i_smb_7 ; F4
|
|
DEFW i_sed,i_sbc_ay,i_plx,i_undoc_3 ; F8
|
|
DEFW i_undoc_3,i_sbc_ax,i_inc_ax,i_bbs_7 ; FC
|
|
|
|
font_data:
|
|
MDAT "font.bin"
|
|
|
|
mask_data: defb %00000011,%11111111
|
|
defb %11000000,%11111111
|
|
defb %11110000,%00111111
|
|
defb %11111100,%00001111
|
|
|
|
end: equ $
|
|
length: equ end-start
|
|
|
|
|
|
; Ken Wessen's custom BASIC+Krusader+Monitor ROM (&e000-&ffff)
|
|
; BRK handler points to mini-monitor in this version
|
|
dump &e000
|
|
MDAT "65C02.rom.bin"
|
|
|
|
; Original Monitor ROM (&ff00-&ffff)
|
|
; If uncommented, this will replace the monitor ROM section from above
|
|
dump &ff00
|
|
MDAT "apple1.rom"
|