diff --git a/Makefile b/Makefile index dfa5dc00b..ede737de6 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ # DISK=4cade.2mg +VOLUME=A.4AM.PACK # third-party tools required to build # https://sourceforge.net/projects/acme-crossass/ @@ -19,26 +20,34 @@ ACME=acme CADIUS=cadius asm: md - $(ACME) -r build/prorwts2.lst src/PRORWTS2.S + $(ACME) -r build/4cade.lst src/4cade.a dsk: md asm - cadius CREATEVOLUME build/"$(DISK)" "A.4AM.PACK" 32MB -# cp res/_FileInformation.txt build/ -# bin/fixFileInformation.sh build/_FileInformation.txt -# $(CADIUS) ADDFILE build/"$(DISK)" "/A.4AM.PACK/" "res/CREDITS.TXT" -# $(CADIUS) CREATEFOLDER build/"$(DISK)" "/A.4AM.PACK/LIB/" -# $(CADIUS) ADDFILE build/"$(DISK)" "/A.4AM.PACK/LIB/" "build/ONBEYONDZ1" + $(CADIUS) CREATEVOLUME build/"$(DISK)" "${VOLUME}" 32766KB >/dev/null + 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/COVER" >/dev/null + $(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/COVER.A2FC" >/dev/null + $(CADIUS) CREATEFOLDER build/"$(DISK)" "/${VOLUME}/X/" >/dev/null + bin/do2po.py res/dsk/ build/po/ + rsync -a res/dsk/*.po build/po/ + bin/extract.py build/po/ | sh + rm -f build/X/**/.DS_Store + rm -f build/X/**/PRODOS + $(CADIUS) ADDFOLDER build/"$(DISK)" "/${VOLUME}/X" "build/X" artwork: dsk - $(CADIUS) ADDFOLDER build/"$(DISK)" "/A.4AM.PACK/ARTWORK" "res/artwork" -# $(CADIUS) ADDFILE build/"$(DISK)" "/A.4AM.PACK/ARTWORK/" "res/DHRSLIDE.SYSTEM" -# $(CADIUS) ADDFOLDER build/"$(DISK)" "/A.4AM.PACK/ARTWORKGS" "res/artworkgs" +# $(CADIUS) ADDFOLDER build/"$(DISK)" "/${VOLUME}/ARTWORK" "res/artwork" +# $(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/ARTWORK/" "res/DHRSLIDE.SYSTEM" +# $(CADIUS) ADDFOLDER build/"$(DISK)" "/${VOLUME}/ARTWORKGS" "res/artworkgs" mount: dsk osascript bin/V2Make.scpt "`pwd`" bin/4cade.vii build/"$(DISK)" md: - mkdir -p build + mkdir -p build/po + mkdir -p build/X clean: rm -rf build/ diff --git a/bin/do2po.py b/bin/do2po.py new file mode 100755 index 000000000..12244be60 --- /dev/null +++ b/bin/do2po.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +import sys +import glob +import os.path + +kMap = {0x00: 0x00, + 0x07: 0x08, + 0x0E: 0x01, + 0x06: 0x09, + 0x0D: 0x02, + 0x05: 0x0A, + 0x0C: 0x03, + 0x04: 0x0B, + 0x0B: 0x04, + 0x03: 0x0C, + 0x0A: 0x05, + 0x02: 0x0D, + 0x09: 0x06, + 0x01: 0x0E, + 0x08: 0x07, + 0x0F: 0x0F} + +indir, outdir = sys.argv[1:3] + +for infile in glob.glob(os.path.join(indir, "*.dsk")): + outfile = os.path.join(outdir, os.path.splitext(os.path.basename(infile))[0] + ".po") + with open(infile, 'rb') as f, open(outfile, 'wb') as g: + for track in range(0, 0x23): + sectors = [bytes(256)] * 0x10 + for dos_sector in range(0, 0x10): + sectors[kMap[dos_sector]] = f.read(256) + g.write(b"".join(sectors)) diff --git a/bin/extract.py b/bin/extract.py new file mode 100755 index 000000000..6d98061a7 --- /dev/null +++ b/bin/extract.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 + +import sys +import glob +import os.path + +indir = sys.argv[1] +for infile in glob.glob(os.path.join(indir, "*.po")): + print("cadius EXTRACTVOLUME \"" + infile + "\" build/X/ || cadius EXTRACTVOLUME \"" + infile + "\" build/X/") diff --git a/res/COVER b/res/COVER new file mode 100644 index 000000000..c416e5de5 Binary files /dev/null and b/res/COVER differ diff --git a/res/COVER.A2FC b/res/COVER.A2FC new file mode 100644 index 000000000..43a475b69 Binary files /dev/null and b/res/COVER.A2FC differ diff --git a/res/PRODOS b/res/PRODOS new file mode 100644 index 000000000..a701ba0fe Binary files /dev/null and b/res/PRODOS differ diff --git a/res/_FileInformation.txt b/res/_FileInformation.txt new file mode 100644 index 000000000..9d5ff241d --- /dev/null +++ b/res/_FileInformation.txt @@ -0,0 +1,4 @@ +PRODOS=Type(FF),AuxType(0000),Access(C3) +LAUNCHER.SYSTEM=Type(FF),AuxType(2000),Access(C3) +COVER=Type(06),AuxType(4000),Access(C3) +COVER.A2FC=Type(06),AuxType(2000),Access(C3) diff --git a/src/4cade.a b/src/4cade.a new file mode 100644 index 000000000..0f2e16ac7 --- /dev/null +++ b/src/4cade.a @@ -0,0 +1,53 @@ +!cpu 6502 +!to "build/LAUNCHER.SYSTEM",plain +*=$2000 + +MEMFLAG = $FF ; bit 7 = 0 if 64K, 1 if 128K + +MACHID = $BF98 ; machine identification byte + + lda MACHID + and #$30 + cmp #$30 ; C=0 if 64K, C=1 if 128K + ror MEMFLAG ; set bit 7 from C + +; jsr init ; initialize ProRWTS2 +; lda $C08B +; lda $C08B +; lda #cover +; sta namhi +; lda #0 +; sta sizelo +; lda #$20 +; sta sizehi +; jsr hddopendir +; bit $C055 +; bit $C052 +; bit $C057 +; bit $C050 +- lda #0 + beq - + +cover !byte cover_e-cover_b +cover_b !text "COVER" +cover_e + +;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 diff --git a/src/constants.a b/src/constants.a new file mode 100644 index 000000000..80191f6ad --- /dev/null +++ b/src/constants.a @@ -0,0 +1,10 @@ +;license:MIT +;(c) 2018 by 4am +; + +; zero page +PARAM = $00 ; used by PARAMS_ON_STACK macro, so basically everywhere +PTR = $02 +SRC = $04 +DEST = $06 +SAVE = $08 diff --git a/src/macros.a b/src/macros.a new file mode 100644 index 000000000..1209b136e --- /dev/null +++ b/src/macros.a @@ -0,0 +1,63 @@ +;license:MIT +;(c) 2018 by 4am +; +; common assembler macros +; + +; for functions that take parameters on the stack +; set (PARAM) to point to the parameters and +; move the stack pointer to the first byte after the parameters +; clobbers A,X +!macro PARAMS_ON_STACK .bytes { + pla + sta PARAM + plx + stx PARAM+1 + lda #.bytes + clc + adc PARAM + bcc + + inx ++ phx + pha +} + +; for functions that take parameters on the stack +; load a 16-bit value from the parameters on the stack into A (low) and Y (high) +; (assumes PARAMS_ON_STACK was used first) +!macro LDPARAM .offset { + ldy #.offset+1 + lda (PARAM),y + pha + dey + lda (PARAM),y + ply +} + +; load the address of .ptr into A (low) and Y (high) +!macro LDADDR .ptr { + lda #<.ptr + ldy #>.ptr +} + +; load a 16-bit value into A (low) and Y (high) +!macro LDAY .ptr { + lda .ptr + ldy .ptr+1 +} + +; store a 16-bit value from A (low) and Y (high) +!macro STAY .ptr { + sta .ptr + sty .ptr+1 +} + +; use BIT to swallow the following 1-byte opcode +!macro HIDE_NEXT_BYTE { + !byte $24 +} + +; use BIT to swallow the following 2-byte opcode +!macro HIDE_NEXT_2_BYTES { + !byte $2C +} diff --git a/src/prodos.mli.a b/src/prodos.mli.a new file mode 100644 index 000000000..fb9cb3e1e --- /dev/null +++ b/src/prodos.mli.a @@ -0,0 +1,455 @@ +;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 diff --git a/src/PRORWTS2.S b/src/prorwts2.a similarity index 99% rename from src/PRORWTS2.S rename to src/prorwts2.a index 9627655c1..d6c298fe2 100644 --- a/src/PRORWTS2.S +++ b/src/prorwts2.a @@ -9,8 +9,6 @@ ver_02 = 1 } else { ;ver_02 = 0 !cpu 65c02 } ;ver_02 -!to "build/prorwts2",plain -*=$800 ;place no code before init label below. @@ -43,8 +41,8 @@ ver_02 = 1 allow_sparse = 0 ;enable support for reading sparse files bounds_check = 0 ;set to 1 to prevent access beyond the end of the file ;but limits file size to 64k-2 bytes. - no_interrupts= 0 ;set to 1 to disable interrupts across calls - detect_err = 0 ;set to 1 to to detect errors in no_interrupt mode + no_interrupts= 1 ;set to 1 to disable interrupts across calls + detect_err = 1 ;set to 1 to to detect errors in no_interrupt mode swap_zp = 0 ;set to 1 to include code to preserve zpage ;used only by rwts_mode rwts_mode = 0 ;set to 1 to enable emulation of DOS RWTS when running from hard disk @@ -582,7 +580,7 @@ filename !byte filename_e-filename_b filename_b !text "diskimage.dsk" filename_e } else { ;rwts_mode = 0 - rts + rts } ;rwts_mode c7_parms !byte 1