a2zip/ezip.asm

6454 lines
77 KiB
NASM

; Infocom EZIP (Z-Machine architecture v4) interpreter for Apple II,
; The EZIP interpreter is copyrighted by Infocom, Inc.
; This partially reverse-engineered source code is
; Ccopyright 2023 Eric Smith <spacewar@gmail.com>
cpu 6502
; The differences between revisions stated here is not comprehensizve.
iver2a equ $0201 ; Has exactly four save positions per disk, will only
; work for games that have up to 32 KiB saves.
; Released with A Mind Forever Voyaging r77 850814
iver2b equ $0202 ; Allows disks to have three or four save positions,
; supporting games with up to 46 KiB saves.
; Forces CSWL to be COUT1 at start.
; Adds "be patient" message to verify.
; Radically changes implementation of get_prop_addr,
; purpose unknown.
; Changes random number generator, purpose unknown.
; Changes subroutine Seb96, purpose unknown.
; Changes some constants in save and restore,
; purpose unknown.
; Released with Trinity r11 860509
iver2c equ $0203 ; Changes deselecting output stream 3
; (table), to prevent table stream stack underflow.
; Changes data tables used by random number generator,
; purpose unknown.
; Released with Bureaucracy r86 870212
iver2d equ $0204 ; Changes spaces to tabs in save messages (probably
; by mistake).
; Changes a constant in scan_table, purpose unknown.
; Released with Bureaucracy r116 870602
; No Apple II games with EZIP versions 2E through 2G have been found
iver2h equ $0208 ; Removes several calls to HOME.
; Changes the tabs in messages back to spaces.
; Adds two extra carriage returns at the end of
; some messages.
; Released with Nord and Bert r19 870723
char_tab equ $09
char_cr equ $0d
ifndef iver
iver equ iver2a
endif
fillto macro addr, val
while * < addr
size set addr-*
if size > 256
size set 256
endif
fcb [size] val
endm
endm
if iver==iver2a
; EZIP 2A sets the high bit of interpreter message strings
; macro for text string
text_str macro arg
irpc char,arg
fcb 'char'+$80
endm
endm
else
; EZIP 2B and later do NOT set the high bit of interpreter message strings
; macro for text string
text_str macro arg
fcb arg
endm
endif
; macro to print a message
prt_msg macro name
ldx #msg_name&$ff
lda #msg_name>>8
ldy #msg_len_name
jsr msg_out
endm
; macro to print a message and return
prt_msg_ret macro name
ldx #msg_name&$ff
lda #msg_name>>8
ldy #msg_len_name
jmp msg_out
endm
; macro to print a message, loads in alternate order (sigh)
prt_msg_alt macro name
lda #msg_name>>8
ldx #msg_name&$ff
ldy #msg_len_name
jsr msg_out
endm
; macro to fetch one byte from the PC and increment the PC
; Post-condition:
; A = fetched byte
; Y = fetched byte
fetch_pc_byte_inline macro
ldy pc_phys_page+2
sta rd_main_ram,y ; indexed to get main or card RAM
ldy pc
lda (pc_phys_page),y
sta rd_main_ram ; set back to main RAM
inc pc
bne .no_page_cross
jsr advance_pc_page
.no_page_cross:
tay
endm
; macro to start a table of addresses, split into a high byte table and a low byte table
optab_start macro label,size
label_hi equ *
label_lo equ *+size
optab_org set *
optab_siz set size
optab_idx set 0
endm
; macro for an entry in a table of addresses, split into a high byte table and a low byte table
optab_ent macro addr
org optab_org+optab_idx
fcb addr>>8
org optab_org+optab_siz+optab_idx
fcb addr&$ff
optab_idx set optab_idx+1
endm
; disk zero page variables
org $00
Z00: rmb 1
Z01: rmb 1
Z02: rmb 1
Z03: rmb 1
rwts_sector: rmb 1
rwts_track: rmb 1
Z06: rmb 1
rwts_cmd: rmb 1
rwts_buf: rmb 2
Z0a: rmb 1
rwts_slotx16: rmb 1
Z0c: rmb 1
Z0d: rmb 1
Z0e: rmb 1
Z0f: rmb 1
Z10: rmb 1
rwts18_sector: rmb 1
rmb 1
Z13: rmb 1
Z14: rmb 1
Z15: rmb 1
rmb 1
rwts18_sector_temp: rmb 1
rmb 2
Z1a: rmb 1
; Apple II zero page locations
wndwdt equ $21
wndtop equ $22
wndbot equ $23
cursrh equ $24
cursrv equ $25
bas2l equ $2a
invflg equ $32
cswl equ $36
rndloc equ $4e
; interpreter zero page variables
interp_zp_origin equ $56
org interp_zp_origin
opcode: rmb 1
argcnt: rmb 1
arg1: rmb 2
arg2: rmb 2
arg3: rmb 2
arg4: rmb 2
arg5: rmb 2
arg6: rmb 2
arg7: rmb 2
arg8: rmb 2
Z68: rmb 1
Z69: rmb 1
Z6a: rmb 1
acc: rmb 2
Z6d: rmb 1
Z6e: rmb 1
Z6f: rmb 1
Z70: rmb 1
Z71: rmb 1
Z72: rmb 1
Z73: rmb 1
Z74: rmb 1
pc: rmb 3
pc_phys_page: rmb 3 ; physical address of page holding current PC
; third byte is 0/1 for page in main/aux RAM
aux_ptr: rmb 3
aux_phys_page: rmb 3 ; physical address of page holding current PC
; third byte is 0/1 for page in main/aux RAM
Z81: rmb 1
Z82: rmb 1
Z83: rmb 1
Z84: rmb 1
rmb 2
Z87: rmb 1
Z88: rmb 1
Z89: rmb 1
Z8a: rmb 1
Z8b: rmb 1
rmb 8
Z94: rmb 1
Z95: rmb 1
Z96: rmb 1
Z97: rmb 1
Z98: rmb 1
Z99: rmb 1
Z9a: rmb 1
Z9b: rmb 1
Z9c: rmb 1
Z9d: rmb 1
Z9e: rmb 1
Z9f: rmb 1
Za0: rmb 1
Za1: rmb 1
Za2: rmb 1
Za3: rmb 1
Za4: rmb 1
Za5: rmb 1
Za6: rmb 1
Za7: rmb 1
Za8: rmb 1
Za9: rmb 1
Zaa: rmb 1
Zab: rmb 1
Zac: rmb 1
Zad: rmb 1
Zae: rmb 1
Zaf: rmb 1
disk_block_num: rmb 2
Zb2: rmb 1
Zb3: rmb 1
rmb 2
Zb6: rmb 1
Zb7: rmb 1
Zb8: rmb 1
Zb9: rmb 1
Zba: rmb 1
rmb 2
Zbd: rmb 1
Zbe: rmb 1
Zbf: rmb 1
Zc0: rmb 2
Zc2: rmb 1
Zc3: rmb 1
Zc4: rmb 1
Zc5: rmb 1
Zc6: rmb 1
Zc7: rmb 2
Zc9: rmb 2
Zcb: rmb 1
Zcc: rmb 1
Zcd: rmb 1
Zce: rmb 1
Zcf: rmb 1
Zd0: rmb 1
Zd1: rmb 1
Zd2: rmb 1
Zd3: rmb 1
Zd4: rmb 1
Zd5: rmb 1
rmb 1
Zd7: rmb 1
rmb 1
Zd9: rmb 1
rmb 4
Zde: rmb 1
rmb 2
Ze1: rmb 1
Ze2: rmb 1
Ze3: rmb 1
Ze4: rmb 1
Ze5: rmb 1
rmb 1
Ze7: rmb 1
Ze8: rmb 2
rmb 1
stk_ptr: rmb 2 ; stack pointer
Zed: rmb 2
rmb 2
ostream_1_state: rmb 1
ostream_2_state: rmb 1
ostream_3_state: rmb 1
Zf4: rmb 1
Zf5: rmb 1
Zf6: rmb 1
Zf7: rmb 1
D0100 equ $0100
D01ff equ $01ff
D0200 equ $0200
D057b equ $057b
D086a equ $086a
S086b equ $086b
org $0900
rwts_sec_buf_size equ 86
rwts_data_buf rmb 256 ; user data
rwts_pri_buf: rmb 256 ; disk nibbles
rwts_sec_buf: rmb 86 ; disk nibbles
if iver>=iver2b
align $0100
endif
D0b56: rmb 128
D0bd6: rmb 128
D0c56: rmb 128
D0cd6: rmb 128
; data stack, 256 words, builds upward
D0d56: rmb $0100
D0e56: rmb $0100
D0f56: rmb $0100
D1056: rmb $0100
local_vars: rmb 30
rmb 2
D1176: rmb 2 ; save hdr_game_ver
D1178: rmb 2 ; save stk_ptr
D117a: rmb 2 ; save Zed
D117c: rmb 3 ; save PC
align $0100
max_main_ram_addr equ $c000
max_main_ram_pages equ (max_main_ram_addr-*)>>8
; game header
hdr_arch: rmb 1 ; Z-machine architecture version
hdr_flags_1: rmb 1 ; flags 1
hdr_game_ver: rmb 2 ; game version
hdr_high_mem: rmb 2 ; base of high memory
hdr_init_pc: rmb 2 ; initial value of program counter (byte address)
hdr_vocab: rmb 2 ; location of dictionary
hdr_object: rmb 2 ; object table
hdr_globals: rmb 2 ; global variable table
hdr_pure: rmb 2 ; base of pure (immutable) memory
hdr_flags2: rmb 2 ; flags 2
rmb 6 ; "serial" (usually game release date)
hdr_abbrev: rmb 2 ; abbreviation table
hdr_length: rmb 2 ; length of file (divided by 4 for v4 and v5)
hdr_checksum: rmb 2 ; checksum of file
hdr_interp_platform: rmb 1 ; interpreter platform number
hdr_interp_rev: rmb 1 ; interpreter revision
hdr_scr_height: rmb 1 ; screen height, lines of text
hdr_scr_width: rmb 1 ; screen width, characters
D1000 equ $1000 ; used for memory test at startup only, otherwise
; would overlap Z-Machine stack or other vars
; Apple IIe I/O
kbd equ $c000
rd_main_ram equ $c002
rd_card_ram equ $c003
wr_main_ram equ $c004
wr_card_ram equ $c005
kbd_strb equ $c010
spkr equ $c030
text_on equ $c051
mixed_off equ $c052
txt_page_1 equ $c054
; Disk II I/O (indexed by slot x 16)
ph_off equ $c080
mtr_off equ $c088
mtr_on equ $c089
drv0_en equ $c08a
drv1_en equ $c08b
q6l equ $c08c
q6h equ $c08d
q7l equ $c08e
q7h equ $c08f
; Apple slot 3 firmware (80-column)
sl3fw equ $c300
; Apple II monitor ROM locations
; IIe IIe IIc IIc IIc
; IIe enh opt IIc 3.5 mem1 mem2 IIc+ IIgs
romid equ $fbb3 ; $06 $06 $06 $06 $06 $06 $06 $06 $06f
romid2 equ $fbc0 ; $ea $e0 $e0 $00 $00 $00 $00 $00 $ea
vtab equ $fc22
home equ $fc58
clreol equ $fc9c
Sfca8 equ $fca8
rdkey equ $fd0c
cout equ $fded
cout1 equ $fdf0
bell equ $ff3a
org $d000
rwts:
nop
nop
nop
php
sei
jsr rwts_inner
bcs .fail
plp
clc
rts
.fail: plp
sec
rts
pre_nibble:
ldx #$00
ldy #$02
.loop1: dey
lda (rwts_buf),y
lsr
rol rwts_sec_buf,x
lsr
rol rwts_sec_buf,x
sta rwts_pri_buf,y
inx
cpx #rwts_sec_buf_size
bcc .loop1
ldx #$00
tya
bne .loop1
ldx #rwts_sec_buf_size-1
.loop2: lda rwts_sec_buf,x
and #$3f
sta rwts_sec_buf,x
dex
bpl .loop2
rts
write_data_field:
stx Z0e
stx Dd474
sec
lda q6h,x ; check write protect
lda q7l,x
bmi .exit
lda rwts_sec_buf
sta Z0d
lda #$ff ; write a sync pattern
sta q7h,x
ora q6l,x
pha
pla
nop
ldy #$04 ; write four more sync patterns
.loop1: pha
pla
jsr write_28
dey
bne .loop1
lda #$d5 ; write data field prologue
jsr write_30
lda #$aa
jsr write_30
lda #$ad
jsr write_30
; write secondary buffer (reverse order)
tya
ldy #rwts_sec_buf_size
bne .lp2a
.loop2: lda rwts_sec_buf,y
.lp2a: eor rwts_sec_buf-1,y
tax
lda nib_tab,x
ldx Z0e
sta q6h,x
lda q6l,x
dey
bne .loop2
; write primary buffer
lda Z0d
nop
.loop3: eor rwts_pri_buf,y
tax
lda nib_tab,x
ldx Dd474
sta q6h,x
lda q6l,x
lda rwts_pri_buf,y
iny
bne .loop3
tax ; write checksum
lda nib_tab,x
ldx Z0e
jsr write_21
lda #$de ; write data field epilogue
jsr write_30
lda #$aa
jsr write_30
lda #$eb
jsr write_30
lda #$ff ; dummy write to get third byte of data field epilogue out
jsr write_30
lda q7l,x ; turn off writing
.exit: lda q6l,x
rts
write_30:
clc ; 2
write_28:
pha ; 3
pla ; 4
write_21:
sta q6h,x ; 5
ora q6l,x ; 4
rts ; 6
; +6 jsr
post_nibble:
ldy #$00
.loop1: ldx #rwts_sec_buf_size
.loop2: dex
bmi .loop1
lda rwts_pri_buf,y
lsr rwts_sec_buf,x
rol
lsr rwts_sec_buf,x
rol
sta (rwts_buf),y
iny
cpy Z0d
bne .loop2
rts
read_data_field_16:
ldy #$20
.loop1: dey
beq read_data_field_16_fail
.loop2: lda q6l,x
bpl .loop2
.loop3: eor #$d5 ; check for data field prologue 1st byte
bne .loop1
nop
.loop4: lda q6l,x
bpl .loop4
cmp #$aa ; check for data field prologue 2nd byte
bne .loop3
ldy #rwts_sec_buf_size
.loop5: lda q6l,x
bpl .loop5
cmp #$ad ; check for data field prologue 3rd byte
bne .loop3
; read secondary buffer in reverse order (high to low)
lda #$00
.loop6: dey
sty Z0d
.loop7: ldy q6l,x
bpl .loop7
eor denib_tab,y
ldy Z0d
sta rwts_sec_buf,y
bne .loop6
; read primary buffer in forward order
.loop8: sty Z0d
.loop9: ldy q6l,x
bpl .loop9
eor denib_tab,y
ldy Z0d
sta rwts_pri_buf,y
iny
bne .loop8
.loop10:
ldy q6l,x
bpl .loop10
cmp denib_tab,y ; verify checksum
bne read_data_field_16_fail
.loop11:
lda q6l,x
bpl .loop11
cmp #$de ; check for data field epilogue 1st byte
bne read_data_field_16_fail
nop
.loop12:
lda q6l,x
bpl .loop12
cmp #$aa ; check for data field epilogue 2nd byte
beq read_address_field_success
read_data_field_16_fail:
sec
rts
; search for and read address field
read_address_field:
ldy #$fc
sty Z0d
.loop1: iny
bne .loop2
inc Z0d
beq read_data_field_16_fail
.loop2: lda q6l,x
bpl .loop2
.loop3: cmp #$d5 ; check for address field prologue 1st byte
bne .loop1
nop
.loop4: lda q6l,x
bpl .loop4
cmp #$aa ; check for address field prologue 2nd byte
bne .loop3
ldy #$03
.loop5: lda q6l,x
bpl .loop5
cmp #$96 ; check for address field prologue 3rd byte
bne .loop3
lda #$00
.loop6: sta Z0e
.loop7: lda q6l,x
bpl .loop7
rol
sta Z0d
.loop8: lda q6l,x
bpl .loop8
and Z0d
sta Z0f,y
eor Z0e
dey
bpl .loop6
tay
bne read_data_field_16_fail
.loop9: lda q6l,x
bpl .loop9
cmp #$de ; check for address field epilogue 1st byte
bne read_data_field_16_fail
nop
.loop10:
lda q6l,x
bpl .loop10
cmp #$aa ; check for address field epilogue 2nd byte
bne read_data_field_16_fail
read_address_field_success:
clc
rts
seek_track:
stx rwts_slotx16
sta Z0c
cmp Dd461
beq .rtn
lda #$00
sta Z0d
.loop1: lda Dd461
sta Z0e
sec
sbc Z0c
beq .fwd5
bcs .fwd1
eor #$ff
inc Dd461
bcc .fwd2
.fwd1: adc #$fe
dec Dd461
.fwd2: cmp Z0d
bcc .fwd3
lda Z0d
.fwd3: cmp #$0c
bcs .fwd4
tay
.fwd4: sec
jsr .subr1
lda motor_on_time_tab,y
jsr delay
lda Z0e
clc
jsr .subr2
lda motor_off_time_tab,y
jsr delay
inc Z0d
bne .loop1
.fwd5: jsr delay
clc
.subr1: lda Dd461
.subr2: and #$03
rol
ora rwts_slotx16
tax
lda ph_off,x
ldx rwts_slotx16
.rtn: rts
delay: ldx #$11
.loop1: dex
bne .loop1
inc Z13
bne .fwd1
inc Z14
.fwd1: sec
sbc #$01
bne delay
rts
motor_on_time_tab:
fcb $01,$30,$28,$24,$20,$1e,$1d,$1c
fcb $1c,$1c,$1c,$1c
motor_off_time_tab:
fcb $70,$2c,$26,$22,$1f,$1e,$1d,$1c
fcb $1c,$1c,$1c,$1c
nib_tab:
fcb $96,$97,$9a,$9b,$9d,$9e,$9f,$a6
fcb $a7,$ab,$ac,$ad,$ae,$af,$b2,$b3
fcb $b4,$b5,$b6,$b7,$b9,$ba,$bb,$bc
fcb $bd,$be,$bf,$cb,$cd,$ce,$cf,$d3
fcb $d6,$d7,$d9,$da,$db,$dc,$dd,$de
fcb $df,$e5,$e6,$e7,$e9,$ea,$eb,$ec
fcb $ed,$ee,$ef,$f2,$f3,$f4,$f5,$f6
fcb $f7,$f9,$fa,$fb,$fc,$fd,$fe,$ff
denib_tab equ *-$96
fcb $00,$01,$98,$99,$02,$03,$9c,$04
fcb $05,$06,$a0,$a1,$a2,$a3,$a4,$a5
fcb $07,$08,$a8,$a9,$aa,$09,$0a,$0b
fcb $0c,$0d,$b0,$b1,$0e,$0f,$10,$11
fcb $12,$13,$b8,$14,$15,$16,$17,$18
fcb $19,$1a,$c0,$c1,$c2,$c3,$c4,$c5
fcb $c6,$c7,$c8,$c9,$ca,$1b,$cc,$1c
fcb $1d,$1e,$d0,$d1,$d2,$1f,$d4,$d5
fcb $20,$21,$d8,$22,$23,$24,$25,$26
fcb $27,$28,$e0,$e1,$e2,$e3,$e4,$29
fcb $2a,$2b,$e8,$2c,$2d,$2e,$2f,$30
fcb $31,$32,$f0,$f1,$33,$34,$35,$36
fcb $37,$38,$f8,$39,$3a,$3b,$3c,$3d
fcb $3e,$3f
; On entry:
; A = command
; $00 = read 16-sector
; $01 = write 16-sector
; $80 = read 18-sector
rwts_inner:
sta rwts_cmd
lda #$02
sta Dd475
asl
sta Dd471
ldx Z00
cpx Z01
beq .fwd1
ldx Z01
lda q7l,x
.loop1: ldy #$08
lda q6l,x
.loop2: cmp q6l,x
bne .loop1
dey
bne .loop2
ldx Z00
stx Z01
.fwd1: lda q7l,x
lda q6l,x
ldy #$08
.loop3: lda q6l,x
pha
pla
pha
pla
stx Dd473
cmp q6l,x
bne .fwd2
dey
bne .loop3
.fwd2: php
lda mtr_on,x
lda #$d8
sta Z14
lda Z02
cmp Z03
beq .fwd3
sta Z03
plp
ldy #$00
php
.fwd3: ror
bcc .fwd4
lda drv0_en,x
bcs .fwd5
.fwd4: lda drv1_en,x
.fwd5: ror Z0a
plp
php
bne .fwd6
ldy #$07
.loop4: jsr delay
dey
bne .loop4
ldx Dd473
.fwd6: lda rwts_track
jsr Sd417
plp
bne .fwd7
ldy Z14
bpl .fwd7
.loop5: ldy #$12
.loop6: dey
bne .loop6
inc Z13
bne .loop5
inc Z14
bne .loop5
.fwd7: lda rwts_cmd ; is command read or write?
ror
php
bcc .loop7 ; read
jsr pre_nibble ; write
.loop7: lda #48
sta addr_field_search_retry_counter
.loop8: ldx Dd473
lda rwts_cmd ; 16- or 18-sector?
bpl .fwd8 ; 16-sector
; 18-sector - read a data field instead of an address field
sta Z1a
jsr read_data_field_18
bcc .fwd9
bcs .loop9 ; always taken
; 16-sector - read an address field
.fwd8: jsr read_address_field
bcc .fwd9
; address field not found
.loop9: dec addr_field_search_retry_counter
bpl .loop8
; too many errors searching for address field
.loop10:
lda Dd461
pha
lda #$60
jsr Sd449
dec Dd475
beq .fwd10
lda #$04
sta Dd471
lda #$00
jsr Sd417
pla
.loop11:
jsr Sd417
jmp .loop7
.fwd9: ldy rwts18_sector
cpy Dd461
beq .fwd11
lda Dd461
pha
tya
jsr Sd449
pla
dec Dd471
bne .loop11
beq .loop10 ; always taken
.fwd10: pla
lda #$40
plp
jmp .fwd16
.fwd11: lda rwts_cmd
bmi .fwd12
ldy rwts_sector
lda interleave_tab,y
cmp Z10
bne .loop9
.fwd12: plp
bcs .fwd18
lda rwts_cmd
bpl .fwd13
ldy rwts_sector
sty Z1a
jsr read_data_field_18
bcc .fwd14 ; unnecessary
sec
bcs .fwd14
.fwd13: jsr read_data_field_16
.fwd14: bcc .fwd15
clc
php
bcc .loop9
.fwd15: ldx #$00
stx Z0d
jsr post_nibble
ldx Dd473
.rev1: lda #$00
clc
bcc .fwd17
.fwd16: sec
.fwd17: sta Z06
lda mtr_off,x
rts
.fwd18: jsr write_data_field
bcc .rev1
lda #$10
bne .fwd16 ; always taken
Sd417: asl
jsr Sd41f
lsr Dd461
rts
Sd41f: sta Z0c
jsr Sd442
lda Dd461,y
bit Z0a
bmi .fwd1
lda Dd469,y
.fwd1: sta Dd461
lda Z0c
bit Z0a
bmi .fwd2
sta Dd469,y
bpl .fwd3
.fwd2: sta Dd461,y
.fwd3: jmp seek_track
Sd442: txa
lsr
lsr
lsr
lsr
tay
rts
Sd449: pha
lda Z02
ror
ror Z0a
jsr Sd442
pla
asl
bit Z0a
bmi .fwd1
sta Dd469,y
bpl .rtn
.fwd1: sta Dd461,y
.rtn: rts
Dd461: fcb $00,$00,$00,$00,$00,$00,$00,$00
Dd469: fcb $00,$00,$00,$00,$00,$00,$00,$00
Dd471: fcb $00
addr_field_search_retry_counter:
fcb $00
Dd473: fcb $00
Dd474: fcb $00
Dd475: fcb $00
interleave_tab:
fcb $00,$04,$08,$0c,$01,$05,$09,$0d
fcb $02,$06,$0a,$0e,$03,$07,$0b,$0f
read_data_field_18:
lda #$20
sta Z15
tay
.loop1: lda #$84
dec Z15
beq .fwd3
.loop2: dey
beq .loop2
nop
nop
lda q6l,x
bpl .loop2
cmp #$d5 ; check for data field prologue 1st byte
bne .loop2
.loop3: lda q6l,x
bpl .loop3
cmp #$aa ; check for data field prologue 2nd byte
bne .loop1
.loop4: lda q6l,x
bpl .loop4
cmp #$ad ; check for data field prologue 3rd byte
bne .loop1
sec
.loop5: lda q6l,x
bpl .loop5
rol
sta rwts18_sector_temp
.loop6: lda q6l,x
bpl .loop6
and rwts18_sector_temp
sta rwts18_sector
lda Z1a
bmi .fwd1
; read 86 nibbles into secondary buffer, reverse order
.loop7: ldy #rwts_sec_buf_size
lda #$00
.loop8: dey
sty Z0d
.loop9: ldy q6l,x
bpl .loop9
eor denib_tab,y
ldy Z0d
sta rwts_sec_buf,y
bne .loop8
; read 256 nibbles into primary buffer, forward order
.loop10:
sty Z0d
.loop11:
ldy q6l,x
bpl .loop11
eor denib_tab,y
ldy Z0d
sta rwts_pri_buf,y
iny
bne .loop10
.loop12:
ldy q6l,x ; get checksum
bpl .loop12
dec Z1a
bpl .loop7
cmp denib_tab,y
bne .fwd2
.fwd1: clc
rts
.fwd2: lda #$85
.fwd3: sta Z06
sec
rts
; subroutine called by boot1
Sd505: lda text_on
lda mixed_off
lda txt_page_1
lda #rwts_data_buf>>8
sta rwts_buf+1
lda #rwts_data_buf&$ff
sta rwts_buf
lda #$01
sta Z02
sta Z03
rts
; convert block number to track and sector
Sd51d: lda #$00
sta rwts_track
ldx disk_block_num+1
ldy disk_block_num
cpx #$01 ; is the block number greater than $100?
bcc .fwd5 ; under $100, 16-sector
bne .fwd1 ; $200 or over, 18-sector
cpy #$8a ; is the block number greater than $18a
bcc .fwd5 ; under $18a, 16-sector
; 18-sector
.fwd1: lda Ze7
cmp #$02
beq .fwd2
jsr Sd87e
ldx disk_block_num+1 ; subtract $18a to get side B relative block number
ldy disk_block_num
.fwd2: tya
sec
sbc #$8a
tay
txa
sbc #$01
tax
tya
;restoring divsion by 18 sectors/track for side B
sec
.loop1: sbc #18
bcs .fwd3
dex
bmi .fwd4
sec
.fwd3: inc rwts_track
bcs .loop1
.fwd4: clc
adc #18
sta rwts_sector
lda rwts_track
cmp #35 ; max track is 34
bcc .no_int_err_0c
jmp int_err_0c
.no_int_err_0c:
lda #$84
bne .fwd7 ; always taken
; 16-sector
.fwd5: lda Ze7
cmp #$01
beq .fwd6
jsr Sd856
; convert block number to track and sector, 16-sector (side A)
ldx disk_block_num+1
ldy disk_block_num
.fwd6: tya
and #$0f
sta rwts_sector
txa
asl
asl
asl
asl
sta rwts_track
tya
lsr
lsr
lsr
lsr
ora rwts_track
clc
adc #3 ; first track of side A image
cmp #35 ; max track is 34
bcs int_err_0c
sta rwts_track
lda #$00
; 16- and 18-sector paths rejoin here
.fwd7: sta rd_main_ram
jsr rwts
bcs int_err_0e
ldy Ded07
sta wr_main_ram,y ; indexed to get main or card
ldy #$00
.loop2: lda rwts_data_buf,y
sta (Zb2),y
iny
bne .loop2
sta wr_main_ram
inc disk_block_num
bne .fwd8
inc disk_block_num+1
.fwd8: inc Zb3
lda Zb3
cmp #$c0
bcc .rtn
lda #$08
sta Zb3
lda #$01
sta Ded07
.rtn: rts
; disk I/O error
int_err_0e:
lda #$0e
jmp int_error
Ld5c8: inc rwts_sector
lda rwts_sector
and #$0f
bne .fwd1
ldx rwts_track
inx
cpx #35 ; max track is 34
bcs Ld5f3
stx rwts_track
.fwd1: sta rwts_sector
inc Zb3
clc
rts
Sd5df: ldy #$00
sta rd_main_ram
.loop1: lda (Zb2),y
sta rwts_data_buf,y
iny
bne .loop1
lda #$01
jsr rwts
bcc Ld5c8
Ld5f3: rts
int_err_0c:
lda #$0c
jmp int_error
; disk I/O error
int_err_0e_alt:
lda #$0e
jmp int_error
read_sector:
lda #$00 ; read command
jsr rwts
bcs int_err_0e_alt
ldy #$00
sta rd_main_ram
.loop1: lda rwts_data_buf,y
sta (Zb2),y
iny
bne .loop1
inc disk_block_num
bne .noincblkhi
inc disk_block_num+1
.noincblkhi:
inc rwts_sector
lda rwts_sector
and #$0f
bne .noinctrk
ldx rwts_track
inx
cpx #35 ; max track is 34
bcs Ld5f3
stx rwts_track
.noinctrk:
sta rwts_sector
inc Zb3
clc
rts
; end of low-level disk routines
Sd62f: jsr op_new_line
lda #$00
sta Zd4
if iver<=iver2d
jmp home
else
rts
endif
msg_default_is:
text_str " (Default is "
Dd646: text_str "*) >"
msg_len_default_is equ *-msg_default_is
; On entry:
; A = default value - 1
Sd64a: clc
adc #'1'
sta Dd646
prt_msg_ret default_is
if iver>=iver2b
max_save_position:
fcb $00
endif
msg_position:
fcb char_cr
text_str "Position 1-"
if iver==iver2a
text_str "4"
else
msg_position_max_ascii: text_str "*"
endif
msg_len_position equ *-msg_position
msg_drive:
fcb char_cr
text_str "Drive 1 or 2"
msg_len_drive equ *-msg_drive
msg_slot:
fcb char_cr
text_str "Slot 1-7"
msg_len_slot equ *-msg_slot
Dd67c: fcb $05
msg_pos_drive_slot_verify:
fcb char_cr,char_cr
text_str "Position "
Dd688: text_str "*; Drive #"
Dd692: text_str "*; Slot "
Dd69a: text_str "*."
fcb char_cr
text_str "Are you sure? (Y/N) >"
msg_len_pos_drive_slot_verify equ *-msg_pos_drive_slot_verify
msg_insert_save:
fcb char_cr
text_str "Insert"
if iver==iver2d
fcb char_tab
else
text_str " "
endif
text_str "SAVE disk into Drive #"
Dd6d0: text_str "*."
msg_len_insert_save equ *-msg_insert_save
msg_yes:
text_str "YES"
fcb char_cr
msg_len_yes equ *-msg_yes
msg_no:
text_str "NO"
fcb char_cr
msg_len_no equ *-msg_no
Sd6d9: prt_msg position
lda Ze1
jsr Sd64a
.loop1: jsr Sda78
cmp #char_cr
beq .fwd1
sec
sbc #'1'
if iver==iver2a
cmp #4
else
cmp max_save_position
endif
bcc .fwd2
jsr Sdd39
jmp .loop1
.fwd1: lda Ze1
.fwd2: sta Ze3
clc
adc #'1'
sta Dd688
sta Dd8d1
sta Dd99d
ora #$80
jsr Sdaee
prt_msg drive
lda Ze2
jsr Sd64a
.loop2: jsr Sda78
cmp #char_cr
beq .fwd3
sec
sbc #'1'
cmp #2
bcc .fwd4
jsr Sdd39
jmp .loop2
.fwd3: lda Ze2
.fwd4: sta Ze4
clc
adc #'1'
sta Dd6d0
sta Dd692
ora #$80
jsr Sdaee
lda romid2_save ; IIc family?
bne .fwd5 ; no
lda #$05 ; yes, force slot 6
bne .fwd7
.fwd5: prt_msg slot
lda Dd67c
jsr Sd64a
.loop3: jsr Sda78
cmp #char_cr
beq .fwd6
sec
sbc #'1'
cmp #$07
bcc .fwd7
jsr Sdd39
jmp .loop3
.fwd6: lda Dd67c
.fwd7: sta Ze5
clc
adc #'1'
sta Dd69a
ldx romid2_save ; IIc family?
beq .fwd8 ; yes
ora #$80 ; no
jsr Sdaee
.fwd8: prt_msg pos_drive_slot_verify
.loop4: jsr Sda78
cmp #'y'
beq .fwd10
cmp #'Y'
beq .fwd10
cmp #char_cr
beq .fwd10
cmp #'n'
beq .fwd9
cmp #'N'
beq .fwd9
jsr Sdd39
jmp .loop4
.fwd9: prt_msg no
jmp Sd6d9
.fwd10: prt_msg yes
lda Ze4
sta Z02
inc Z02
ldx Ze5
inx
txa
asl
asl
asl
asl
sta Z00
lda Ze3
if iver==iver2a
; exactly four save locations, each eight tracks
asl
asl
asl
sta rwts_track
lda Ze3
lsr
php
clc
adc rwts_track
sta rwts_track
lda #$00
plp
bcc .fwd11
lda #$08
.fwd11: sta rwts_sector
else
ldx max_save_position
cpx #$03
beq .fwd12
clc
adc #$03
.fwd12: tax
lda save_start_track_tbl,X
sta rwts_track
lda save_start_sector_tbl,X
sta rwts_sector
endif
prt_msg insert_save
Sd7f2: prt_msg press_return
.loop5: jsr Sda78
cmp #char_cr
beq .fwd13
jsr Sdd39
jmp .loop5
.fwd13: rts
msg_press_return:
fcb char_cr
text_str "Press [RETURN] to continue."
fcb char_cr
if iver>=iver2h
fcb char_cr
fcb char_cr
endif
msg_len_press_return equ *-msg_press_return
if iver>=iver2b
save_start_track_tbl: fcb $00,$0b,$17 ; three save positions
fcb $00,$08,$11,$19 ; four save positions
save_start_sector_tbl: fcb $00,$08,$00 ; three save positions
fcb $00,$08,$00,$08 ; four save positions
endif
msg_insert_story:
fcb char_cr
text_str "Insert"
if iver==iver2d
fcb char_tab
else
text_str " "
endif
text_str "Side "
Dd833: text_str "* of the STORY disk into Drive #1."
fcb char_cr
if iver>=iver2h
fcb char_cr
fcb char_cr
endif
msg_len_insert_story equ *-msg_insert_story
Sd856: lda #'1'
sta Dd833
lda #$01
sta Ze7
.loop1: prt_msg insert_story
jsr Sd7f2
lda #$00
sta rwts_sector
sta rwts_track
lda #$01
sta Z02
lda #$00
jsr rwts
bcs .loop1
bcc Ld8ac ; always taken
Sd87e: lda #$32
sta Dd833
lda #$02
sta Ze7
lda Z02
pha
lda #$01
sta Z02
pla
cmp #$02
beq Ld8ac
.loop2: prt_msg insert_story
jsr Sd7f2
lda #$00
sta rwts_sector
sta rwts_track
lda #$84
jsr rwts
bcs .loop2
Ld8ac: lda #$ff
sta Zd4
rts
msg_save_position:
text_str "Save Position"
fcb char_cr
msg_len_save_position equ *-msg_save_position
msg_saving_position:
fcb char_cr,char_cr
text_str "Saving"
if iver==iver2d
fcb char_tab
else
text_str " "
endif
text_str "position "
Dd8d1: text_str "* ..."
fcb char_cr
if iver>=iver2h
fcb char_cr
fcb char_cr
endif
msg_len_saving_position equ *-msg_saving_position
op_save:
jsr Sd62f
prt_msg save_position
jsr Sd6d9
prt_msg saving_position
lda hdr_game_ver
sta D1176
lda hdr_game_ver+1
sta D1176+1
lda stk_ptr
sta D1178
lda stk_ptr+1
sta D1178+1
lda Zed
sta D117a
lda Zed+1
sta D117a+1
ldx #$02
.loop1: lda pc,x
sta D117c,x
dex
bpl .loop1
lda #(hdr_arch>>8)-1
sta Zb3
jsr Sd5df
bcc .fwd1
.loop2: jsr Sd87e
if iver<=iver2d
jsr home
endif
lda #$16
sta cursrv
jsr vtab
jmp store_result_zero
.fwd1: lda #(hdr_arch>>8)-5
sta Zb3
lda #$04
sta Z73
.loop3: jsr Sd5df
bcs .loop2
dec Z73
bne .loop3
lda Z81
sta Zb3
ldx hdr_pure
inx
stx Z6d
.loop4: jsr Sd5df
bcs .loop2
dec Z6d
bne .loop4
jsr Sd87e
if iver<=iver2d
jsr home
endif
lda #$16
sta cursrv
jsr vtab
lda Ze4
sta Ze2
lda Ze5
sta Dd67c
lda Ze3
sta Ze1
lda #$01
ldx #$00
jmp store_result_xa
msg_restore_position:
text_str "Restore Position"
fcb char_cr
msg_len_restore_position equ *-msg_restore_position
msg_restoring_position:
fcb char_cr,char_cr
text_str "Restoring position "
Dd99d: text_str "* ..."
fcb char_cr
if iver>=iver2h
fcb char_cr
fcb char_cr
endif
msg_len_restoring_position equ *-msg_restoring_position
op_restore:
jsr Sd62f
prt_msg restore_position
jsr Sd6d9
prt_msg restoring_position
ldx #$1f
.loop1: lda local_vars,x
sta D0100,x
dex
bpl .loop1
lda #(hdr_arch>>8)-1
sta Zb3
jsr read_sector
bcs .loop2
lda D1176
cmp hdr_game_ver
bne .loop2
lda D1176+1
cmp hdr_game_ver+1
beq .fwd1
.loop2: ldx #$1f
.loop3: lda D0100,x
sta local_vars,x
dex
bpl .loop3
jsr Sd87e
if iver<=iver2d
jsr home
endif
lda #$16
sta cursrv
jsr vtab
jmp store_result_zero
.fwd1: lda hdr_flags2
sta Z6d
lda hdr_flags2+1
sta Z6e
lda #(hdr_arch>>8)-5
sta Zb3
lda #$04
sta Z73
.loop4: jsr read_sector
bcs .loop2
dec Z73
bne .loop4
lda Z81
sta Zb3
jsr read_sector
bcs .loop2
lda Z6d
sta hdr_flags2
lda Z6e
sta hdr_flags2+1
lda hdr_pure
sta Z6d
.loop5: jsr read_sector
bcs .loop2
dec Z6d
bne .loop5
lda D1178
sta stk_ptr
lda D1178+1
sta stk_ptr+1
lda D117a
sta Zed
lda D117a+1
sta Zed+1
ldx #$02
.loop6: lda D117c,x
sta pc,x
dex
bpl .loop6
jsr find_pc_page
jsr Sd87e
if iver<=iver2d
jsr home
endif
lda #$16
sta cursrv
jsr vtab
lda Ze4
sta Ze2
lda Ze5
sta Dd67c
lda Ze3
sta Ze1
lda #$02
ldx #$00
jmp store_result_xa
Sda78: cld
txa
pha
tya
pha
.loop1: jsr rdkey
and #$7f
cmp #$0d
bne .fwd1
jmp .fwd6
.fwd1: cmp #$7f
bne .fwd2
jmp .fwd6
.fwd2: ldx #$0a
.loop2: cmp Ddad8,x
beq .fwd3
dex
bpl .loop2
bmi .fwd4 ; always taken
.fwd3: lda Ddae3,x
bne .fwd6
.fwd4: cmp #$20
bcc .fwd5
if iver<=iver2d
cmp #$2b
beq .fwd5
endif
cmp #$3c
bcc .fwd6
cmp #$3f
beq .fwd6
cmp #$7b
bcs .fwd5
cmp #$61
bcs .fwd6
cmp #$41
bcc .fwd5
cmp #$5b
bcc .fwd6
.fwd5: jsr Sdd39
jmp .loop1
.fwd6: sta Zd7
adc rndloc
sta rndloc
eor rndloc+1
sta rndloc+1
pla
tay
pla
tax
lda Zd7
rts
Ddad8: fcb $08,$15,$0b,$0a,$3c,$5f,$3e,$40
fcb $25
if iver<=iver2b
fcb $5e,$26
else
fcb $26,$5e
endif
Ddae3: fcb $0b,$07,$0e,$0d,$2c,$2d,$2e,$32
fcb $35
if iver<=iver2b
fcb $36,$37
else
fcb $37,$0e
endif
Sdaee: sta Zd7
txa
pha
tya
pha
lda Zd7
jsr cout
pla
tay
pla
tax
rts
Sdafe: jsr Sf446
lda #$00
sta Zd0
sta Zd1
ldy wndtop
sty Zd5
dec argcnt
dec argcnt
beq .fwd3
lda arg3
sta Z6e
lda #$00
sta Z70
sta Z6f
dec argcnt
beq .fwd1
lda arg4
sta Z6f
lda arg4+1
sta Z70
.fwd1: bit kbd_strb
.loop1: lda Z6e
sta Z6d
.loop2: ldx #$0a
.loop3: lda #$40
jsr Sfca8
dex
bne .loop3
bit kbd
bmi .fwd3
dec Z6d
bne .loop2
lda Z6f
ora Z70
bne .fwd2
jmp .fwd10
.fwd2: jsr Sf5f9
lda acc
beq .loop1
jmp .fwd10
.fwd3: ldy #$00
.loop4: jsr Sda78
cmp #$0e
beq .fwd7
cmp #$07
beq .fwd7
cmp #$0d
beq .fwd8
cmp #$7f
beq .fwd5
cmp #$0b
beq .fwd5
sta D0200,y
iny
.loop5: ldx invflg
bpl .fwd4
ora #$80
.fwd4: jsr Sdaee
if iver==iver2a
cpy Zbe
else
cpy #$4d
endif
bcc .loop4
.loop6: jsr Sda78
cmp #$0d
beq .fwd8
cmp #$7f
beq .fwd5
cmp #$0b
beq .fwd5
jsr Sdd39
jmp .loop6
.fwd5: dey
bmi .fwd6
lda #$08
jsr Sdaee
lda #$a0
jsr Sdaee
lda #$08
bne .loop5
.fwd6: ldy #$00
.fwd7: jsr Sdd39
jmp .loop4
.fwd8: lda #$8d
sta D0200,y
iny
sty Z9f
sty Zde
jsr Sdaee
.loop7: lda D01ff,y
cmp #$41
bcc .fwd9
cmp #$5b
bcs .fwd9
adc #$20
.fwd9: and #$7f
sta (Zc3),y
dey
bne .loop7
jsr Sdbf3
lda Z9f
rts
.fwd10: lda #$00
rts
; On entry:
; A:X message address
; Y message length
msg_out:
stx .lda+1
sta .lda+2
sty Z6f
ldx #$00
.loop1:
.lda fcb $bd,$00,$00 ; lda $0000,x ; self-modifying code, MUST be absolute,x
ldy invflg
bpl .fwd1
ora #$80
.fwd1: jsr Sdaee
inx
dec Z6f
bne .loop1
rts
Ldbf2: rts
Sdbf3: lda Zd4
beq Ldbf2
lda ostream_2_state
beq Ldbf2
lda cswl
pha
lda cswl+1
pha
lda cursrh
pha
lda D057b
pha
lda Ddc35
sta cswl
lda Ddc35+1
sta cswl+1
lda #$00
sta cursrh
sta D057b
ldy #$00
.loop1: lda D0200,y
jsr cout
iny
dec Zde
bne .loop1
pla
sta D057b
pla
sta cursrh
pla
sta cswl+1
pla
sta cswl
rts
Ddc34: fcb $00
Ddc35: fdb $0000
Sdc37: prt_msg printer_slot
lda #$00
jsr Sd64a
jsr Sda78
cmp #char_cr
beq .fwd1
sec
sbc #'0'
cmp #$08
bcs Sdc37
bcc .fwd2
.fwd1: lda #$01
.fwd2: clc
adc #$c0
sta Ddc35+1
jsr Sdd17
inc Ddc34
; send sequence <control-I>80N to convince printer firmware to use
; 80 columns
lda cswl
pha
lda cswl+1
pha
lda Ddc35
sta cswl
lda Ddc35+1
sta cswl+1
lda #$89
jsr cout
lda #$b8
jsr cout
lda #$b0
jsr cout
lda #$ce
jsr cout
lda cswl
sta Ddc35
lda cswl+1
sta Ddc35+1
pla
sta cswl+1
pla
sta cswl
rts
op_split_window:
lda hdr_flags_1
and #$20
beq Ldcd7
lda arg1
beq Sdcd8
if iver==iver2a
cmp #23
else
cmp #24
endif
bcs Ldcd7
ldx Zd9
beq .fwd1
lda wndtop
sec
sbc arg1
bcs .fwd2
.fwd1: lda arg1
if iver==iver2a
sta wndbot
endif
sta Zd9
if iver==iver2a
jsr home
endif
.fwd2: lda #24
sta wndbot
lda arg1
sta wndtop
cmp Zd5
bcc .fwd3
sta Zd5
.fwd3: lda #$00
sta cursrh
sta D057b
lda #23
sta cursrv
jsr vtab
Ldcd7: rts
Sdcd8: lda #$00
sta wndtop
sta Zd5
sta Zd9
rts
op_set_window:
lda hdr_flags_1
and #$01
beq Ldcd7
lda Zd9
beq Ldcd7
lda arg1
bne .fwd1
lda #$ff
sta Zd4
lda #$00
sta Zc2
if iver<=iver2d
sta cursrh
sta D057b
else
lda Zd0
sta D057b
sta cursrh
endif
lda #$17
sta cursrv
if iver<=iver2d
bne .fwd2
else
jmp .fwd2
endif
.fwd1: cmp #$01
bne Ldcd7
sta Zc2
lda #$00
sta Zd4
sta cursrh
sta D057b
sta cursrv
.fwd2: jmp vtab
Sdd17: lda #char_cr+$80
jmp cout
op_sound_effect:
lda hdr_flags_1
and #$20
beq .rtn
ldx arg1
dex
beq Sdd39
dex
bne .rtn
ldy #$ff
.loop1: lda #$10
jsr Sfca8
lda spkr
dey
bne .loop1
.rtn: rts
Sdd39: jmp bell
Sdd3c: lda #$00
sta Zf7
.loop1: ldy #$00
.loop2: sta D1000,y
iny
bne .loop2
inc Zf7
lda Zf7
sta wr_card_ram
.loop3: sta D1000,y
iny
bne .loop3
sta wr_main_ram
dec Zf7
.loop4: lda D1000,y
cmp Zf7
bne .fwd1
iny
bne .loop4
inc Zf7
sta rd_card_ram
.loop5: lda D1000,y
cmp Zf7
bne .fwd1
iny
bne .loop5
sta rd_main_ram
lda Zf7
bne .loop1
clc
rts
.fwd1: sta rd_main_ram
sec
rts
romid2_save:
fcb $00
Ddd82: fcb $00
Ddd83: fcb $00
; interpreter startup entry point jumped from boot1
interp_start:
lda bas2l+1
sta Z00
sta Z01
if iver>=iver2b
lda #cout1>>8
sta cswl+1
lda #cout1&$ff
sta cswl
endif
ldx #$00
stx rwts_sector
stx Zb2
inx ; read rest of interpreter starting with track 1
stx rwts_track
stx Z02
stx Z03
lda #$df ; starting at $df00
sta Zb3
lda #25 ; sector count
sta Z6d
.loop1: jsr read_sector
dec Z6d
bne .loop1
lda #$ff
sta invflg
lda romid
cmp #$06 ; is the computer an Apple IIe or later?
beq .fwd1 ; yes
jmp computer_inadequate
.fwd1: lda romid2
sta romid2_save
beq .fwd2
jsr Sdd3c
bcs computer_inadequate
.fwd2: jsr sl3fw
restart:
lda Z01
ldx Z03
sta Ddd82
stx Ddd83
jsr home
lda #$0a
sta cursrv
lda #$1b
sta cursrh
sta D057b
jsr vtab
prt_msg_alt story_loading
lda #$00 ; clear interp zero page vars
ldx #interp_zp_origin
.loop2: sta Z00,x
inx
bne .loop2
inc stk_ptr
inc Zed
inc Zd4
inc ostream_1_state
inc Ze7
lda #hdr_arch>>8
sta Z81
sta Zb3
lda #$00
sta Ded07
jsr Sd51d
lda hdr_arch ; check header architecture version version
cmp #$04
beq Lde21
lda #$0f
jmp int_error
computer_inadequate:
lda #$05
sta cursrv
jsr vtab
lda #$00
jmp int_error
Lde21:
if iver>=iver2b
lda hdr_pure ; heck header size of impure memory
cmp #$ad ; BUG - should be max_main_ram_pages, which differs ($ad or $ae) depending on interpreter revision
bcc .fwd1a
lda #$0d
jmp int_error
.fwd1a: cmp #$80
bcc .fwd1b
lda #$03
bne .fwd1c
.fwd1b: lda #$04
.fwd1c: sta max_save_position
clc
adc #$30
sta msg_position_max_ascii
endif
ldx hdr_high_mem ; base of high memory
inx
stx Z82
lda hdr_flags_1
ora #$33 ; bit 0: coulurs available (!)
; bit 1: picture display av (!)
; bit 4: fixed-space style av
; bit 5: sound effects av
sta hdr_flags_1
lda #iver>>8 ; set interpreter platform number
sta hdr_interp_platform
lda #$40+(iver&$ff) ; set interpreter revision
sta hdr_interp_rev
lda #24 ; set screen dimensiosn
sta hdr_scr_height
lda #80
sta hdr_scr_width
lda hdr_globals
clc
adc Z81
sta Z84
lda hdr_globals+1
sta Z83
lda hdr_abbrev
clc
adc Z81
sta Z88
lda hdr_abbrev+1
sta Z87
lda hdr_object
clc
adc Z81
sta Z8a
lda hdr_object+1
sta Z89
jsr Seeef
jsr home
lda hdr_init_pc
sta pc+1
lda hdr_init_pc+1
sta pc
jsr find_pc_page
ldx wndwdt
dex
stx Zbf
lda Ddc34
bpl .fwd3
lda #$01
sta Ddc34
sta ostream_2_state
ora hdr_flags2+1
sta hdr_flags2+1
.fwd3: jsr home
; fall into main loop
main_loop:
lda #$00
sta argcnt
fetch_pc_byte_inline
sta opcode
bmi op_80_ff
jmp op_00_7f
op_80_ff:
cmp #$b0
bcs op_b0_ff
jmp op_80_af
op_b0_ff:
cmp #$c0
bcs op_c0_ff
jmp op_b0_bf
; opcode $c0..$ff: VAR format
op_c0_ff:
cmp #$ec ; is it call_vs2 (up to 8 args)?
beq op_ec ; yes
jsr fetch_pc_byte
sta Z68
ldx #$00
stx Z6a
beq .fwd1 ; always taken
.loop1: lda Z68
asl
asl
sta Z68
.fwd1: and #$c0
bne .fwd2
jsr Se075
jmp .fwd4
.fwd2: cmp #$40
bne .fwd3
jsr Se071
jmp .fwd4
.fwd3: cmp #$80
bne Ldf08
jsr Se089
.fwd4: ldx Z6a
lda acc
sta arg1,x
lda acc+1
sta arg1+1,x
inc argcnt
inx
inx
stx Z6a
cpx #$08
bcc .loop1
Ldf08: lda opcode
cmp #$e0
bcs Ldf11
jmp dispatch_2op_tab
; dispatch through VAR op table
Ldf11: and #$1f
tay
lda tab_var_lo,y
sta Ldf20+1
lda tab_var_hi,y
sta Ldf20+2
Ldf20 jsr $ffff ; self-modifying code
jmp main_loop
int_err_01:
lda #$01
jmp int_error
; call_vf2, up to eight args
op_ec: jsr fetch_pc_byte
sta Z68
jsr fetch_pc_byte
sta Z69
lda Z68
ldx #$00
stx Z6a
beq .loop2
.loop1: lda Z68
asl
asl
sta Z68
.loop2: and #$c0
bne .fwd1
jsr Se075
jmp .fwd3
.fwd1: cmp #$40
bne .fwd2
jsr Se071
jmp .fwd3
.fwd2: cmp #$80
bne Ldf08
jsr Se089
.fwd3: ldx Z6a
lda acc
sta arg1,x
lda acc+1
sta arg1+1,x
inc argcnt
inx
inx
stx Z6a
cpx #$10
beq Ldf08
cpx #$08
bne .loop1
lda Z69
sta Z68
jmp .loop2
; 0OP instructions
op_b0_bf:
and #$0f
tay
lda tab_0op_lo,y
sta .jsr+1
lda tab_0op_hi,y
sta .jsr+2
.jsr: jsr $ffff ; self-modifying code
jmp main_loop
int_err_02:
lda #$02
jmp int_error
op_80_af:
and #$30
bne .fwd2
; 1OP
fetch_pc_byte_inline
jmp .fwd3
.fwd2: and #$20
bne .fwd5
.fwd3: sta arg1+1
fetch_pc_byte_inline
sta arg1
inc argcnt
jmp dispatch_1op
.fwd5: jsr Se089
jsr Se066
dispatch_1op:
lda opcode
and #$0f
tay
lda tab_1op_lo,y
sta Ldfea+1
lda tab_1op_hi,y
sta Ldfea+2
Ldfea: jsr $ffff ; self-modifying code
jmp main_loop
; unreferenced - was used in e.g. ZIP interpreter F
int_err_03:
lda #$03
jmp int_error
op_00_7f:
; check type of first arg
and #$40
bne .fwd1
; first arg is immediate byte
sta arg1+1 ; A contains zero
fetch_pc_byte_inline
sta arg1
inc argcnt
jmp .fwd2
.fwd1:
; first arg is a variable
jsr Se089
jsr Se066 ; store acc in arg1 and increment argcnt
.fwd2:
; check type of second arg
lda opcode
and #$20
bne .fwd3
; second arg is immediate byte
sta arg2+1 ; A contains zero
fetch_pc_byte_inline
sta arg2
jmp .fwd4
.fwd3:
; second arg is variable
jsr Se089
lda acc
sta arg2
lda acc+1
sta arg2+1
.fwd4: inc argcnt
dispatch_2op_tab:
lda opcode
and #$1f
tay
lda tab_2op_lo,y
sta .jsr+1
lda tab_2op_hi,y
sta .jsr+2
.jsr: jsr $ffff ; self-modifying code
jmp main_loop
int_err_04:
lda #$04
jmp int_error
Se066: lda acc
sta arg1
lda acc+1
sta arg1+1
inc argcnt
rts
Se071: lda #$00
beq Le078 ; always taken
Se075: jsr fetch_pc_byte
Le078: sta acc+1
jsr fetch_pc_byte
sta acc
rts
Se080: tax
bne Le08e
jsr pop_acc
jmp push_acc
Se089: jsr fetch_pc_byte
beq pop_acc
Le08e: cmp #$10
bcs Le09f
asl
tax
lda local_vars-2,x
sta acc
lda local_vars-1,x
sta acc+1
rts
Le09f: jsr Se14b
lda (Z6d),y
sta acc+1
iny
lda (Z6d),y
sta acc
rts
op_pop:
pop_acc:
lda stk_ptr
bne .fwd1
sta stk_ptr+1
.fwd1: dec stk_ptr
bne .fwd2
ora stk_ptr+1
beq int_err_05 ; data stack underflow
.fwd2: ldy stk_ptr
lda stk_ptr+1
beq .fwd3
lda D0e56,y
sta acc
tax
lda D1056,y
sta acc+1
rts
.fwd3: lda D0d56,y
sta acc
tax
lda D0f56,y
sta acc+1
rts
int_err_05:
lda #$05
jmp int_error
push_acc:
ldx acc
lda acc+1
; push word in A:X onto data stack
push_ax:
pha
ldy stk_ptr
lda stk_ptr+1
beq .fwd1
if iver==iver2a
tax ; wrong! how did this ever work at all?
else
txa
endif
sta D0e56,y
pla
sta D1056,y
jmp .fwd2
.fwd1: txa
sta D0d56,y
pla
sta D0f56,y
.fwd2: inc stk_ptr
bne .fwd3
lda stk_ptr
ora stk_ptr+1
bne int_err_06 ; data stack overflow
inc stk_ptr+1
.fwd3: rts
int_err_06:
lda #$06
jmp int_error
Le10d: tax
bne Le12d
lda stk_ptr
bne .fwd1
sta stk_ptr+1
.fwd1: dec stk_ptr
bne push_acc
ora stk_ptr+1
beq int_err_05
bne push_acc ; always taken
; store a zero result into variable (or stack) designated by next byte of program
store_result_zero:
lda #$00
ldx #$00
; store result in X:A into acc and variable (or stack) designated by next byte of program
store_result_xa:
sta acc
stx acc+1
; store result in acc into variable (or stack) designated by next byte of program
store_result:
jsr fetch_pc_byte
beq push_acc
Le12d: cmp #$10
bcs .fwd2
; store result in acc into local variable specified by A
asl
tax
lda acc
sta local_vars-2,x
lda acc+1
sta local_vars-1,x
rts
; store result in acc into global variable specified by A (offset by $10)
.fwd2: jsr Se14b
lda acc+1
sta (Z6d),y
iny
lda acc
sta (Z6d),y
rts
Se14b: sec
sbc #$10
ldy #$00
sty Z6e
asl
rol Z6e
clc
adc Z83
sta Z6d
lda Z6e
adc Z84
sta Z6e
Le160: rts
predicate_false:
jsr fetch_pc_byte
bpl Le172
Le166: and #$40
bne Le160
jmp fetch_pc_byte
predicate_true:
jsr fetch_pc_byte
bpl Le166
Le172: tax
and #$40
beq .fwd1
txa
and #$3f
sta acc
lda #$00
sta acc+1
beq .fwd3 ; always taken
.fwd1: txa
and #$3f
tax
and #$20
beq .fwd2
txa
ora #$e0
tax
.fwd2: stx acc+1
jsr fetch_pc_byte
sta acc
lda acc+1
bne Le1a7
.fwd3: lda acc
bne .fwd4
jmp op_rfalse
.fwd4: cmp #$01
bne Le1a7
jmp op_rtrue
Le1a7: lda acc
sec
sbc #$02
tax
lda acc+1
sbc #$00
sta Z6d
ldy #$00
sty Z6e
asl
rol Z6e
asl
rol Z6e
txa
adc pc
bcc .fwd5
inc Z6d
bne .fwd5
inc Z6e
.fwd5: sta pc
lda Z6d
ora Z6e
beq op_nop
lda Z6d
clc
adc pc+1
sta pc+1
lda Z6e
adc pc+2
and #$03
sta pc+2
jmp find_pc_page
op_nop: rts
Se1e3: lda arg1
sta acc
lda arg1+1
sta acc+1
rts
; unreferenced - see S1b1d in ZIP revision F
lda hdr_flags2+1
ora #$04
sta hdr_flags2+1
rts
; 0OP instructions (no operands), opcodes $b0..$bf
optab_start tab_0op,16
optab_ent op_rtrue
optab_ent op_rfalse
optab_ent op_print ; (literal string)
optab_ent op_print_ret ; (literal string)
optab_ent op_nop
optab_ent op_save
optab_ent op_restore
optab_ent op_restart
optab_ent op_ret_popped
optab_ent op_pop
optab_ent op_quit
optab_ent op_new_line
optab_ent op_show_status ; [nop, some games might mistakenly use]
optab_ent op_verify
optab_ent int_err_02 ; [illegal]
optab_ent int_err_02 ; [illegal]
; 1OP instructions (one operand), opcodes $80..$af
optab_start tab_1op,16
optab_ent op_jz
optab_ent op_get_sibling
optab_ent op_get_child
optab_ent op_get_parent
optab_ent op_get_prop_len ; get length of property (given addr)
optab_ent op_inc
optab_ent op_dec
optab_ent op_print_addr
optab_ent op_call_1s
optab_ent op_remove_obj
optab_ent op_print_obj
optab_ent op_ret ; with value
optab_ent op_jump
optab_ent op_print_paddr
optab_ent op_load
optab_ent op_not
; 2OP instructions (two operand), opcodes $20..$7f
; The 2OP table is also used for VAR instructions (0-4 operands),
; opcodes $c0..$df
optab_start tab_2op,32
optab_ent int_err_04 ; [illegal]
optab_ent op_je
optab_ent op_jl
optab_ent op_jg
optab_ent op_dec_chk
optab_ent op_inc_chk
optab_ent op_jin ; jump if object a is direct child of object b
optab_ent op_test ; (bitmap)
optab_ent op_or
optab_ent op_and
optab_ent op_test_attr
optab_ent op_set_attr
optab_ent op_clear_attr
optab_ent op_store
optab_ent op_insert_obj
optab_ent op_loadw
optab_ent op_loadb
optab_ent op_get_prop
optab_ent op_get_prop_addr
optab_ent op_get_next_prop
optab_ent op_add
optab_ent op_sub
optab_ent op_mul
optab_ent op_div
optab_ent op_mod
optab_ent op_call_2s
optab_ent int_err_04 ; [illegal]
optab_ent int_err_04 ; [illegal]
optab_ent int_err_04 ; [illegal]
optab_ent int_err_04 ; [illegal]
optab_ent int_err_04 ; [illegal]
optab_ent int_err_04 ; [illegal]
; VAR instructions (0-4 operands, 0-8 for call_vs2),
; opcodes $e0..$ff
optab_start tab_var,32
optab_ent op_call_vs ; (up to 3 args)
optab_ent op_storew
optab_ent op_storeb
optab_ent op_put_prop
optab_ent op_sread
optab_ent op_print_char
optab_ent op_print_num
optab_ent op_random
optab_ent op_push
optab_ent op_pull
optab_ent op_split_window
optab_ent op_set_window
optab_ent op_call_vs2 ; (up to 7 args)
optab_ent op_erase_window
optab_ent op_erase_line
optab_ent op_set_cursor
optab_ent op_get_cursor ; [nop]
optab_ent op_set_text_state
optab_ent op_buffer_mode
optab_ent op_output_stream
optab_ent op_input_stream ; [nop]
optab_ent op_sound_effect
optab_ent op_read_char
optab_ent op_scan_table
optab_ent int_err_01
optab_ent int_err_01
optab_ent int_err_01
optab_ent int_err_01
optab_ent int_err_01
optab_ent int_err_01
optab_ent int_err_01
optab_ent int_err_01
op_rtrue:
ldx #$01
Le2b7: lda #$00
Le2b9: stx arg1
sta arg1+1
jmp op_ret
op_rfalse:
ldx #$00
beq Le2b7
op_print:
ldx #$05
.loop1: lda pc,x
sta aux_ptr,x
dex
bpl .loop1
jsr Sef7e
ldx #$05
.loop2: lda aux_ptr,x
sta pc,x
dex
bpl .loop2
rts
op_print_ret:
jsr op_print
jsr op_new_line
jmp op_rtrue
op_ret_popped:
jsr pop_acc
jmp Le2b9
op_verify:
jsr op_new_line
ldx #$03
lda #$00
if iver>=iver2b
sta Zd7
endif
.loop1: sta Z71,x
sta aux_ptr,x
dex
bpl .loop1
lda #$40
sta aux_ptr
lda hdr_length
sta Z6e
lda hdr_length+1
asl
rol Z6e
rol Z71
asl
sta Z6d
rol Z6e
rol Z71
lda #$00
sta disk_block_num
sta disk_block_num+1
jmp .fwd1
.loop2: lda aux_ptr
bne .fwd2
.fwd1: lda #$09
sta Zb3
lda #$00
sta Ded07
jsr Sd51d
if iver>=iver2b
lda Zd7
bne .fwd2
lda Ze7
cmp #$02
bne .fwd2
prt_msg_alt be_patient
inc Zd7
endif
.fwd2: ldy aux_ptr
lda rwts_data_buf,y
inc aux_ptr
bne .fwd3
inc aux_ptr+1
bne .fwd3
inc aux_ptr+2
.fwd3: clc
adc Z73
sta Z73
bcc .fwd4
inc Z74
.fwd4: lda aux_ptr
cmp Z6d
bne .loop2
lda aux_ptr+1
cmp Z6e
bne .loop2
lda aux_ptr+2
cmp Z71
bne .loop2
lda hdr_checksum+1
cmp Z73
bne .rtn_f
lda hdr_checksum
cmp Z74
bne .rtn_f
jmp predicate_true
.rtn_f: jmp predicate_false
if iver>=iver2b
msg_be_patient:
fcb char_cr
text_str "Please be patient, this takes a while"
fcb char_cr
msg_len_be_patient equ *-msg_be_patient
endif
op_jz: lda arg1
ora arg1+1
beq Le394
Le36c: jmp predicate_false
op_get_sibling:
lda arg1
ldx arg1+1
jsr setup_object
ldy #$08
bne Le383 ; always taken
op_get_child:
lda arg1
ldx arg1+1
jsr setup_object
ldy #$0a
Le383: lda (Z6d),y
tax
iny
lda (Z6d),y
jsr store_result_xa
lda acc
bne Le394
lda acc+1
beq Le36c
Le394: jmp predicate_true
op_get_parent:
lda arg1
ldx arg1+1
jsr setup_object
ldy #$06
lda (Z6d),y
tax
iny
lda (Z6d),y
jmp store_result_xa
op_get_prop_len:
lda arg1+1
clc
adc Z81
sta Z6e
lda arg1
sec
sbc #$01
sta Z6d
bcs .fwd1
dec Z6e
.fwd1: ldy #$00
lda (Z6d),y
bmi .fwd3
and #$40
beq .fwd2
lda #$02
bne .fwd4
.fwd2: lda #$01
bne .fwd4
.fwd3: and #$3f
.fwd4: ldx #$00
jmp store_result_xa
op_inc: lda arg1
jsr Se080
inc acc
bne .fwd1
inc acc+1
.fwd1: jmp Le3f4
op_dec: lda arg1
jsr Se080
lda acc
sec
sbc #$01
sta acc
lda acc+1
sbc #$00
sta acc+1
Le3f4: lda arg1
jmp Le10d
op_print_addr:
lda arg1
sta Z6d
lda arg1+1
sta Z6e
jsr Secf8
jmp Sef7e
op_remove_obj:
lda arg1
ldx arg1+1
jsr setup_object
lda Z6d
sta Z6f
lda Z6e
sta Z70
ldy #$07
lda (Z6d),y
sta Z71
dey
lda (Z6d),y
tax
lda Z71
ora (Z6d),y
beq .rtn
lda Z71
jsr setup_object
ldy #$0a
lda (Z6d),y
tax
iny
lda (Z6d),y
cmp arg1
bne .loop1
cpx arg1+1
bne .loop1
ldy #$08
lda (Z6f),y
iny
iny
sta (Z6d),y
dey
lda (Z6f),y
iny
iny
sta (Z6d),y
bne .fwd1
.loop1: jsr setup_object
ldy #$08
lda (Z6d),y
tax
iny
lda (Z6d),y
cmp arg1
bne .loop1
cpx arg1+1
bne .loop1
ldy #$08
lda (Z6f),y
sta (Z6d),y
iny
lda (Z6f),y
sta (Z6d),y
.fwd1: lda #$00
ldy #$06
sta (Z6f),y
iny
sta (Z6f),y
iny
sta (Z6f),y
iny
sta (Z6f),y
.rtn: rts
op_print_obj:
lda arg1
ldx arg1+1
jsr setup_object
ldy #$0c
lda (Z6d),y
tax
iny
lda (Z6d),y
sta Z6d
stx Z6e
inc Z6d
bne .fwd1
inc Z6e
.fwd1: jsr Secf8
jmp Sef7e
op_ret: lda Zed
sta stk_ptr
lda Zed+1
sta stk_ptr+1
jsr pop_acc
stx Z6e
txa
beq .fwd1
dex
txa
asl
sta Z6d
.loop1: jsr pop_acc
ldy Z6d
sta local_vars+1,y
txa
sta local_vars,y
dec Z6d
dec Z6d
dec Z6e
bne .loop1
.fwd1: jsr pop_acc
stx pc+1
sta pc+2
jsr pop_acc
sta pc
jsr pop_acc
stx Zed
sta Zed+1
jsr find_pc_page
jsr Se1e3
Le4db: jmp store_result ; self-modifying code - jmp target changed by code at Sf5f9 and Lf67c
op_jump:
jsr Se1e3
jmp Le1a7
op_print_paddr:
lda arg1
sta Z6d
lda arg1+1
sta Z6e
jsr Sef65
jmp Sef7e
op_load:
lda arg1
jsr Se080
jmp store_result
op_not: lda arg1
eor #$ff
tax
lda arg1+1
eor #$ff
; fall into store_result_ax
; store result in A:X into variable (or stack) designated by next byte of program
store_result_ax:
stx acc
sta acc+1
jmp store_result
op_jl: jsr Se1e3
jmp Le513
op_dec_chk:
jsr op_dec
Le513: lda arg2
sta Z6d
lda arg2+1
sta Z6e
jmp Le53c
op_jg: lda arg1
sta Z6d
lda arg1+1
sta Z6e
jmp Le534
op_inc_chk:
jsr op_inc
lda acc
sta Z6d
lda acc+1
sta Z6e
Le534: lda arg2
sta acc
lda arg2+1
sta acc+1
Le53c: lda Z6e
eor acc+1
bpl .fwd1
lda Z6e
cmp acc+1
bcc Le583
jmp predicate_false
.fwd1: lda acc+1
cmp Z6e
bne .fwd2
lda acc
cmp Z6d
.fwd2: bcc Le583
jmp predicate_false
; is object ARG1 in (a direct child of) object ARG2?
op_jin: lda arg1
ldx arg1+1
jsr setup_object
ldy #$06
lda (Z6d),y
cmp arg2+1
bne Le570
iny
lda (Z6d),y
cmp arg2
beq Le583
Le570: jmp predicate_false
op_test:
lda arg2
and arg1
cmp arg2
bne Le570
lda arg2+1
and arg1+1
cmp arg2+1
bne Le570
Le583: jmp predicate_true
op_or: lda arg1
ora arg2
tax
lda arg1+1
ora arg2+1
jmp store_result_ax
op_and: lda arg1
and arg2
tax
lda arg1+1
and arg2+1
jmp store_result_ax
op_test_attr:
jsr setup_attribute
lda Z72
and Z70
sta Z72
lda Z71
and Z6f
ora Z72
bne Le583
jmp predicate_false
op_set_attr:
jsr setup_attribute
ldy #$00
lda Z72
ora Z70
sta (Z6d),y
iny
lda Z71
ora Z6f
sta (Z6d),y
rts
op_clear_attr:
jsr setup_attribute
ldy #$00
lda Z70
eor #$ff
and Z72
sta (Z6d),y
iny
lda Z6f
eor #$ff
and Z71
sta (Z6d),y
rts
op_store:
lda arg2
sta acc
lda arg2+1
sta acc+1
lda arg1
jmp Le10d
op_insert_obj:
jsr op_remove_obj
lda arg1
ldx arg1+1
jsr setup_object
lda Z6d
sta Z6f
lda Z6e
sta Z70
lda arg2+1
ldy #$06
sta (Z6d),y
tax
lda arg2
iny
sta (Z6d),y
jsr setup_object
ldy #$0a
lda (Z6d),y
sta Z72
lda arg1+1
sta (Z6d),y
iny
lda (Z6d),y
tax
lda arg1
sta (Z6d),y
txa
ora Z72
beq .rtn
txa
ldy #$09
sta (Z6f),y
dey
lda Z72
sta (Z6f),y
.rtn: rts
op_loadw:
jsr Se643
jsr fetch_aux_byte
Le632: sta acc+1
jsr fetch_aux_byte
sta acc
jmp store_result
op_loadb:
jsr Se647
lda #$00
beq Le632
Se643: asl arg2
rol arg2+1
Se647: lda arg2
clc
adc arg1
sta aux_ptr
lda arg2+1
adc arg1+1
sta aux_ptr+1
lda #$00
adc #$00
sta aux_ptr+2
jmp find_aux_page
op_get_prop:
jsr Sf1e3
.loop1: jsr Sf201
cmp arg2
beq .fwd2
bcc .fwd1
jsr Sf230
jmp .loop1
.fwd1: lda arg2
sec
sbc #$01
asl
tay
lda (Z89),y
sta acc+1
iny
lda (Z89),y
sta acc
jmp store_result
.fwd2: jsr Sf206
iny
cmp #$01
beq .fwd3
cmp #$02
beq .fwd4
lda #$07
jmp int_error
.fwd3: lda (Z6d),y
ldx #$00
beq .fwd5 ; always taken
.fwd4: lda (Z6d),y
tax
iny
lda (Z6d),y
.fwd5: sta acc
stx acc+1
jmp store_result
op_get_prop_addr:
if iver==iver2a
jsr Sf1e3
.loop1: jsr Sf201
cmp arg2
beq .fwd1
bcc Le6ce
jsr Sf230
jmp .loop1
.fwd1: jsr Sf206
else
lda arg1
ldx arg1+1
jsr setup_object
ldy #$0c
lda (Z6d),Y
clc
adc Z81
tax
iny
lda (Z6d),Y
sta Z6d
stx Z6e
ldy #$00
lda (Z6d),Y
asl
tay
iny
.loop2b:
lda (Z6d),Y
and #$3f
cmp arg2
beq .fwd8b
bcs .fwd2b
jmp Le6ce
.fwd2b: lda (Z6d),Y
and #$80
beq .fwd3b
iny
lda (Z6d),Y
and #$3f
jmp .fwd5b
.fwd3b: lda (Z6d),Y
and #$40
beq .fwd4b
lda #$02
jmp .fwd5b
.fwd4b: lda #$01
.fwd5b: tax
.loop3b:
iny
bne .fwd6b
inc Z6e
.fwd6b: dex
bne .loop3b
iny
tya
clc
adc Z6d
sta Z6d
bcc .fwd7b
inc Z6e
.fwd7b: ldy #$00
jmp .loop2b
.fwd8b: lda (Z6d),Y
and #$80
beq .fwd9b
iny
lda (Z6d),Y
and #$3f
jmp .fwd11b
.fwd9b: lda (Z6d),Y
and #$40
beq .fwd10b
lda #$02
jmp .fwd11b
.fwd10b:
lda #$01
.fwd11b:
endif
iny
tya
clc
adc Z6d
sta acc
lda Z6e
adc #$00
sec
sbc Z81
sta acc+1
jmp store_result
Le6ce: jmp store_result_zero
op_get_next_prop:
jsr Sf1e3
lda arg2
beq .fwd2
.loop1: jsr Sf201
cmp arg2
beq .fwd1
bcc Le6ce
jsr Sf230
jmp .loop1
.fwd1: jsr Sf21e
.fwd2: jsr Sf201
ldx #$00
jmp store_result_xa
op_add:
lda arg1
clc
adc arg2
tax
lda arg1+1
adc arg2+1
jmp store_result_ax
op_sub:
lda arg1
sec
sbc arg2
tax
lda arg1+1
sbc arg2+1
jmp store_result_ax
op_mul: jsr Se7c6
.loop1: ror Zcc
ror Zcb
ror arg2+1
ror arg2
bcc .fwd1
lda arg1
clc
adc Zcb
sta Zcb
lda arg1+1
adc Zcc
sta Zcc
.fwd1: dex
bpl .loop1
ldx arg2
lda arg2+1
jmp store_result_ax
op_div:
jsr divide
ldx Zc7
lda Zc7+1
jmp store_result_ax
op_mod:
jsr divide
ldx Zc9
lda Zc9+1
jmp store_result_ax
; On exit
; quotient in Zc7
; remainder in Zc9
divide: lda arg1+1
sta Zce
eor arg2+1
sta Zcd
lda arg1
sta Zc7
lda arg1+1
sta Zc7+1
bpl .fwd1
jsr Se782
.fwd1: lda arg2
sta Zc9
lda arg2+1
sta Zc9+1
bpl .fwd2
jsr Se774
.fwd2: jsr Se790
lda Zcd
bpl .fwd3
jsr Se782
.fwd3: lda Zce
bpl Le781
Se774: lda #$00
sec
sbc Zc9
sta Zc9
lda #$00
sbc Zc9+1
sta Zc9+1
Le781: rts
Se782: lda #$00
sec
sbc Zc7
sta Zc7
lda #$00
sbc Zc7+1
sta Zc7+1
rts
Se790: lda Zc9
ora Zc9+1
beq int_err_08
jsr Se7c6
.loop1: rol Zc7
rol Zc7+1
rol Zcb
rol Zcc
lda Zcb
sec
sbc Zc9
tay
lda Zcc
sbc Zc9+1
bcc .fwd1
sty Zcb
sta Zcc
.fwd1: dex
bne .loop1
rol Zc7
rol Zc7+1
lda Zcb
sta Zc9
lda Zcc
sta Zc9+1
rts
int_err_08:
lda #$08
jmp int_error
Se7c6: ldx #$10
lda #$00
sta Zcb
sta Zcc
clc
rts
op_je: dec argcnt
bne .fwd1
lda #$09
jmp int_error
.fwd1: lda arg1
ldx arg1+1
cmp arg2
bne .fwd2
cpx arg2+1
beq .rtn_t
.fwd2: dec argcnt
beq .rtn_f
cmp arg3
bne .fwd3
cpx arg3+1
beq .rtn_t
.fwd3: dec argcnt
beq .rtn_f
cmp arg4
bne .rtn_f
cpx arg4+1
bne .rtn_f
.rtn_t: jmp predicate_true
.rtn_f: jmp predicate_false
; call instructions that store a result
op_call_1s
op_call_2s:
op_call_vs:
op_call_vs2:
lda arg1
ora arg1+1
bne .fwd1
ldx #$00
jmp store_result_xa
.fwd1: ldx Zed
lda Zed+1
jsr push_ax
lda pc
jsr push_ax
ldx pc+1
lda pc+2
jsr push_ax
lda #$00
asl arg1
rol arg1+1
rol
sta pc+2
asl arg1
rol arg1+1
rol pc+2
lda arg1+1
sta pc+1
lda arg1
sta pc
jsr find_pc_page
jsr fetch_pc_byte
sta Z6f
sta Z70
beq .fwd2
lda #$00
sta Z6d
.loop1: ldy Z6d
ldx local_vars,y
lda local_vars+1,y
jsr push_ax
jsr fetch_pc_byte
sta Z6e
jsr fetch_pc_byte
ldy Z6d
sta local_vars,y
lda Z6e
sta local_vars+1,y
iny
iny
sty Z6d
dec Z6f
bne .loop1
; if present, copy arg2 through arg8 to the first local variables
.fwd2: dec argcnt
beq .fwd3
lda arg2
sta local_vars
lda arg2+1
sta local_vars+1
dec argcnt
beq .fwd3
lda arg3
sta local_vars+2
lda arg3+1
sta local_vars+3
dec argcnt
beq .fwd3
lda arg4
sta local_vars+4
lda arg4+1
sta local_vars+5
dec argcnt
beq .fwd3
lda arg5
sta local_vars+6
lda arg5+1
sta local_vars+7
dec argcnt
beq .fwd3
lda arg6
sta local_vars+8
lda arg6+1
sta local_vars+9
dec argcnt
beq .fwd3
lda arg7
sta local_vars+10
lda arg7+1
sta local_vars+11
dec argcnt
beq .fwd3
lda arg8
sta local_vars+12
lda arg8+1
sta local_vars+13
.fwd3: ldx Z70
txa
jsr push_ax
lda stk_ptr+1
sta Zed+1
lda stk_ptr
sta Zed
rts
op_storew:
asl arg2
rol arg2+1
jsr Se8f4
lda arg3+1
sta (Z6d),y
iny
bne Le8ef
op_storeb:
jsr Se8f4
Le8ef: lda arg3
sta (Z6d),y
rts
Se8f4: lda arg2
clc
adc arg1
sta Z6d
lda arg2+1
adc arg1+1
clc
adc Z81
sta Z6e
ldy #$00
rts
op_put_prop:
jsr Sf1e3
.loop1: jsr Sf201
cmp arg2
beq .fwd1
bcc int_err_0a
jsr Sf230
jmp .loop1
.fwd1: jsr Sf206
iny
cmp #$01
beq .fwd2
cmp #$02
bne int_err_0b
lda arg3+1
sta (Z6d),y
iny
.fwd2: lda arg3
sta (Z6d),y
rts
int_err_0a:
lda #$0a
jmp int_error
int_err_0b:
lda #$0b
jmp int_error
op_print_char:
lda arg1
jmp Sf311
op_print_num:
lda arg1
sta Zc7
lda arg1+1
sta Zc7+1
lda Zc7+1
bpl .fwd1
lda #$2d
jsr Sf311
jsr Se782
.fwd1: lda #$00
sta Zcf
.loop1: lda Zc7
ora Zc7+1
beq .fwd2
lda #$0a
sta Zc9
lda #$00
sta Zc9+1
jsr Se790
lda Zc9
pha
inc Zcf
bne .loop1
.fwd2: lda Zcf
bne .loop2
lda #$30
jmp Sf311
.loop2: pla
clc
adc #$30
jsr Sf311
dec Zcf
bne .loop2
rts
op_random:
lda arg1
ora arg1+1
bne .fwd1
sta Ze8
sta Ze8+1
jmp store_result_zero
.fwd1: lda Ze8
ora Ze8+1
bne .fwd3
lda arg1+1
bpl .fwd2
eor #$ff
sta Ze8+1
lda arg1
eor #$ff
sta Ze8
inc Ze8
lda #$00
sta Zc0
sta Zc0+1
beq .fwd3 ; always taken
.fwd2: lda arg1
sta arg2
lda arg1+1
sta arg2+1
jsr Sf2ff
stx arg1
and #$7f
sta arg1+1
jsr divide
lda Zc9
clc
adc #$01
sta acc
lda Zc9+1
adc #$00
sta acc+1
jmp store_result
.fwd3:
if iver>=iver2b
lda arg1
sta Ze8
lda arg1+1
sta Ze8+1
endif
lda Zc0+1
cmp Ze8+1
bcc .fwd4
lda Zc0
cmp Ze8
bcc .fwd4
beq .fwd4
lda #$01
sta Zc0
lda #$00
sta Zc0+1
.fwd4: lda Zc0
sta acc
lda Zc0+1
sta acc+1
inc Zc0
bne .fwd5
inc Zc0+1
.fwd5: jmp store_result
op_push:
ldx arg1
lda arg1+1
jmp push_ax
op_pull:
jsr pop_acc
lda arg1
jmp Le10d
op_scan_table:
lda arg2
sta aux_ptr
lda arg2+1
sta aux_ptr+1
lda #$00
sta aux_ptr+2
jsr find_aux_page
.loop1: jsr fetch_aux_byte
sta Z6e
jsr fetch_aux_byte
cmp arg1
bne .fwd1
lda Z6e
cmp arg1+1
beq .fwd2
.fwd1: dec arg3
bne .loop1
lda arg3+1
beq .fwd4
dec arg3+1
jmp .loop1
.fwd2: sec
lda aux_ptr
if iver<=iver2c
sbc #$01
else
sbc #$02
endif
sta aux_ptr
bcs .fwd3
dec aux_ptr+1
.fwd3: sta acc
lda aux_ptr+1
sta acc+1
jsr store_result
jmp predicate_true
.fwd4: lda #$00
sta acc
sta acc+1
jsr store_result
jmp predicate_false
op_sread:
lda arg1+1
clc
adc Z81
sta Zc4
lda arg1
sta Zc3
lda arg2+1
clc
adc Z81
sta Zc6
lda arg2
sta Zc5
ldy #$00
lda (Zc3),y
cmp #$4f
bcc .fwd1
lda #$4e
.fwd1: sta Zbe
jsr Sdafe
sta Z9f
lda #$00
sta Za0
ldy #$01
sta (Zc5),y
sty Z9d
iny
sty Z9e
.loop1: ldy #$00
lda (Zc5),y
beq .fwd2
if iver==iver2a
cmp #$3c
else
cmp #$3b
endif
bcc .fwd3
.fwd2:
if iver==iver2a
lda #$3b
else
lda #$3a
endif
sta (Zc5),y
.fwd3: iny
cmp (Zc5),y
bcc .rtn
lda Z9f
ora Za0
bne .fwd4
.rtn: rts
.fwd4: lda Za0
cmp #$09
bcc .fwd5
jsr Seb3e
.fwd5: lda Za0
bne .fwd6
ldx #$08
.loop2: sta Z8b,x
dex
bpl .loop2
jsr Seb30
lda Z9d
ldy #$03
sta (Za1),y
tay
lda (Zc3),y
jsr Seb6b
bcs .fwd7
jsr Seb5f
bcc .fwd6
inc Z9d
dec Z9f
jmp .loop1
.fwd6: lda Z9f
beq .fwd8
ldy Z9d
lda (Zc3),y
jsr Seb5a
bcs .fwd8
ldx Za0
sta Z8b,x
dec Z9f
inc Za0
inc Z9d
jmp .loop1
.fwd7: sta Z8b
dec Z9f
inc Za0
inc Z9d
.fwd8: lda Za0
beq .loop1
jsr Seb30
lda Za0
ldy #$02
sta (Za1),y
jsr Sf0ac
jsr Seb96
ldy #$01
lda (Zc5),y
clc
adc #$01
sta (Zc5),y
jsr Seb30
ldy #$00
sty Za0
lda acc+1
sta (Za1),y
iny
lda acc
sta (Za1),y
lda Z9e
clc
adc #$04
sta Z9e
jmp .loop1
Seb30: lda Zc5
clc
adc Z9e
sta Za1
lda Zc6
adc #$00
sta Za2
rts
Seb3e: lda Z9f
beq .rtn
ldy Z9d
lda (Zc3),y
jsr Seb5a
bcs .rtn
dec Z9f
inc Za0
inc Z9d
bne Seb3e
.rtn: rts
Deb54: fcb $21,$3f,$2c,$2e,$0d,$20 ; "!?,.. "
Seb5a: jsr Seb6b
bcs Leb94
Seb5f: ldx #$05
.loop1: cmp Deb54,x
beq Leb94
dex
bpl .loop1
clc
rts
Seb6b: sta Zd7
lda hdr_vocab
ldy hdr_vocab+1
sta aux_ptr+1
sty aux_ptr
lda #$00
sta aux_ptr+2
jsr find_aux_page
jsr fetch_aux_byte
sta Z6f
.loop1: jsr fetch_aux_byte
cmp Zd7
beq .fwd1
dec Z6f
bne .loop1
lda Zd7
clc
rts
.fwd1: lda Zd7
Leb94: sec
rts
Seb96: lda hdr_vocab
ldy hdr_vocab+1
sta aux_ptr+1
sty aux_ptr
lda #$00
sta aux_ptr+2
jsr find_aux_page
jsr fetch_aux_byte
clc
adc aux_ptr
sta aux_ptr
bcc .fwd1
inc aux_ptr+1
.fwd1: jsr find_aux_page
jsr fetch_aux_byte
sta Za5
sta Z6d
lda #$00
sta Z6e
sta Z6f
jsr fetch_aux_byte
sta Za4
jsr fetch_aux_byte
sta Za3
lda #$00
sta Zf4
sta Zf5
sta Zf6
ldx Za5
.loop1: clc
lda Zf4
adc Za3
sta Zf4
lda Zf5
adc Za4
sta Zf5
lda Zf6
adc #$00
sta Zf6
dex
bne .loop1
clc
lda Zf4
adc aux_ptr
sta Zf4
lda Zf5
adc aux_ptr+1
sta Zf5
lda Zf6
adc aux_ptr+2
sta Zf6
if iver>=iver2b
lda Zf4
sec
sbc Za5
sta Zf4
lda Zf5
sbc #$00
sta Zf5
endif
lsr Za4
ror Za3
.loop2: asl Z6d
rol Z6e
rol Z6f
lsr Za4
ror Za3
bne .loop2
clc
lda aux_ptr
adc Z6d
sta aux_ptr
lda aux_ptr+1
adc Z6e
sta aux_ptr+1
lda aux_ptr+2
adc Z6f
sta aux_ptr+2
sec
lda aux_ptr
sbc Za5
sta aux_ptr
bcs .loop3
lda aux_ptr+1
sec
sbc #$01
sta aux_ptr+1
bcs .loop3
lda aux_ptr+2
sbc #$00
sta aux_ptr+2
.loop3: lsr Z6f
ror Z6e
ror Z6d
lda aux_ptr
sta Z70
lda aux_ptr+1
sta Z71
lda aux_ptr+2
sta Z72
jsr find_aux_page
jsr fetch_aux_byte
cmp Z94
bcc .fwd2
bne .fwd6
jsr fetch_aux_byte
cmp Z95
bcc .fwd2
bne .fwd6
jsr fetch_aux_byte
cmp Z96
bcc .fwd2
bne .fwd6
jsr fetch_aux_byte
cmp Z97
bcc .fwd2
bne .fwd6
jsr fetch_aux_byte
cmp Z98
bcc .fwd2
bne .fwd6
jsr fetch_aux_byte
cmp Z99
beq .fwd10
bcs .fwd6
.fwd2: lda Z70
clc
adc Z6d
sta aux_ptr
lda Z71
adc Z6e
if iver==iver2a
sta aux_ptr+1
lda Z72
adc Z6f
sta aux_ptr+2
lda aux_ptr+2
cmp Zf6
else
bcs .fwd5
sta aux_ptr+1
lda #$00
sta aux_ptr+2
lda aux_ptr+1
cmp Zf5
endif
beq .fwd3
bcs .fwd5
bcc .fwd7 ; always taken
.fwd3:
if iver==iver2a
lda aux_ptr+1
cmp Zf5
beq .fwd4
bcs .fwd5
bcc .fwd7 ; always taken
endif
.fwd4: lda aux_ptr
cmp Zf4
bcc .fwd7
beq .fwd7
.fwd5: lda Zf4
sta aux_ptr
lda Zf5
sta aux_ptr+1
lda Zf6
sta aux_ptr+2
jmp .fwd7
.fwd6: lda Z70
sec
sbc Z6d
sta aux_ptr
lda Z71
sbc Z6e
sta aux_ptr+1
lda Z72
sbc Z6f
sta aux_ptr+2
.fwd7: lda Z6f
bne .fwd8
lda Z6e
bne .fwd8
lda Z6d
cmp Za5
bcc .fwd9
.fwd8: jmp .loop3
.fwd9: lda #$00
sta acc
sta acc+1
rts
.fwd10: lda Z70
sta acc
lda Z71
sta acc+1
rts
Secf8: lda Z6d
sta aux_ptr
lda Z6e
sta aux_ptr+1
lda #$00
sta aux_ptr+2
jmp find_aux_page
Ded07: fcb $00
Ded08: fcb $00
Ded09: fcb $00
Ded0a: fcb $00
Ded0b: fcb $00
Ded0c: fcb $00
Ded0d: fcb $00
Ded0e: fcb $00
Ded0f: fcb $00
Ded10: fcb $00
Ded11: fcb $00
Ded12: fcb $00
Led13: lda hdr_length+1
sta Z6f
lda hdr_length
ldy #$05
.loop1: lsr
ror Z6f
dey
bpl .loop1
sta Z70
.loop2: jsr Sed72
bcc .rtn
jsr Sd51d
lda Ded07
cmp #$01
bne .loop2
lda Zb3
if iver==iver2a
cmp #$95
else
cmp #$96
endif
bne .loop2
lda #$00
sta Ded07
lda #$00
sta Ded08
.loop3: lda #$09
sta Zb3
jsr Sed72
bcc .rtn
jsr Sd51d
ldy #$09
lda Ded08
ldx #$01
sta rd_main_ram
jsr S086b
inc Ded08
lda Ded08
cmp #$4f
bcc .loop3
jsr home
lda #$02
sta cursrv
jmp Sd87e
.rtn: rts
Sed72: lda Z6f
sec
sbc #$01
sta Z6f
lda Z70
sbc #$00
sta Z70
rts
find_aux_page:
lda aux_ptr+2
bne .fwd2
lda aux_ptr+1
cmp #max_main_ram_pages
bcs .fwd1
adc #hdr_arch>>8
ldy #$00
beq .fwd3
.fwd1:
; FIXME - not sure how the $a5/$a6 is determined
if iver==iver2a
sbc #$a6
else
sbc #$a5
endif
ldy #$01
bne .fwd3
.fwd2: cmp #$01
bne .fwd4
lda aux_ptr+1
cmp #$3b
bcs .fwd4
; FIXME - not sure how the $5a/$5b is determined
if iver==iver2a
adc #$5a
else
adc #$5b
endif
ldy #$01
.fwd3: sty aux_phys_page+2
sta aux_phys_page+1
.rtn: rts
.fwd4: lda aux_ptr+2
ldy aux_ptr+1
jsr find_page
clc
; FIXME - not sure how the $95/$96 is determined
if iver==iver2a
adc #$95
else
adc #$96
endif
sta aux_phys_page+1
ldy #$01
sty aux_phys_page+2
lda Dee02
beq .rtn
jmp find_pc_page ; unnecessary, could just fall through
find_pc_page:
lda pc+2
bne .fwd2
lda pc+1
cmp #max_main_ram_pages
bcs .fwd1
adc #hdr_arch>>8
ldy #$00
beq .fwd3 ; always taken
.fwd1:
; FIXME - not sure how the $a5/$a6 is determined
if iver==iver2a
sbc #$a6
else
sbc #$a5
endif
ldy #$01
bne .fwd3 ; always taken
.fwd2: cmp #$01
bne .fwd4
lda pc+1
cmp #$3b
bcs .fwd4
; FIXME - not sure how the $5a/$5b is determined
if iver==iver2a
adc #$5a
else
adc #$5b
endif
ldy #$01
.fwd3: sty pc_phys_page+2
sta pc_phys_page+1
.rtn: rts
.fwd4: lda pc+2
ldy pc+1
jsr find_page
clc
; FIXME - not sure how the $95/$96 is determined
if iver==iver2a
adc #$95
else
adc #$96
endif
sta pc_phys_page+1
ldy #$01
sty pc_phys_page+2
lda Dee02
beq .rtn
jmp find_aux_page
Dee02: fcb $00
find_page:
sta Ded0a
sty Ded09
ldx #$00
stx Dee02
jsr Seed7
bcc .fwd1
ldx Ded0b
lda D0b56,x
sta Ded0b
tax
lda Ded0a
sta D0c56,x
lda Ded09
sta D0cd6,x
tay
txa
pha
lda Ded0a
jsr fetch_page
dec Dee02
pla
rts
.fwd1: sta Ded0c
cmp Ded0b
bne .fwd2
rts
.fwd2: ldy Ded0b
lda D0b56,y
sta Ded0f
lda Ded0c
jsr Seeb9
ldy Ded0b
lda Ded0c
jsr See93
lda Ded0c
sta Ded0b
rts
fetch_page:
cmp #$01
bcc .fwd2
bne .fwd1
cpy #$8a
bcc .fwd2
.fwd1: sta disk_block_num+1
sty disk_block_num
txa
clc
; FIXME - not sure how the $95/$96 is determined
if iver==iver2a
adc #$95
else
adc #$96
endif
sta Zb3
ldx #$01
stx Ded07
jmp Sd51d
.fwd2: tya
sec
sbc #$3b
pha
txa
clc
if iver==iver2a
adc #$95
else
adc #$96
endif
tay
sta rd_main_ram
ldx #$01
stx D086a
ldx #$00
pla
jmp S086b
See93: sta Ded11
sty Ded10
tax
tya
sta D0bd6,x
lda D0b56,y
sta Ded12
txa
ldx Ded12
sta D0bd6,x
txa
ldx Ded11
sta D0b56,x
lda Ded11
sta D0b56,y
rts
Seeb9: tax
lda D0b56,x
sta Ded0d
lda D0bd6,x
sta Ded0e
tax
lda Ded0d
sta D0b56,x
lda Ded0e
ldx Ded0d
sta D0bd6,x
rts
Seed7:
; FIXME - not sure how the $2a/$29 is determined
if iver==iver2a
ldx #$2a
else
ldx #$29
endif
.loop1: lda Ded0a
cmp D0c56,x
beq .fwd1
.loop2: dex
bpl .loop1
sec
rts
.fwd1: tya
cmp D0cd6,x
bne .loop2
txa
clc
rts
Seeef:
; FIXME - not sure how the $2a/$29 is determined
if iver==iver2a
ldx #$2a
else
ldx #$29
endif
stx Ded0b
lda #$ff
.loop1: sta D0c56,x
dex
bpl .loop1
ldx #$00
ldy #$01
.loop2: tya
sta D0bd6,x
inx
iny
; FIXME - not sure how the $2b/$2a is determined
if iver==iver2a
cpx #$2b
else
cpx #$2a
endif
bcc .loop2
lda #$00
dex
sta D0bd6,x
ldx #$00
ldy #$ff
if iver==iver2a
lda #$2a
else
lda #$29
endif
.loop3: sta D0b56,x
inx
iny
tya
if iver==iver2a
cpx #$2b
else
cpx #$2a
endif
bcc .loop3
jmp Led13
Sef23: pha
inc aux_ptr+1
bne .fwd1
inc aux_ptr+2
.fwd1: jsr find_aux_page
pla
rts
advance_pc_page:
pha
inc pc+1
bne .fwd1
inc pc+2
.fwd1: jsr find_pc_page
pla
rts
; Fetch one byte from the aux ptr and increment the aux ptr
; On exit:
; A = fetched byte
; Y = fetched byte
fetch_aux_byte:
ldy aux_phys_page+2
sta rd_main_ram,y ; indexed to get main or card
ldy aux_ptr
lda (aux_phys_page),y
sta rd_main_ram
inc aux_ptr
bne .fwd1
jsr Sef23
.fwd1: tay
rts
; Fetch one byte from the PC and increment the PC
; On exit:
; A = fetched byte
; Y = fetched byte
fetch_pc_byte:
fetch_pc_byte_inline
rts
Sef65: lda Z6d
asl
sta aux_ptr
lda Z6e
rol
sta aux_ptr+1
lda #$00
rol
sta aux_ptr+2
asl aux_ptr
rol aux_ptr+1
rol aux_ptr+2
jmp find_aux_page
Lef7d: rts
Sef7e: ldx #$00
stx Za6
stx Zaa
dex
stx Za7
.loop1: jsr Sf064
bcs Lef7d
sta Za8
tax
beq .fwd4
cmp #$04
bcc .fwd7
cmp #$06
bcc .fwd5
jsr Sf046
tax
bne .fwd1
lda #$5b
.loop2: clc
adc Za8
.loop3: jsr Sf311
jmp .loop1
.fwd1: cmp #$01
bne .fwd2
lda #$3b
bne .loop2 ; always taken
.fwd2: lda Za8
sec
sbc #$06
beq .fwd3
tax
lda Df195,x
jmp .loop3
.fwd3: jsr Sf064
asl
asl
asl
asl
asl
sta Za8
jsr Sf064
ora Za8
jmp .loop3
.fwd4: lda #$20
bne .loop3 ; always taken
.fwd5: sec
sbc #$03
tay
jsr Sf046
bne .fwd6
sty Za7
jmp .loop1
.fwd6: sty Za6
cmp Za6
beq .loop1
lda #$00
sta Za6
beq .loop1 ; always taken
.fwd7: sec
sbc #$01
asl
asl
asl
asl
asl
asl
sta Za9
jsr Sf064
asl
clc
adc Za9
tay
lda (Z87),y
sta Z6e
iny
lda (Z87),y
sta Z6d
lda aux_ptr+2
pha
lda aux_ptr+1
pha
lda aux_ptr
pha
lda Za6
pha
lda Zaa
pha
lda Zac
pha
lda Zab
pha
jsr Sf052
jsr Sef7e
pla
sta Zab
pla
sta Zac
pla
sta Zaa
pla
sta Za6
pla
sta aux_ptr
pla
sta aux_ptr+1
pla
sta aux_ptr+2
ldx #$ff
stx Za7
jsr find_aux_page
jmp .loop1
Sf046: lda Za7
bpl .fwd1
lda Za6
rts
.fwd1: ldy #$ff
sty Za7
rts
Sf052: lda Z6d
asl
sta aux_ptr
lda Z6e
rol
sta aux_ptr+1
lda #$00
rol
sta aux_ptr+2
jmp find_aux_page
Sf064: lda Zaa
bpl .fwd1
sec
rts
.fwd1: bne .fwd2
inc Zaa
jsr fetch_aux_byte
sta Zac
jsr fetch_aux_byte
sta Zab
lda Zac
lsr
lsr
jmp .fwd5
.fwd2: sec
sbc #$01
bne .fwd3
lda #$02
sta Zaa
lda Zab
sta Z6d
lda Zac
asl Z6d
rol
asl Z6d
rol
asl Z6d
rol
jmp .fwd5
.fwd3: lda #$00
sta Zaa
lda Zac
bpl .fwd4
lda #$ff
sta Zaa
.fwd4: lda Zab
.fwd5: and #$1f
clc
rts
Sf0ac: lda #$05
ldx #$08
.loop1: sta Z94,x
dex
bpl .loop1
lda #$09
sta Zad
lda #$00
sta Zae
sta Zaf
.loop2: ldx Zae
inc Zae
lda Z8b,x
sta Za8
bne .fwd1
lda #$05
bne .loop3 ; always taken
.fwd1: lda Za8
jsr get_letter_case
beq .fwd3
clc
adc #$03
ldx Zaf
sta Z94,x
inc Zaf
dec Zad
bne .fwd2
jmp Lf15c
.fwd2: lda Za8
jsr get_letter_case
cmp #$02
beq .fwd4
lda Za8
sec
sbc #$3b
bpl .loop3
.fwd3: lda Za8
sec
sbc #$5b
.loop3: ldx Zaf
sta Z94,x
inc Zaf
dec Zad
bne .loop2
jmp Lf15c
.fwd4: lda Za8
jsr Sf133
bne .loop3
lda #$06
ldx Zaf
sta Z94,x
inc Zaf
dec Zad
beq Lf15c
lda Za8
lsr
lsr
lsr
lsr
lsr
and #$03
ldx Zaf
sta Z94,x
inc Zaf
dec Zad
beq Lf15c
lda Za8
and #$1f
jmp .loop3
Sf133: ldx #$19
.loop1: cmp Df195,x
beq .fwd1
dex
bne .loop1
rts
.fwd1: txa
clc
adc #$06
rts
; On entry:
; A = charcter
; On return:
; A = $00 for lower case alpha
; $01 for upper case alpha
; $02 for non-alpha
get_letter_case:
cmp #'a'
bcc .fwd1
cmp #'z'+1
bcs .fwd1
lda #$00
rts
.fwd1: cmp #'A'
bcc .fwd2
cmp #'Z'+1
bcs .fwd2
lda #$01
rts
.fwd2: lda #$02
rts
Lf15c: lda Z95
asl
asl
asl
asl
rol Z94
asl
rol Z94
ora Z96
sta Z95
lda Z98
asl
asl
asl
asl
rol Z97
asl
rol Z97
ora Z99
tax
lda Z97
sta Z96
stx Z97
lda Z9b
asl
asl
asl
asl
rol Z9a
asl
rol Z9a
ora Z9c
sta Z99
lda Z9a
ora #$80
sta Z98
rts
Df195: fcb $00,char_cr
fcb "0123456789"
fcb ".,!?_#'"
fcb $22 ; double quote
fcb "/"
fcb $5c ; backslash
fcb "-:()"
setup_object:
stx Z6e
asl
sta Z6d
rol Z6e
ldx Z6e
asl
rol Z6e
asl
rol Z6e
asl
rol Z6e
sec
sbc Z6d
sta Z6d
lda Z6e
stx Z6e
sbc Z6e
sta Z6e
lda Z6d
clc
adc #$70
bcc .fwd1
inc Z6e
.fwd1: clc
adc Z89
sta Z6d
lda Z6e
adc Z8a
sta Z6e
rts
Sf1e3: lda arg1
ldx arg1+1
jsr setup_object
ldy #$0c
lda (Z6d),y
clc
adc Z81
tax
iny
lda (Z6d),y
sta Z6d
stx Z6e
ldy #$00
lda (Z6d),y
asl
tay
iny
rts
Sf201: lda (Z6d),y
and #$3f
rts
Sf206: lda (Z6d),y
and #$80
beq .fwd1
iny
lda (Z6d),y
and #$3f
rts
.fwd1: lda (Z6d),y
and #$40
beq .fwd2
lda #$02
rts
.fwd2: lda #$01
rts
Sf21e: jsr Sf206
tax
.loop1: iny
bne .fwd1
inc Z6d
bne .fwd1
inc Z6e
.fwd1: dex
bne .loop1
iny
rts
Sf230: jsr Sf21e
tya
clc
adc Z6d
sta Z6d
bcc .fwd1
inc Z6e
.fwd1: ldy #$00
rts
setup_attribute:
lda arg1
ldx arg1+1
jsr setup_object
lda arg2
cmp #$10
bcc .fwd3
sbc #$10
tax
cmp #$10
bcc .fwd1
sbc #$10
tax
lda Z6d
clc
adc #$04
sta Z6d
bcc .fwd2
inc Z6e
jmp .fwd2
.fwd1: lda Z6d
clc
adc #$02
sta Z6d
bcc .fwd2
inc Z6e
.fwd2: txa
.fwd3: sta Z71
ldx #$01
stx Z6f
dex
stx Z70
lda #$0f
sec
sbc Z71
tax
beq .fwd4
.loop1: asl Z6f
rol Z70
dex
bne .loop1
.fwd4: ldy #$00
lda (Z6d),y
sta Z72
iny
lda (Z6d),y
sta Z71
rts
msg_internal_error:
text_str "Internal error "
Df2a4: text_str "00. "
msg_len_internal_error equ *-msg_internal_error
; On entry:
; A = error number
; Does not return
int_error:
ldy #$01 ; divide by 10, storing into message
.loop1: ldx #0
.loop2: cmp #10
bcc .fwd1
sbc #10
inx
bne .loop2
.fwd1: ora #$30
sta Df2a4,y
txa
dey
bpl .loop1
prt_msg internal_error
jmp Lf2ce
; Does not return
op_quit:
jsr op_new_line
Lf2ce: prt_msg end_of_session
jmp * ; deliberately hang
msg_end_of_session:
text_str "End of session."
fcb char_cr
msg_len_end_of_session equ *-msg_end_of_session
op_restart:
ldx #$00
stx wndtop
lda ostream_2_state
beq .fwd1
dex
stx Ddc34
.fwd1: jsr Sd856
jmp restart
; Unreferenced? See S14dc in ZIP revision F
lda #$fb
rts
Sf2ff: inc rndloc
dec rndloc+1
lda rndloc
adc Zc0
tax
lda rndloc+1
sbc Zc0+1
sta Zc0
stx Zc0+1
rts
Sf311: sta Zd7
ldx ostream_3_state
beq .fwd1
if iver==iver2a
jsr Sf3b3
else
jmp Sf3b3
endif
.fwd1: ldx ostream_1_state
bne .fwd2
ldx ostream_2_state
bne .fwd2
rts
.fwd2: lda Zd7
ldx Zbd
bne .fwd6
cmp #char_cr
bne .fwd3
jmp op_new_line
.fwd3: cmp #' '
bcc .rtn
ldx invflg
bpl .fwd4
ora #$80
.fwd4: ldx Zd1
sta D0200,x
ldy Zd0
cpy Zbf
bcc .fwd5
jmp Lf3cd
.fwd5: inc Zd0
inc Zd1
.rtn: rts
.fwd6: sta Zd7
cmp #$20
bcc .rtn2
lda D057b
cmp #$50
bcs .rtn2
lda cursrh
cmp #$50
bcs .rtn2
lda Zc2
beq .fwd7
lda cursrv
cmp wndtop
bcs .rtn2
bcc .fwd8 ; always taken
.fwd7: lda cursrv
cmp wndtop
bcc .rtn2
.fwd8: lda ostream_1_state
beq .fwd9
lda Zd7
ora #$80
jsr cout
.fwd9: lda Zc2
bne .rtn2
lda Zd4
beq .rtn2
lda ostream_2_state
beq .rtn2
lda cswl
pha
lda cswl+1
pha
lda D057b
pha
lda cursrh
pha
lda Ddc35
sta cswl
lda Ddc35+1
sta cswl+1
lda Zd7
jsr cout
pla
sta cursrh
pla
sta D057b
pla
sta cswl+1
pla
sta cswl
.rtn2: rts
Sf3b3: tax
lda Zb9
clc
adc Zb7
sta Z6d
lda Zba
adc Zb8
sta Z6e
ldy #$00
txa
sta (Z6d),y
inc Zb9
bne .rtn
inc Zba
.rtn: rts
Lf3cd: lda #$a0
stx Zd3
.loop1: cmp D0200,x
beq .fwd1
dex
bne .loop1
ldx Zbf
.fwd1: stx Zd2
stx Zd1
jsr op_new_line
ldx Zd2
ldy #$00
.loop2: inx
cpx Zd3
bcc .fwd2
beq .fwd2
sty Zd0
sty Zd1
rts
.fwd2: lda D0200,x
sta D0200,y
iny
bne .loop2
op_new_line:
ldx Zd1
lda #$8d
sta D0200,x
inc Zd1
lda ostream_1_state
beq .fwd2
lda Zc2
bne .fwd1
inc Zd5
.fwd1: ldx Zd5
inx
cpx wndbot
bcc .fwd2
lda wndtop
sta Zd5
inc Zd5
bit kbd_strb
prt_msg_alt more
.loop1: bit kbd
bpl .loop1
bit kbd_strb
ldy #$06
.loop2: lda #$08
jsr cout
dey
bne .loop2
jsr clreol
.fwd2: jsr Sf446
lda #$00
sta Zd0
sta Zd1
rts
Sf446: ldy Zd1
beq .rtn
sty Zde
lda ostream_1_state
beq .fwd1
ldx #$00
.loop1: lda D0200,x
jsr Sdaee
inx
dey
bne .loop1
.fwd1: lda Zc2
bne .rtn
jsr Sdbf3
.rtn: rts
op_show_status:
rts
; Note that buffer mode only applies to the lower window,
; and buffering never happens for the upper window.
; (In Z-Machine v6, every window has its own buffer mode
; flag.)
op_buffer_mode:
ldx arg1
bne .fwd1
jsr Sf446
ldx #$00
stx Zd1
inx
stx Zbd
rts
.fwd1: dex
bne .rtn
stx Zbd
.rtn: rts
op_output_stream:
ldx arg1
bmi ostream_deselect
dex
beq ostream_select_1
dex
beq ostream_select_2
dex
beq ostream_select_3
dex
beq ostream_select_4
rts
ostream_deselect:
inx
beq ostream_deselect_1
inx
beq ostream_deselect_2
inx
beq ostream_deselect_3
inx
beq ostream_deselect_4
rts
; output stream 1 is the screen
ostream_select_1:
inx
stx ostream_1_state
rts
ostream_deselect_1:
stx ostream_1_state
rts
; output stream 2 is the transcript (printer)
ostream_select_2:
inx
stx ostream_2_state
lda hdr_flags2+1
ora #$01
sta hdr_flags2+1
lda Ddc34
bne .rtn
jsr Sdc37
.rtn: rts
ostream_deselect_2:
stx ostream_2_state
lda hdr_flags2+1
and #$fe
sta hdr_flags2+1
rts
; output stream 3 is a Z-machine table
; selecting stream 3 can be done recursively
ostream_select_3:
inx
stx ostream_3_state
lda arg2+1
clc
adc Z81
ldx arg2
stx Zb7
sta Zb8
lda #$02
sta Zb9
lda #$00
sta Zba
rts
ostream_deselect_3:
if iver>=iver2c
lda ostream_3_state ; if no output stream 3 was selected, do nothing.
beq .fwd2
; This above fix appears to introduce a new bug, in that the following
; "stx ostream_3_state" instruction (outside the conditional assembly)
; will always store 1, even if the ostream table stack is empty.
endif
stx ostream_3_state
lda Zb9
clc
adc Zb7
sta Z6d
lda Zba
adc Zb8
sta Z6e
lda #$00
tay
sta (Z6d),y
ldy #$01
lda Zb9
sec
sbc #$02
sta (Zb7),y
bcs .fwd1
dec Zba
.fwd1: lda Zba
dey
sta (Zb7),y
lda #$00
sta Zb6
.fwd2 rts
; output stream 4, if it existed, would be a script file of user input
ostream_select_4:
ostream_deselect_4:
rts
op_set_cursor:
if iver==iver2a
lda hdr_flags_1
and #$10
beq .rtn
lda Zc2
bne .fwd2
ldx arg1
dex
txa
clc
adc wndtop
sta cursrv
ldx Zbd
bne .fwd1
sta Zd5
.fwd1: ldx arg2
dex
stx D057b
stx cursrh
jmp vtab
.rtn: rts
.fwd2: ldx arg1
dex
stx cursrv
jmp .fwd1
else
lda hdr_flags_1
and #$10
beq .rtn
ldy Zbd
beq .rtn
ldy Zc2
beq .rtn
ldx arg1
dex
stx cursrv
ldx arg2
dex
stx D057b
stx cursrh
jmp vtab
.rtn: rts
endif
op_get_cursor:
op_input_stream:
rts
op_set_text_state:
lda arg1
bne .fwd1
lda #$ff
sta invflg
.rtn: rts
.fwd1: cmp #$01
bne .rtn
lda hdr_flags_1
and #$02
beq .rtn
lda #$3f
sta invflg
rts
op_erase_line:
lda hdr_flags_1
and #$10
beq Lf559
lda arg1
cmp #$01
bne Lf559
jmp clreol
Lf559: rts
op_erase_window:
lda hdr_flags_1
and #$01
beq Lf559
lda arg1
beq .fwd1
cmp #$01
beq .fwd2
cmp #$ff
bne Lf559
jsr Sdcd8
jmp home
.fwd1: lda wndtop
sta Zd5
jsr home
lda #$17
sta cursrv
jmp vtab
.fwd2: lda wndtop
pha
ldx #$00
stx wndtop
sta wndbot
jsr home
lda #$18
sta wndbot
pla
sta wndtop
sta cursrv
dec cursrv
jmp vtab
op_read_char:
lda arg1
cmp #$01
bne .fwd3
lda wndtop
sta Zd5
if iver<=iver2d
lda #$00
sta Zd0
else
inc Zd5
lda #$00
endif
sta Zd1
dec argcnt
beq .fwd2
lda arg2
sta Z6e
lda #$00
sta Z70
sta Z6f
dec argcnt
beq .fwd1
lda arg3
sta Z6f
lda arg3+1
sta Z70
.fwd1: bit kbd_strb
.loop1: lda Z6e
sta Z6d
.loop2: ldx #$0a
.loop3: lda #$40
jsr Sfca8
dex
bne .loop3
bit kbd
bmi .fwd2
dec Z6d
bne .loop2
lda Z6f
ora Z70
beq .fwd3
jsr Sf5f9
lda acc
bne .fwd3
beq .loop1 ; always taken
.fwd2: jsr Sda78
ldx #$00
jmp store_result_xa
.fwd3: jmp store_result_zero
Sf5f9: lda #Lf67c>>8
sta Le4db+2
lda #Lf67c&$ff
sta Le4db+1
lda Z6e
pha
lda Z70
pha
lda Z6f
pha
ldx Zed
lda Zed+1
jsr push_ax
lda pc
jsr push_ax
ldx pc+1
lda pc+2
jsr push_ax
lda #$00
asl Z6f
rol Z70
rol
sta pc+2
asl Z6f
rol Z70
rol pc+2
lda Z70
sta pc+1
lda Z6f
sta pc
jsr find_pc_page
jsr fetch_pc_byte
sta Z6f
sta Z70
beq .fwd1
lda #$00
sta Z6d
.loop1: ldy Z6d
ldx local_vars,y
lda local_vars+1,y
jsr push_ax
jsr fetch_pc_byte
sta Z6e
jsr fetch_pc_byte
ldy Z6d
sta local_vars,y
lda Z6e
sta local_vars+1,y
iny
iny
sty Z6d
dec Z6f
bne .loop1
.fwd1: ldx Z70
txa
jsr push_ax
lda stk_ptr
sta Zed
lda stk_ptr+1
sta Zed+1
jmp main_loop
Lf67c: lda #store_result>>8
sta Le4db+2
lda #store_result&$ff
sta Le4db+1
pla
pla
pla
sta Z6f
pla
sta Z70
pla
sta Z6e
rts
msg_more:
text_str "[MORE]"
msg_len_more equ *-msg_more
msg_printer_slot:
fcb char_cr
text_str "Printer Slot 1-7: "
msg_len_printer_slot equ *-msg_printer_slot
msg_story_loading:
text_str "The story is loading ..."
msg_len_story_loading equ *-msg_story_loading
if iver==iver2a
align $0100,$ff
else
align $0100,$00
endif