games.conf parser works, okvs works, glue.prorwts2 works

This commit is contained in:
4am 2018-08-30 21:31:54 -07:00
parent 323e715cb1
commit ae064cdee6
10 changed files with 277 additions and 547 deletions

View File

@ -27,7 +27,7 @@ dsk: md asm
cp res/_FileInformation.txt build/
$(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/PRODOS" >/dev/null
$(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "build/LAUNCHER.SYSTEM" >/dev/null
$(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/games.conf" >/dev/null
$(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/GAMES.CONF" >/dev/null
$(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/COVER" >/dev/null
$(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/COVER.A2FC" >/dev/null
$(CADIUS) CREATEFOLDER build/"$(DISK)" "/${VOLUME}/X/" >/dev/null

View File

@ -2,3 +2,4 @@ PRODOS=Type(FF),AuxType(0000),Access(C3)
LAUNCHER.SYSTEM=Type(FF),AuxType(2000),Access(C3)
COVER=Type(06),AuxType(2000),Access(C3)
COVER.A2FC=Type(06),AuxType(2000),Access(C3)
GAMES.CONF=Type(04),AuxType(4000),Access(C3)

View File

@ -1 +1 @@
# # 4cade master game list # # Format: # AB,name=directory # # A=1 if game requires joystick, 0 if playable on keyboard # B=1 if game requires 128K, 0 if playable on 64K # all other values for A or B -> ignore entire line # 00,Agent USA=AGENT.USA 11,Airheart=AIRHEART 00,Alcazar=ALCAZAR 00,Alien Downpour=ALIEN.DOWNPOUR # TODO: Alien Rain volume name and executable filename do not match (one has period, one doesn't) 00,Alien Rain=ALIENRAIN 00,Ankh=ANKH 00,Apple Panic=APPLE.PANIC 00,Aquatron=AQUATRON 10,Arkanoid=ARKANOID 00,Battlezone=BATTLEZONE 10,BC's Quest For Tires=BCS.QUEST 00,Beer Run=BEER.RUN 00,Bellhop=BELLHOP 00,Bill Budge's Trilogy=BUDGETRILOGY 00,Blister Ball=BLISTER.BALL 00,Bolo=BOLO 00,Brainteaser Boulevard=BRAINTEASERBLVD 00,BurgerTime=BURGERTIME 00,Cannonball Blitz=CANNONBALL.BLTZ 00,Canyon Climber=CANYON.CLIMBER 00,Centipede=CENTIPEDE 10,Choplifter=CHOPLIFTER 00,Commando=COMMANDO 00,Conan=CONAN 10,Crisis Mountain=CRISIS.MOUNTAIN 00,Crossfire=CROSSFIRE 01,D-Generation=D.GENERATION 10,David's Midnight Magic=DAVIDS.MAGIC 10,Defender=DEFENDER 00,Dig Dug=DIG.DUG 10,Dino Eggs=DINO.EGGS 10,Donkey Kong=DONKEY.KONG 10,Drelbs=DRELBS 00,Drol=DROL 00,Epoch=EPOCH 00,Falcons=FALCONS 00,Flight Simulator I=FS1 00,Flip Out=FLIP.OUT 10,Formula 1 Racer=FORMULA.1 00,Frogger=FROGGER 10,Galaxian=GALAXIAN 10,The Goonies=GOONIES 00,Gremlins=GREMLINS 10,H.E.R.O.=HERO 00,Hard Hat Mack=HARD.HAT.MACK 00,Head On=HEAD.ON 00,High Rise=HIGH.RISE 00,Hungry Boy=HUNGRYBOY 10,Impossible Mission=IMPOSSIBLE.MISS 00,Joust=JOUST 00,Jungle Hunt=JUNGLE.HUNT 00,Karateka=KARATEKA 00,Lady Tut=LADY.TUT 10,Lost Tomb=LOST.TOMB 10,Mad Bomber=MAD.BOMBER 00,Mario Bros=MARIO.BROS 00,Montezuma's Revenge=MONTEZUMA 00,Moon Patrol=MOON.PATROL 00,Mr. Cool=MR.COOL 10,Mr. Do=MR.DO 00,Mr. Robot=MR.ROBOT 00,Ms. Pacman=MS.PACMAN 00,Nibbler=NIBBLER 00,Night Stalker=NIGHT.STALKER 00,Nightmare Gallery=NIGHTMARE 00,NORAD=NORAD 00,O'Riley's Mine=ORILEYS.MINE 00,Outpost=OUTPOST 00,Pac-Man=PAC.MAN 00,Paperboy=PAPERBOY 00,Pest Patrol=PEST.PATROL 00,Pie-Man=PIEMAN 00,Pit Stop II=PITSTOP.II 10,Pitfall II=PITFALL.II 00,Plasmania=PLASMANIA 00,Pooyan=POOYAN 01,Prince of Persia=PRINCEUNP 00,Puckman=PUCK.MAN 11,Qix=QIX 01,Radwarrior=RADWARRIOR 00,Repton=REPTON 00,Ribbit=RIBBIT 00,Robotron 2084=ROBOTRON.2084 00,Sabotage=SABOTAGE 00,Serpentine=SERPENTINE 10,Shamus=SHAMUS 00,Snack Attack=SNACK.ATTACK 00,Snake Byte=SNAKE.BYTE 00,Sneakers=SNEAKERS 00,Snoggle=SNOGGLE 00,Space Raiders=SPACE.RAIDERS 00,Spider Raid=SPIDER.RAID 01,Spiderbot=SPIDERBOT 00,Spy Hunter=SPY.HUNTER 00,Spy's Demise=SPYS.DEMISE 10,Starblaster=STARBLASTER 10,Stargate=STARGATE 00,Stellar 7=STELLAR.7 00,Succession=SUCCESSION 00,Swashbuckler=SWASHBUCKLER 00,Tag Team Wrestling=TAG.TEAM 00,Tapper=TAPPER 00,Thief=THIEF 00,Thunder Bombs=THUNDERBOMBS 10,Tomahawk=TOMAHAWK 00,Track N Field=TRACK.AND.FIELD 10,Tubeway ][=TUBEWAY 01,Victory Road=VICTORY.ROAD 00,Wavy Navy=WAVY.NAVY [eof]
# # 4cade master game list # # Format: # AB,name=directory # # A=1 if game requires joystick, 0 if playable on keyboard # B=1 if game requires 128K, 0 if playable on 64K # all other values for A or B -> ignore entire line (like this one!) # 00,Agent USA=AGENT.USA 11,Airheart=AIRHEART 00,Alcazar=ALCAZAR 00,Alien Downpour=ALIEN.DOWNPOUR # TODO: Alien Rain volume name and executable filename do not match (one has period, one doesn't) 00,Alien Rain=ALIENRAIN 00,Ankh=ANKH 00,Apple Panic=APPLE.PANIC 00,Aquatron=AQUATRON 10,Arkanoid=ARKANOID 00,Battlezone=BATTLEZONE 10,BC's Quest For Tires=BCS.QUEST 00,Beer Run=BEER.RUN 00,Bellhop=BELLHOP 00,Bill Budge's Trilogy=BUDGETRILOGY 00,Blister Ball=BLISTER.BALL 00,Bolo=BOLO 00,Brainteaser Boulevard=BRAINTEASERBLVD 00,BurgerTime=BURGERTIME 00,Cannonball Blitz=CANNONBALL.BLTZ 00,Canyon Climber=CANYON.CLIMBER 00,Centipede=CENTIPEDE 10,Choplifter=CHOPLIFTER 00,Commando=COMMANDO 00,Conan=CONAN 10,Crisis Mountain=CRISIS.MOUNTAIN 00,Crossfire=CROSSFIRE 01,D-Generation=D.GENERATION 10,David's Midnight Magic=DAVIDS.MAGIC 10,Defender=DEFENDER 00,Dig Dug=DIG.DUG 10,Dino Eggs=DINO.EGGS 10,Donkey Kong=DONKEY.KONG 10,Drelbs=DRELBS 00,Drol=DROL 00,Epoch=EPOCH 00,Falcons=FALCONS 00,Flight Simulator I=FS1 00,Flip Out=FLIP.OUT 10,Formula 1 Racer=FORMULA.1 00,Frogger=FROGGER 10,Galaxian=GALAXIAN 10,The Goonies=GOONIES 00,Gremlins=GREMLINS 10,H.E.R.O.=HERO 00,Hard Hat Mack=HARD.HAT.MACK 00,Head On=HEAD.ON 00,High Rise=HIGH.RISE 00,Hungry Boy=HUNGRYBOY 10,Impossible Mission=IMPOSSIBLE.MISS 00,Joust=JOUST 00,Jungle Hunt=JUNGLE.HUNT 00,Karateka=KARATEKA 00,Lady Tut=LADY.TUT 10,Lost Tomb=LOST.TOMB 10,Mad Bomber=MAD.BOMBER 00,Mario Bros=MARIO.BROS 00,Montezuma's Revenge=MONTEZUMA 00,Moon Patrol=MOON.PATROL 00,Mr. Cool=MR.COOL 10,Mr. Do=MR.DO 00,Mr. Robot=MR.ROBOT 00,Ms. Pacman=MS.PACMAN 00,Nibbler=NIBBLER 00,Night Stalker=NIGHT.STALKER 00,Nightmare Gallery=NIGHTMARE 00,NORAD=NORAD 00,O'Riley's Mine=ORILEYS.MINE 00,Outpost=OUTPOST 00,Pac-Man=PAC.MAN 00,Paperboy=PAPERBOY 00,Pest Patrol=PEST.PATROL 00,Pie-Man=PIEMAN 00,Pit Stop II=PITSTOP.II 10,Pitfall II=PITFALL.II 00,Plasmania=PLASMANIA 00,Pooyan=POOYAN 01,Prince of Persia=PRINCEUNP 00,Puckman=PUCK.MAN 11,Qix=QIX 01,Radwarrior=RADWARRIOR 00,Repton=REPTON 00,Ribbit=RIBBIT 00,Robotron 2084=ROBOTRON.2084 00,Sabotage=SABOTAGE 00,Serpentine=SERPENTINE 10,Shamus=SHAMUS 00,Snack Attack=SNACK.ATTACK 00,Snake Byte=SNAKE.BYTE 00,Sneakers=SNEAKERS 00,Snoggle=SNOGGLE 00,Space Raiders=SPACE.RAIDERS 00,Spider Raid=SPIDER.RAID 01,Spiderbot=SPIDERBOT 00,Spy Hunter=SPY.HUNTER 00,Spy's Demise=SPYS.DEMISE 10,Starblaster=STARBLASTER 10,Stargate=STARGATE 00,Stellar 7=STELLAR.7 00,Succession=SUCCESSION 00,Swashbuckler=SWASHBUCKLER 00,Tag Team Wrestling=TAG.TEAM 00,Tapper=TAPPER 00,Thief=THIEF 00,Thunder Bombs=THUNDERBOMBS 10,Tomahawk=TOMAHAWK 00,Track N Field=TRACK.AND.FIELD 10,Tubeway ][=TUBEWAY 01,Victory Road=VICTORY.ROAD 00,Wavy Navy=WAVY.NAVY [eof]

View File

@ -5,8 +5,33 @@
!source "src/constants.a"
!source "src/macros.a"
Init
jsr Has64K ; check for 64K (required)
bcc @found64K
bcs @no64K
jsr DisableAccelerator ; set to 1 MHz
jsr Has128K ; check for 128K (absence is OK, we just filter out some games)
ror MachineStatus
jsr HasJoystick ; check for joystick (absence is OK, we just filter out some games)
ror MachineStatus
+READ_ROM_WRITE_RAM1
ldx #$00 ; relocate rest of program to RAM bank 1 in language card
@FM lda FirstMover,x
sta $D000,x
inx
bne @FM
lda @FM+2
cmp #>LastMover
bcs +
inc @FM+2
inc @FM+5
bne @FM
+
jsr init ; initialize ProRWTS2 (bye bye ProDOS)
+READ_RAM1_WRITE_RAM1
jmp Start
@no64K
jsr $FB2F
jsr $FC58
ldy #@no64Klen
@ -18,85 +43,53 @@
@s_no64K !raw "REQUIRES 64K"
@no64Klen=*-@s_no64K
@found64K
jsr DisableAccelerator ; set to 1 MHz
jsr Has128K ; check for 128K (absence is OK, we just filter out some games)
ror MachineStatus
jsr HasJoystick ; check for joystick (absence is OK, we just filter out some games)
ror MachineStatus
lda LCBANK1WRITE ; read ROM / write LC bank 1
lda LCBANK1WRITE
ldx #$00
FM lda FirstMover,x
sta $D000,x
inx
bne FM
; inc FM+2
; inc FM+5
; lda FM+5
; cmp #>LastMover
; bcc FM
jsr init ; initialize ProRWTS2 (bye bye ProDOS)
lda LCBANK1 ; read/write LC bank 1
lda LCBANK1
jmp Start
; these routines will only be called once, from main memory, before relocating to language card
!source "src/memcheck.a"
!source "src/joystick.a"
!source "src/normfast.a"
; ProRWTS2 has its own function to relocate itself
!source "src/prorwts2.a"
FirstMover
!pseudopc $D000 {
!zone
Start
lda #$00 ; read first $2000 bytes
sta sizelo
lda #$20
sta sizehi
lda #0 ; 0 = read into main memory
sta auxreq
lda #cmdread ; read (instead of write)
sta reqcmd
bit MachineStatus
bvs @ShowCover128K
lda #<cover64 ; pointer to length-prefixed filename
sta namlo
lda #>cover64
sta namhi
jsr hddopendir ; call ProRWTS2
bvs @Load128
jsr LoadFile
!word cover64
clc
bcc @Show
@ShowCover128K
inc auxreq ; 1 = read into aux memory
lda #<cover128 ; pointer to length-prefixed filename
sta namlo
lda #>cover128
sta namhi
jsr hddopendir ; call ProRWTS2
lda #$20 ; read next $2000 bytes
sta sizehi
dec auxreq ; 0 = read into main memory
jsr hddrdwrpart ; call ProRWTS2
sta $C000 ; display double hi-res page 1
@Load128
jsr LoadDHRFile
!word cover128
sta $C000 ; double hi-res mode
sta $C00D
sta $C05E
sta $C001
@Show
sta $C057
sta $C057 ; show graphics page 1 (HGR or DHGR)
sta $C052
sta $C054
sta $C050
jsr LoadFile
- !word gamesconf
jsr ParseGamesList
!word gGamesListStore
!word -
bit $C010
- lda $C000
bpl -
bit $C010
brk
gamesconf
!byte gamesconf_e-gamesconf_b
gamesconf_b
!text "GAMES.CONF"
gamesconf_e
cover64
!byte cover64_e-cover64_b
cover64_b
@ -107,24 +100,11 @@ cover128
cover128_b
!text "COVER.A2FC"
cover128_e
; these routines will only be called after relocating to language card
!source "src/glue.prorwts2.a"
!source "src/okvs.a"
!source "src/parse.games.a"
gGamesListStore
!word *+2 ; address of first okvs store
}
LastMover
;LoadDHGR
; sta $C000
; ldx #$20 ; copy $2000 bytes to auxmem
; stx @copya+2
; stx @copyb+2
; ldy #0
;@writeToAuxLoop
; sta $C005
;@copya lda $FF00, y
;@copyb sta $FF00, y
; iny
; bne @copya
; sta $C004
; inc @copya+2
; inc @copyb+2
; dex
; bne @writeToAuxLoop

View File

@ -3,25 +3,14 @@
;
; soft switches
STOREOFF = $C000 ; write to use following flags:
STOREOFF = $C000 ; write to use following 4 flags:
READMAINMEM = $C002 ; write to R main mem
READAUXMEM = $C003 ; write to R aux mem
WRITEMAINMEM = $C004 ; write to W main mem
WRITEAUXMEM = $C005 ; write to W aux mem
SETMAINZP = $C008 ; write to R/W main mem zero page
SETAUXZP = $C009 ; write to R/W aux mem zero page
AUXMEMSTATUS = $C013 ; read high bit only
AUXZPSTATUS = $C016 ; read high bit only
;
SLOT3STATUS = $C017 ; read high bit only
LCBANK2READ = $C080 ; read once to R RAM bank 2 / no write
ROMIN = $C081 ; read twice to R ROM / W RAM bank 2
ROMONLY = $C082 ; read once to R ROM / no write
;LCBANK2 = $C083 ; read twice to R/W RAM bank 2
LCBANK1READ = $C088 ; read once to R RAM bank 1 / no write
LCBANK1WRITE = $C089 ; read twice to R ROM / W RAM bank 1
LCBANK1 = $C08B ; read twice to R/W RAM bank 1
; ROM
MACHINEID = $FBB3
@ -31,5 +20,13 @@ PTR = $02
SRC = $04
DEST = $06
SAVE = $08
MachineStatus =$FF ; bit 7 = 1 if machine has joystick
MachineStatus =$F0 ; bit 7 = 1 if machine has joystick
; bit 6 = 1 if machine has 128K
; $FE ; used by ParseGamesList
; $FF ; used by ParseGamesList
; main memory
gKeyLen = $1F00 ; used by ParseGamesList
gKey = $1F01
gValLen = $1F80
gVal = $1F81

63
src/glue.prorwts2.a Normal file
View File

@ -0,0 +1,63 @@
;license:MIT
;(c) 2017-8 by 4am
;
; ProRWTS2 glue functions
;
; Public functions
; - LoadFile
;
;------------------------------------------------------------------------------
; LoadFile
; load a file into memory all at once, using ProRWTS2
; uses file's load address
;
; in: stack contains 2 bytes of parameters:
; +1 address of filename
; out: all flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;------------------------------------------------------------------------------
LoadFile
+PARAMS_ON_STACK 2
+LDPARAM 1
+STAY namlo ; set filename
lda #$FF ; read entire file (ProRWTS2 will figure out exact size)
sta sizelo
sta sizehi
lda #0 ; 0 = read into main memory
sta auxreq
lda #cmdread ; read (instead of write)
sta reqcmd
jmp hddopendir ; exit via ProRWTS2
;------------------------------------------------------------------------------
; LoadDHRFile
; load .A2FC file (uncompressed double hi-res graphics) into memory
; all at once, using ProRWTS2
; first $2000 bytes of file are loaded into auxiliary memory $2000..$3FFF
; second $2000 bytes of file are loaded into main memory $2000..$3FFF
;
; in: stack contains 2 bytes of parameters:
; +1 address of filename
; out: all flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;------------------------------------------------------------------------------
LoadDHRFile
+PARAMS_ON_STACK 2
+LDPARAM 1
+STAY namlo ; set filename
lda #$00 ; read first $2000 bytes
sta sizelo
lda #$20
sta sizehi
lda #1 ; 1 = read into aux memory
sta auxreq
lda #cmdread ; read (instead of write)
sta reqcmd
jsr hddopendir ; call ProRWTS2
lda #$20 ; read next $2000 bytes
sta sizehi
dec auxreq ; 0 = read into main memory
jmp hddrdwrpart ; call ProRWTS2

View File

@ -66,3 +66,18 @@
!macro HIDE_NEXT_2_BYTES {
!byte $2C
}
; various language card configurations
!macro READ_RAM1_WRITE_RAM1 {
bit $C08B
bit $C08B
}
!macro READ_ROM_WRITE_RAM1 {
bit $C089
bit $C089
}
!macro READ_ROM_NO_WRITE {
bit $C082
}

View File

@ -9,8 +9,7 @@
; ROM in memory (not LC RAM bank)
;------------------------------------------------------------------------------
Has64K
lda LCBANK1 ; read/write LC RAM bank 1
lda LCBANK1
+READ_RAM1_WRITE_RAM1
lda #$AA ; test #1 for $D0 page
sta $D000
eor $D000
@ -22,7 +21,7 @@ Has64K
clc
+HIDE_NEXT_BYTE
@no sec
sta ROMONLY
+READ_ROM_NO_WRITE
rts
;------------------------------------------------------------------------------
@ -41,7 +40,8 @@ Has64K
; https://github.com/jmechner/Prince-of-Persia-Apple-II/blob/master/01%20POP%20Source/Source/BOOT.S#L119
;------------------------------------------------------------------------------
Has128K
sta ROMONLY ; need ROM for machine ID byte
+READ_ROM_NO_WRITE
sta STOREOFF
lda MACHINEID
cmp #6
bne @no ; earlier than //e -> no 128K

129
src/parse.games.a Normal file
View File

@ -0,0 +1,129 @@
;license:MIT
;(c) 2018 by 4am
;
; GAMES.CONF parser
;
; Public functions:
; - ParseGamesList
;
;------------------------------------------------------------------------------
; ParseGamesList
; parse buffer with AB,KEY=VALUE lines of text into an okvs
; keys and values limited to 127 characters, which should be enough for anyone
; '[' character at beginning of line ends the parsing
; (see games.conf file for more format information)
;
; in: stack contains 4 bytes of parameters:
; +1 [word] handle to storage space for okvs
; +3 [word] handle to buffer containing contents of GAMES.CONF
; out: all registers and flags clobbered
; $1F00..$1FFF clobbered
; $00/$01 clobbered
; $02/$03 clobbered
; $04/$05 has the address of the next available byte after the okvs
; $FE/$FF clobbered
;------------------------------------------------------------------------------
ParseGamesList
+PARAMS_ON_STACK 4
+LDPARAM 1
+STAY @store1
+STAY @store2
+LDPARAM 3
+STAY $FE
ldy #0
lda ($FE),y
pha
iny
lda ($FE),y
tay
pla
sec
sbc #$01
sta $FE
bcs +
dey
+ sty $FF
jsr okvs_init ; reset key/value store
@store1 !word $FDFD ; SMC
ldy #$00 ; index into ($FE) pointing to current character
@newkey ldx #$00 ; X = index into current key
jsr IncAndGetChar ; get first filter character ('1' if game requires joystick)
cmp #$0D ; ignore blank line
beq @newkey
cmp #$5B ; '[' ends the parsing
beq .parseKeyValueDone
cmp #$30 ; '0' -> no filtering on joystick
beq @filterOnMemory
cmp #$31 ; not '0' or '1' or '[' or CR -> ignore entire line (e.g. comment)
bne @skipLine
bit MachineStatus
bpl @skipLine ; game requires joystick but we don't have one, so ignore entire line
@filterOnMemory
jsr IncAndGetChar ; get second filter character ('1' if game requires 128K)
cmp #$30 ; '0' -> no filtering on memory
beq @swallowComma
cmp #$31 ; not '0' or '1' -> ignore entire line
bne @skipLine
bit MachineStatus
bvc @skipLine ; game requires 128K but we only have 64K, so ignore entire line
@swallowComma
jsr IncAndGetChar
cmp #$2C ; ',' delimiter (required)
bne @skipLine
@gatherKey
jsr IncAndGetChar
cmp #$3D ; '=' ends the key
beq @endKey
sta gKey,x
inx
bpl @gatherKey
@endKey stx gKeyLen
ldx #$00 ; now X = index into the current value
@gatherValue
jsr IncAndGetChar
cmp #$0D ; CR ends the value
beq @endValue
sta gVal,x
inx
bpl @gatherValue
@endValue
stx gValLen
tya
pha ; okvs functions clobber everything but we need Y
jsr okvs_append
@store2 !word $FDFD ; SMC
!word gKeyLen
!word gValLen
!byte 0
pla
tay
clc
bcc @newkey ; always branches
@skipLine ; skip to CR
jsr IncAndGetChar
cmp #$0D ; CR
bne @skipLine
beq @newkey ; always branches
;------------------------------------------------------------------------------
; IncAndGetChar
;
; in: Y = index into ($FE)
; ($FE) -> buffer
; out: A contains next byte from buffer
; Y incremented
; $FF possibly incremented
;------------------------------------------------------------------------------
IncAndGetChar
iny
bne +
inc $FF
+ lda ($FE),y
.parseKeyValueDone
rts

View File

@ -1,455 +0,0 @@
;license:MIT
;(c) 2017-8 by 4am
;
; ProDOS - file and other MLI routines
;
; Public functions
; - LoadFile
; - LoadDHRFile
; - LoadSHRFile
; - SaveFile
; - SetPrefix
; - GetFileInfo
;
; MLI command codes
CMD_QUIT = $65 ; quit to ProDOS
CMD_CREATE = $C0 ; create new file
CMD_DESTROY = $C1 ; delete a file
CMD_SETFILEINFO= $C3 ; set file info
CMD_GETFILEINFO= $C4 ; get file (or volume) info
CMD_SETPREFIX = $C6 ; change default pathname prefix
CMD_OPEN = $C8 ; open a file
CMD_READ = $CA ; read an open file
CMD_WRITE = $CB ; write to an open file
CMD_CLOSE = $CC ; close an open file
; MLI parameter counts
PC_QUIT = $04
PC_CREATE = $07
PC_DESTROY = $01
PC_SETFILEINFO = $07
PC_GETFILEINFO = $0A
PC_SETPREFIX = $01
PC_OPEN = $03
PC_READ = $04
PC_WRITE = $04
PC_CLOSE = $01
; ROM addresses
PRODOSMLI = $BF00 ; [callable] MLI entry point
MACHID = $BF98 ; machine identification byte
kAccessBits = $C3 ; full access (used in SaveFile)
;-------------------------------
; LoadFile
; load a file into memory all at once, using ProDOS MLI calls
;
; in: stack contains 6 bytes of parameters:
; +1 address of pathname
; +3 address of data buffer (to receive file contents)
; +5 address of ProDOS file buffer
; out: if C set, load failed and A contains error code
; from open or read
; if C clear, load succeeded and ($02) contains
; data loaded from file
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
LoadFile
+PARAMS_ON_STACK 6
+LDPARAM 1
+STAY mliparam+1 ; pathname
+LDPARAM 5
+STAY mliparam+3 ; ProDOS file buffer
jsr _openfile
bcs @exit ; C set on error
pha ; push file reference number
+LDPARAM 3
+STAY mliparam+2 ; data buffer
lda #$FF
sta mliparam+4 ; max data length (unlimited, YOLO)
sta mliparam+5
pla ; pull file reference number
jsr _readfile
php ; save flags from readfile
pha
jsr _closefile ; always close whether read worked or not
pla
plp ; restore flags from readfile
; (so caller gets codes from read attempt,
; not close)
@exit rts
;-------------------------------
; LoadDHRFile
; load uncompressed DHR file into memory from .A2FC file
; 1. load first half ($2000 bytes)
; 2. copy to auxmem
; 3. load second half ($2000 bytes)
;
; always loads into graphics page 1 ($2000/main and $2000/aux)
;
; in: stack contains 4 bytes of parameters:
; +1 address of pathname
; +3 address of ProDOS file buffer
; out: if C set, load failed
; if C clear, load succeeded
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
LoadDHRFile
+PARAMS_ON_STACK 4
ldy #$04
- lda (PARAM),y
sta mliparam,y
dey
bne -
jsr _openfile
bcs @exit ; C set on error
sta @saverefnum ; store file refnum
ldy #$20
stz mliparam+2 ; read into $2000 in main mem
sty mliparam+3
stz mliparam+4 ; read length = $2000 bytes (first half of file)
sty mliparam+5
jsr _readfile
bcs @close
sta $C000
ldx #$20 ; copy $2000 bytes to auxmem
stx @copya+2
stx @copyb+2
ldy #0
@writeToAuxLoop
sta $C005
@copya lda $FF00, y
@copyb sta $FF00, y
iny
bne @copya
sta $C004
inc @copya+2
inc @copyb+2
dex
bne @writeToAuxLoop
lda @saverefnum
jsr _readfile ; read another $2000 bytes into $2000 (stays in main mem)
@close php ; save flags from readfile
@saverefnum=*+1
lda #$FD ; file refnum (SMC)
jsr _closefile
plp ; restore flags from readfile
@exit rts
;-------------------------------
; LoadSHRFile
; load uncompressed SHR file into memory from .PIC file
; 1. load first quarter ($2000 bytes)
; 2. copy to graphics memory
; 3. load second quarter ($2000 bytes)
; 4. copy to graphics memory
; 5. load third quarter ($2000 bytes)
; 6. copy to graphics memory
; 7. load fourth quarter ($2000 bytes)
; 8. copy to graphics memory
;
; in: stack contains 4 bytes of parameters:
; +1 address of pathname
; +3 address of ProDOS file buffer
; out: if C set, load failed
; if C clear, load succeeded
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
LoadSHRFile
+PARAMS_ON_STACK 4
ldy #$04
- lda (PARAM),y
sta mliparam,y
dey
bne -
jsr _openfile
bcs @exit ; C set on error
sta @saverefnum ; store file refnum
ldy #$20
stz mliparam+2 ; read into $2000 in main mem
sty mliparam+3
stz mliparam+4 ; read length = $2000 bytes (one quarter of file)
sty mliparam+5
sty @shrdest+2
ldx #4 ; four quarters
- lda @saverefnum ; file refnum
jsr _readfile
bcs @close
phx
!cpu 65816
xce
rep #$30
!rl
!al
lda #$1FFF
tax
inx
@shrdest ldy #$FD00 ; SMC
phb
mvn 0,$E1
plb
sty @shrdest+1
!as
!rs
sec
xce
!cpu 65C02
plx
dex
bne -
@close php ; save flags from readfile
@saverefnum=*+1
lda #$FD ; file refnum (SMC)
jsr _closefile
plp ; restore flags from readfile
@exit rts
;-------------------------------
; SaveFile
; save a file to disk all at once, using ProDOS MLI calls
;
; in: stack contains 11 ($0B) bytes of parameters:
; +1 address of pathname
; +3 [byte] file type
; +4 [word] aux file type
; +6 address of data buffer
; +8 [word] length of data buffer
; +A address of ProDOS file buffer
; out: if C set, save failed
; if C clear, save succeeded
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
SaveFile
+PARAMS_ON_STACK $0B
+LDPARAM 1
+STAY mliparam+1 ; pathname
lda #CMD_DESTROY ; MLI destroy command
ldy #PC_DESTROY ; number of parameters for 'destroy' command
jsr mli ; don't care if this fails
ldy #$03
lda (PARAM),y ; file type
sta mliparam+4
+LDPARAM 4
+STAY mliparam+5 ; aux file type
lda #kAccessBits
sta mliparam+3 ; access bits (full access)
ldy #1
sty mliparam+7 ; storage type (file)
dey
sty mliparam+8 ; creation date (current)
sty mliparam+9
sty mliparam+10 ; creation time (current)
sty mliparam+11
lda #CMD_CREATE ; MLI create command
ldy #PC_CREATE ; number of parameters for 'create' command
jsr mli
bcs @exit
+LDPARAM 10
+STAY mliparam+3 ; PrODOS file buffer
jsr _openfile
bcs @exit
sta mliparam+1 ; store file reference number
+LDPARAM 6
+STAY mliparam+2 ; data buffer
+LDPARAM 8
+STAY mliparam+4 ; data length
lda #CMD_WRITE ; MLI write command
ldy #PC_WRITE ; number of parameters for 'write' command
jsr mli
php ; save flags from write command
jsr _closefile ; always close whether write worked or not
plp ; restore flags from write
; (so caller gets codes from write attempt,
; not close)
@exit rts
;-------------------------------
; SetAuxFileType
; set auxiliary file information only
; access bits and file-type are hard-coded
; intended for updating save-games only
;
; in: stack contains 4 bytes of parameters:
; +1 address of pathname
; +3 auxiliary type to set
; out: if C set, MLI call failed and A contains error code
; from set
; if C clear, MLI call succeeded
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
SetAuxFileType
+PARAMS_ON_STACK 4
+LDPARAM 1
+STAY mliparam+1 ; pathname
+LDPARAM 3
+STAY mliparam+5 ; aux type
lda #%11000011
sta mliparam+3 ; access bits
lda #4
sta mliparam+4 ; file type
lda #0
sta extra+0 ; date
sta extra+1 ; date
sta extra+2 ; time
sta extra+3 ; time
lda #CMD_SETFILEINFO ; MLI command
ldy #PC_SETFILEINFO ; number of parameters for 'setfileinfo' command
bra mli
;-------------------------------
; SetPrefix
; set current directory
;
; in: stack contains 2 bytes of parameters:
; +1 address of pathname
; out: if C set, call failed and A contains error code
; if C clear, call succeeded
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
SetPrefix
+PARAMS_ON_STACK 2
+LDPARAM 1
+STAY mliparam+1 ; pathname
lda #CMD_SETPREFIX
ldy #PC_SETPREFIX
bra mli
;-------------------------------
; GetFileInfo
; just what it says on the tin
;
; in: stack contains 2 bytes of parameters:
; +1 address of pathname
; out: if C set, MLI call failed and A contains error code
; from open or read
; if C clear, MLI call succeeded and mliparam contains
; all the info
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
GetFileInfo
+PARAMS_ON_STACK 2
+LDPARAM 1
+STAY mliparam+1 ; pathname
lda #CMD_GETFILEINFO ; MLI command
ldy #PC_GETFILEINFO ; number of parameters for 'getfileinfo' command
bra mli
;-------------------------------
; open file via ProDOS MLI
;
; in: caller has filled @mliparam with address of
; pathname, address of data buffer, and maximum
; data length
; out: if C set, open failed and A contains error code
; if C clear, open succeeded and A contains
; file reference number
;-------------------------------
_openfile
lda #CMD_OPEN ; MLI command
ldy #PC_OPEN ; number of parameters for 'open' command
jsr mli
bcs @exit
lda refnum ; caller should save file reference number
; as this memory location may be
; overwritten by later MLI calls
@exit rts
;-------------------------------
; read an open file via ProDOS MLI
;
; in: A = file reference number
; caller has filled @mliparam with address of
; data buffer and maximum data length
; out: if C set, read failed and A contains error code
; if C clear, read succeeded and A contains the same
; file reference number that was passed in
;-------------------------------
_readfile
sta mliparam+1 ; store file reference number
lda #CMD_READ ; MLI read command
ldy #PC_READ ; number of parameters for 'read' command
jsr mli
bcs @exit
lda mliparam+1 ; if no error, return file reference number
@exit rts
;-------------------------------
; close an open file
; in: A = file reference number
; out: if error, C set and A contains error code
; if success, C clear
;-------------------------------
_closefile
sta mliparam+1 ; store file reference number
lda #CMD_CLOSE ; MLI close command
ldy #PC_CLOSE ; number of parameters for 'close' command
bra mli
QuitToProDOS
lda #CMD_QUIT
ldy #PC_QUIT
; execution falls through here
;-------------------------------
; low-level MLI wrapper
; in: A = MLI command code
; Y = number of MLI parameters
; caller has filled @mliparam
; with all relevant parameters
; out: returns immediately after
; calling MLI, so whatever
; state the MLI routine sets,
; the caller will see it
; verbatim
;-------------------------------
mli sta mlicmd ; store command code
sty mliparam ; number of parameters
jsr PRODOSMLI ; call ProDOS
mlicmd !byte 00 ; command number
!word mliparam ; address of parameter table
rts
mliparam !byte $FE,$FE,$FE,$FE
filetype !byte $FE ; file type (set by MLI get_file_info)
auxtype ; auxiliary file type (2 bytes, set by MLI get_file_info)
refnum !byte $FE ; file refnum (set by MLI open)
mlilen !byte $FE,$FE ; file length (set by MLI read)
blocks !byte $FE,$FE ; blocks used (set by getvolumeinfo/getfileinfo)
; member is also used by createfile
extra !byte $FE,$FE,$FE,$FE,$FE,$FE,$FE,$FE
; used by get_file_info