mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-07-05 01:28:57 +00:00
Making slow progress integrating ProRWTS with mem mgr.
This commit is contained in:
parent
8ff169d1e6
commit
dd061c37c3
@ -17,7 +17,6 @@ package org.badvision
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.channels.Channels
|
||||
import net.jpountz.lz4.LZ4Factory
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
import java.util.zip.GZIPInputStream
|
||||
@ -78,7 +77,7 @@ class A2PackPartitions
|
||||
def globalScripts = [:]
|
||||
def lastSysModule
|
||||
|
||||
def compressor = LZ4Factory.fastestInstance().highCompressor()
|
||||
def compressor = new Lx47Algorithm()
|
||||
|
||||
def ADD_COMP_CHECKSUMS = false
|
||||
|
||||
@ -1225,137 +1224,6 @@ class A2PackPartitions
|
||||
static int lx47Total = 0
|
||||
static int lx47Savings = 0
|
||||
|
||||
// Transform the LZ4 format to something we call "LZ4M", where the small offsets are stored
|
||||
// as one byte instead of two. In our data, that's about 1/3 of the offsets.
|
||||
//
|
||||
def testLx47(inData, inLen, lz4Len)
|
||||
{
|
||||
def lx47 = new Lx47Algorithm()
|
||||
def inputData = new byte[inLen]
|
||||
System.arraycopy(inData, 0, inputData, 0, inLen)
|
||||
def outputData = lx47.compress(inputData)
|
||||
def savings = lz4Len - outputData.length
|
||||
if (savings >= 8) {
|
||||
//def uncomp = new byte[inLen]
|
||||
//lx47.decompress(outputData, 0, uncomp, 0, inLen)
|
||||
//assert uncomp == inputData
|
||||
|
||||
// Verify the stream comes out right with overlapped decompression
|
||||
def underlap = 2
|
||||
def buf = new byte[inLen+underlap]
|
||||
def initialOffset = inLen - outputData.length + underlap;
|
||||
System.arraycopy(outputData, 0, buf, initialOffset, outputData.length)
|
||||
lx47.decompress(buf, initialOffset, buf, 0, inLen)
|
||||
def uncomp = Arrays.copyOfRange(buf, 0, inLen)
|
||||
assert uncomp == inputData
|
||||
|
||||
uncompTotal += inLen
|
||||
lx47Savings += savings
|
||||
lz4Total += lz4Len
|
||||
lx47Total += outputData.length
|
||||
println String.format("lz47 usize=%d savings=%d utot=%d lz4tot=%d lx47tot=%d total_savings=%d",
|
||||
inLen, savings, uncompTotal, lz4Total, lx47Total, lx47Savings)
|
||||
}
|
||||
else {
|
||||
println String.format("lz47 usize=%d savings=%d SKIP", inLen, savings)
|
||||
}
|
||||
}
|
||||
|
||||
// Transform the LZ4 format to something we call "LZ4M", where the small offsets are stored
|
||||
// as one byte instead of two. In our data, that's about 1/3 of the offsets.
|
||||
//
|
||||
def recompress(data, inLen, uncompData, uncompLen)
|
||||
{
|
||||
def outLen = 0
|
||||
def sp = 0
|
||||
def dp = 0
|
||||
def cksum = 0
|
||||
while (true)
|
||||
{
|
||||
assert dp <= sp
|
||||
|
||||
// First comes the token: 4 bits literal len, 4 bits match len
|
||||
def token = data[dp++] = (data[sp++] & 0xFF)
|
||||
def matchLen = token & 0xF
|
||||
def literalLen = token >> 4
|
||||
|
||||
// The literal length might get extended
|
||||
if (literalLen == 15) {
|
||||
while (true) {
|
||||
token = data[dp++] = (data[sp++] & 0xFF)
|
||||
literalLen += token
|
||||
if (token != 0xFF)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (debugCompression)
|
||||
println String.format("Literal: ptr=\$%x, len=\$%x.", sp, literalLen)
|
||||
|
||||
// Copy the literal bytes
|
||||
outLen += literalLen
|
||||
for ( ; literalLen > 0; --literalLen) {
|
||||
cksum ^= data[sp]
|
||||
data[dp++] = data[sp++]
|
||||
}
|
||||
|
||||
// The last block has only literals, and no match
|
||||
if (sp == inLen)
|
||||
break
|
||||
|
||||
// Grab the offset
|
||||
token = data[sp++] & 0xFF
|
||||
def offset = token | ((data[sp++] & 0xFF) << 8)
|
||||
|
||||
// Re-encode the offset using 1 byte if possible
|
||||
assert offset < 32768
|
||||
if (offset < 128)
|
||||
data[dp++] = offset
|
||||
else {
|
||||
data[dp++] = (offset & 0x7F) | 0x80
|
||||
data[dp++] = (offset >> 7) & 0xFF
|
||||
}
|
||||
|
||||
// If checksums are enabled, output the checksum so far
|
||||
if (offset < 128 && ADD_COMP_CHECKSUMS) {
|
||||
if (debugCompression)
|
||||
println String.format(" [chksum=\$%x]", cksum & 0xFF)
|
||||
data[dp++] = (byte) cksum
|
||||
}
|
||||
|
||||
// The match length might get extended
|
||||
if (matchLen == 15) {
|
||||
while (true) {
|
||||
token = data[dp++] = (data[sp++] & 0xFF)
|
||||
matchLen += token
|
||||
if (token != 0xFF)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
matchLen += 4 // min match length is 4
|
||||
|
||||
if (debugCompression)
|
||||
println String.format("Match: offset=\$%x, len=\$%x.", offset, matchLen)
|
||||
|
||||
// We do nothing with the match bytes except add them to the checksum
|
||||
(0..<matchLen).each {
|
||||
cksum ^= uncompData[outLen]
|
||||
++outLen
|
||||
}
|
||||
}
|
||||
|
||||
// If checksums are enabled, output the final checksum
|
||||
if (ADD_COMP_CHECKSUMS) {
|
||||
if (debugCompression)
|
||||
println String.format("Final cksum: \$%x", cksum & 0xFF)
|
||||
data[dp++] = (byte) cksum
|
||||
}
|
||||
|
||||
assert outLen == uncompLen
|
||||
return dp
|
||||
}
|
||||
|
||||
def compressionSavings = 0
|
||||
|
||||
def compress(buf)
|
||||
@ -1364,30 +1232,25 @@ class A2PackPartitions
|
||||
def uncompressedLen = buf.position()
|
||||
def uncompressedData = unwrapByteBuffer(buf)
|
||||
|
||||
// Now compress it with LZ4
|
||||
// Now compress it with LX47
|
||||
assert uncompressedLen < 327678 : "data block too big"
|
||||
assert uncompressedLen > 0
|
||||
def maxCompressedLen = compressor.maxCompressedLength(uncompressedLen)
|
||||
def compressedData = new byte[maxCompressedLen]
|
||||
def compressedLen = compressor.compress(uncompressedData, 0, uncompressedLen,
|
||||
compressedData, 0, maxCompressedLen)
|
||||
def compressedData = compressor.compress(uncompressedData)
|
||||
def compressedLen = compressedData.length
|
||||
assert compressedLen > 0
|
||||
|
||||
// Then recompress to LZ4M (pretty much always smaller)
|
||||
def recompressedLen = recompress(compressedData, compressedLen, uncompressedData, uncompressedLen)
|
||||
//testLx47(uncompressedData, uncompressedLen, recompressedLen)
|
||||
|
||||
// If we saved at least 20 bytes, take the compressed version.
|
||||
if ((uncompressedLen - recompressedLen) >= 20) {
|
||||
// If we saved at least 10 bytes, take the compressed version.
|
||||
println "TODO: Put back compression"
|
||||
if (false && (uncompressedLen - compressedLen) >= 10) {
|
||||
if (debugCompression)
|
||||
println String.format(" Compress. rawLen=\$%x compLen=\$%x", uncompressedLen, recompressedLen)
|
||||
compressionSavings += (uncompressedLen - recompressedLen) - 2 - (ADD_COMP_CHECKSUMS ? 1 : 0)
|
||||
return [data:compressedData, len:recompressedLen,
|
||||
println String.format(" Compress. rawLen=\$%x compLen=\$%x", uncompressedLen, compressedLen)
|
||||
compressionSavings += (uncompressedLen - compressedLen) - 2 - (ADD_COMP_CHECKSUMS ? 1 : 0)
|
||||
return [data:compressedData, len:compressedLen,
|
||||
compressed:true, uncompressedLen:uncompressedLen]
|
||||
}
|
||||
else {
|
||||
if (debugCompression)
|
||||
println String.format(" No compress. rawLen=\$%x compLen=\$%x", uncompressedLen, recompressedLen)
|
||||
println String.format(" No compress. rawLen=\$%x compLen=\$%x", uncompressedLen, compressedLen)
|
||||
return [data:uncompressedData, len:uncompressedLen, compressed:false]
|
||||
}
|
||||
}
|
||||
@ -1470,8 +1333,7 @@ class A2PackPartitions
|
||||
def prevUserDir = System.getProperty("user.dir")
|
||||
def result
|
||||
def errBuf = new ByteArrayOutputStream()
|
||||
println "Nested: prog=$programName inDir=$inDir inDir=$inDir inFile=$inFile outFile=$outFile"
|
||||
try
|
||||
try
|
||||
{
|
||||
System.setProperty("user.dir", new File(inDir).getAbsolutePath())
|
||||
if (inFile) {
|
||||
@ -1625,14 +1487,13 @@ class A2PackPartitions
|
||||
{
|
||||
if (binaryStubsOnly)
|
||||
return addToCache("sysCode", sysCode, "core", 1, ByteBuffer.allocate(1))
|
||||
|
||||
|
||||
// Read in all the parts of the LegendOS core system and combine them together
|
||||
// with block headers.
|
||||
inDir = "build/" + inDir
|
||||
new File(inDir + "build").mkdirs()
|
||||
println "Created dir ${new File(inDir + "build")}"
|
||||
def outBuf = ByteBuffer.allocate(50000)
|
||||
def compressor = new Lx47Algorithm()
|
||||
["loader", "decomp", "PRORWTS", "PLVM02", "mem"].each { name ->
|
||||
def code
|
||||
if (name == "PRORWTS")
|
||||
@ -1649,7 +1510,6 @@ class A2PackPartitions
|
||||
}
|
||||
code = sysCode[name].buf
|
||||
}
|
||||
println "Processing $name."
|
||||
def compressed = (name ==~ /loader|decomp/) ?
|
||||
code : wrapByteArray(compressor.compress(unwrapByteBuffer(code)))
|
||||
if (name != "loader") {
|
||||
@ -1663,7 +1523,7 @@ class A2PackPartitions
|
||||
compressed.flip()
|
||||
outBuf.put(compressed)
|
||||
}
|
||||
|
||||
|
||||
// Write out the result
|
||||
new File("build/src/core/build/LEGENDOS.SYSTEM.sys#2000").withOutputStream { stream ->
|
||||
stream.write(unwrapByteBuffer(outBuf))
|
||||
|
@ -19,7 +19,7 @@ public class Lx47Algorithm
|
||||
|
||||
void addDebug(String format, Object... arguments) {
|
||||
String str = String.format(format, arguments);
|
||||
System.out.println("Gen: " + str);
|
||||
//System.out.println("Gen: " + str);
|
||||
debugs.add(str);
|
||||
}
|
||||
|
||||
@ -419,7 +419,7 @@ public class Lx47Algorithm
|
||||
|
||||
chkDebug("EOF");
|
||||
}
|
||||
|
||||
|
||||
public byte[] compress(byte[] input_data) {
|
||||
if (false) {
|
||||
input_data = "hellohelloabchello".getBytes();
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -41,22 +41,11 @@ init ; Init pointer to blocks we're going to move/decompress
|
||||
lda #>dataStart
|
||||
sta pData+1
|
||||
; temporary: copy ROM so we can debug decompressor
|
||||
bit setLcWr ; read from ROM, write to LC ram
|
||||
bit setLcWr
|
||||
ldy #0
|
||||
sty pSrc
|
||||
ldx #$f8
|
||||
-- stx pSrc+1
|
||||
- lda (pSrc),y
|
||||
sta (pSrc),y
|
||||
iny
|
||||
bne -
|
||||
inx
|
||||
bne --
|
||||
; First is the decompressor itself (special: just copy one page)
|
||||
bit setLcWr+lcBank1 ; read from ROM, write to LC ram
|
||||
bit setLcWr+lcBank1
|
||||
jsr getBlk
|
||||
bit setLcRW+lcBank1 ; switch in target bank
|
||||
bit setLcRW+lcBank1
|
||||
- lda (pSrc),y
|
||||
.st sta decomp,y
|
||||
iny
|
||||
@ -74,6 +63,7 @@ runBlk jsr getBlk ; get block size and calc pointers
|
||||
}
|
||||
bit setLcRW+lcBank1
|
||||
jsr decomp ; decompress the code
|
||||
bit setLcWr+lcBank1
|
||||
!if DEBUG {
|
||||
lda #"R"
|
||||
jsr ROM_cout
|
||||
|
@ -27,10 +27,8 @@
|
||||
; Constants
|
||||
MAX_SEGS = 96
|
||||
|
||||
DO_COMP_CHECKSUMS = 0 ; during compression debugging
|
||||
DEBUG_DECOMP = 0
|
||||
DEBUG = 0
|
||||
SANITY_CHECK = 0 ; also prints out request data
|
||||
DEBUG = 1
|
||||
SANITY_CHECK = 1 ; also prints out request data
|
||||
|
||||
; Zero page temporary variables
|
||||
tmp = $2 ; len 2
|
||||
@ -43,10 +41,29 @@ isCompressed = $B ; len 1
|
||||
pSrc = $C ; len 2
|
||||
pDst = $E ; len 2
|
||||
ucLen = $10 ; len 2
|
||||
checksum = $12 ; len 1
|
||||
|
||||
plasmaNextOp = $F0 ; PLASMA's dispatch loop
|
||||
plasmaXTbl = $D300 ; op table for auXiliary code execution
|
||||
; Mapping of ProRWTS register names to mem mgr registers:
|
||||
; "status" -> tmp+1
|
||||
; "auxreq" -> isAuxCmd
|
||||
; "reqcmd" -> tmp
|
||||
; "sizelo"+hi -> reqLen
|
||||
; "ldrlo"+hi -> pDst
|
||||
; "namlo"+hi -> pSrc
|
||||
|
||||
lx47Decomp = $DF00
|
||||
|
||||
; ProRWTS constants
|
||||
cmdseek = 0
|
||||
cmdread = 1
|
||||
cmdwrite = 2
|
||||
|
||||
; ProRWTS locations
|
||||
reseek_0 = $18 ; to reset seek ptr, zero out these 3 locs
|
||||
reseek_1 = $1B
|
||||
reseek_2 = $1C
|
||||
proRWTS = $F600
|
||||
opendir = proRWTS
|
||||
rdwrpart = opendir+3
|
||||
|
||||
; Memory buffers
|
||||
fileBuf = $4000 ; len $400
|
||||
@ -63,21 +80,10 @@ gcHash_link = $5300
|
||||
gcHash_dstLo = $5400
|
||||
gcHash_dstHi = $5500
|
||||
|
||||
; Other equates
|
||||
prodosMemMap = $BF58
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
!macro callMLI cmd, parms {
|
||||
lda #cmd
|
||||
ldx #<parms
|
||||
ldy #>parms
|
||||
jsr _callMLI
|
||||
}
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Relocate all the pieces to their correct locations and perform patching.
|
||||
relocate:
|
||||
; put something interesting on the screen :)
|
||||
; Put something interesting on the screen :)
|
||||
jsr ROM_home
|
||||
ldy #0
|
||||
- lda .welcomeText,y
|
||||
@ -85,24 +91,27 @@ relocate:
|
||||
jsr ROM_cout
|
||||
iny
|
||||
bne -
|
||||
jmp +
|
||||
.welcomeText: !text "Welcome to LegendOS.",$8D,0
|
||||
+
|
||||
; special: clear most of the lower 48k
|
||||
; special: clear most of the lower 48k and the ProDOS bank of the LC
|
||||
+ bit setLcRW+lcBank1
|
||||
bit setLcRW+lcBank1
|
||||
ldy #0
|
||||
tya
|
||||
ldx #8
|
||||
.clr1 stx .clrst1+2
|
||||
stx .clrst2+2
|
||||
ldy #0
|
||||
tya
|
||||
.clrst1 sta $800,y
|
||||
.clrst2 sta $880,y
|
||||
iny
|
||||
bpl .clrst1
|
||||
inx
|
||||
cpx #$20
|
||||
cpx #$40 ; skip our own unrelocated code $4000.4FFF
|
||||
bne +
|
||||
ldx #$40
|
||||
+ cpx #$BF
|
||||
ldx #$50
|
||||
+ cpx #$C0 ; skip IO space $C000.CFFF
|
||||
bne +
|
||||
ldx #$D0
|
||||
+ cpx #$F6 ; skip ProRWTS $F600.FEFF, and ROM vecs $FF00.FFFF
|
||||
bne .clr1
|
||||
|
||||
; first our lo memory piece goes to $800
|
||||
@ -116,9 +125,6 @@ relocate:
|
||||
inc .lost+2
|
||||
dex
|
||||
bne .lold
|
||||
; set up to copy the ProDOS code from main memory to aux
|
||||
bit setLcRW+lcBank1 ; only copy bank 1, because bank 2 is PLASMA runtime
|
||||
bit setLcRW+lcBank1 ; write to it
|
||||
; verify that aux mem exists
|
||||
inx
|
||||
stx $D000
|
||||
@ -134,50 +140,8 @@ relocate:
|
||||
cpx $D000
|
||||
beq .gotaux
|
||||
.noaux jsr inlineFatal : !text "AuxMemReq",0
|
||||
.gotaux ldx #$D0
|
||||
.pglup stx .ld+2
|
||||
stx .st+2
|
||||
sei
|
||||
.bylup sta clrAuxZP ; get byte from main LC
|
||||
.ld lda $D000,y
|
||||
sta setAuxZP ; temporarily turn on aux LC
|
||||
.st sta $D000,y
|
||||
iny
|
||||
bne .bylup
|
||||
inx ; all pages until we hit $00
|
||||
bne .pglup
|
||||
cli
|
||||
sta clrAuxZP ; ...back to main LC
|
||||
; patch into the main ProDOS MLI entry point
|
||||
ldx #$4C ; jmp
|
||||
stx $BFBB
|
||||
lda #<enterProDOS1
|
||||
sta $BFBC
|
||||
lda #>enterProDOS1
|
||||
sta $BFBD
|
||||
; patch into the interrupt handler
|
||||
stx $BFEB
|
||||
lda #<enterProDOS2
|
||||
sta $BFEC
|
||||
lda #>enterProDOS2
|
||||
sta $BFED
|
||||
; patch into the shared MLI/IRQ exit routine
|
||||
stx $BFA0
|
||||
lda #<exitProDOS
|
||||
sta $BFA1
|
||||
lda #>exitProDOS
|
||||
sta $BFA2
|
||||
; now blow away the main RAM LC area as a check
|
||||
ldx #$D0
|
||||
tya
|
||||
.clrlup stx .st2+2
|
||||
.st2 sta $D000,Y
|
||||
iny
|
||||
bne .st2
|
||||
inx
|
||||
bne .clrlup
|
||||
; Copy the vectors
|
||||
ldx #6
|
||||
; Copy the 6502 ROM vectors
|
||||
.gotaux ldx #5
|
||||
bit setLcWr+lcBank1 ; read from ROM, write to LC RAM
|
||||
- lda $FFFA,x
|
||||
sta $FFFA,x
|
||||
@ -192,7 +156,7 @@ relocate:
|
||||
sta $FFFE
|
||||
lda #>brkHandler
|
||||
sta $FFFF
|
||||
; Place the bulk of the memory manager code into the newly cleared LC
|
||||
; Place the bulk of the memory manager code into the LC
|
||||
ldx #>hiMemBegin
|
||||
.cpmm stx .ld4+2
|
||||
.ld4 lda hiMemBegin,y
|
||||
@ -217,30 +181,12 @@ init: !zone
|
||||
lda #$B
|
||||
sta $c0ab
|
||||
+ ; END OF KLUDGE
|
||||
; grab the prefix of the current drive
|
||||
lda #<prodosPrefix
|
||||
sta getPfxAddr
|
||||
lda #>prodosPrefix
|
||||
sta getPfxAddr+1
|
||||
+callMLI MLI_GET_PREFIX, getPfxParams
|
||||
bcc +
|
||||
jmp prodosError
|
||||
+ lda prodosPrefix
|
||||
and #$F ; strip off drive/slot, keep string len
|
||||
sta prodosPrefix
|
||||
; switch in mem mgr
|
||||
bit setLcRW+lcBank1
|
||||
bit setLcRW+lcBank1
|
||||
; close all files
|
||||
lda #0
|
||||
jsr closeFile
|
||||
; clear ProDOS mem map so it lets us load stuff anywhere we want
|
||||
ldx #$18
|
||||
lda #0
|
||||
.clr: sta prodosMemMap-1,x
|
||||
dex
|
||||
bne .clr
|
||||
; clear the segment tables
|
||||
lda #0
|
||||
tax
|
||||
- sta tSegLink,x
|
||||
sta tSegAdrLo,x
|
||||
sta tSegAdrHi,x
|
||||
@ -252,7 +198,7 @@ init: !zone
|
||||
; clear other pointers
|
||||
sta targetAddr+1
|
||||
sta scanStart
|
||||
sta partFileRef
|
||||
sta partFileOpen
|
||||
sta curPartition
|
||||
lda #<diskLoader
|
||||
sta nextLdVec+1
|
||||
@ -477,64 +423,6 @@ fatalError: !zone
|
||||
jsr ROM_bell
|
||||
.hang: jmp .hang ; loop forever
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Normal entry point for ProDOS MLI calls. This patches the code at $BFBB.
|
||||
enterProDOS1: !zone
|
||||
pla ; saved A reg
|
||||
sta .ld2+1
|
||||
pla ; lo byte of ret addr
|
||||
sta .ld1+1
|
||||
pla ; hi byte of ret addr
|
||||
sta setAuxZP ; switch to aux stack/ZP/LC
|
||||
pha ; hi byte of ret addr
|
||||
.ld1 lda #11 ; self-modified earlier
|
||||
pha ; lo byte of ret addr
|
||||
.ld2 lda #11 ; saved A reg
|
||||
pha
|
||||
lda $E000 ; this is what the original code at $BFBB did
|
||||
jmp $BFBE ; jump back in where ProDOS enter left off
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Entry point for ProDOS interrupt handler. This patches the code at $BFEB.
|
||||
enterProDOS2: !zone
|
||||
pla ; saved P reg
|
||||
sta .ld2+1
|
||||
pla ; ret addr lo
|
||||
sta .ld1+1
|
||||
pla ; ret addr hi
|
||||
sta setAuxZP ; switch to aux stack/ZP/LC
|
||||
pha
|
||||
.ld1 lda #11 ; self-modified earlier
|
||||
pha
|
||||
.ld2 lda #11 ; ditto
|
||||
pha
|
||||
bit $C08B ; this is what the original code at $BFEB did
|
||||
jmp $BFEE ; back to where ProDOS left off
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Shared exit point for ProDOS MLI and IRQ handlers. This patches the code
|
||||
; at $BFA0.
|
||||
exitProDOS: !zone
|
||||
; pop data from AUX stack
|
||||
pla ; saved A reg
|
||||
sta .ld3+1
|
||||
pla ; P-reg for RTI
|
||||
sta .ld2+1
|
||||
pla ; hi byte of ret addr
|
||||
sta .ld1+1
|
||||
pla ; lo byte of ret addr
|
||||
; push data to MAIN stack
|
||||
sta clrAuxZP ; back to main stack/ZP/LC
|
||||
pha ; lo byte of ret addr
|
||||
.ld1 lda #11 ; self-modified earlier
|
||||
pha ; hi byte of ret addr
|
||||
.ld2 lda #11 ; ditto
|
||||
pha ; P-reg for RTI
|
||||
.ld3 lda #11 ; self-modified earlier (the saved A reg)
|
||||
; Note! We leave LC bank 1 enabled, since that's where the memory
|
||||
; manager lives, and it's the only code that calls ProDOS.
|
||||
rti ; RTI pops P-reg and *exact* return addr (not adding 1)
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; BRK and IRQ handler: switch to ROM, call default handler, switch back
|
||||
brkHandler:
|
||||
@ -790,44 +678,8 @@ __internalErr: !zone {
|
||||
; Space (in main RAM) for saving the state of the LC bank switch
|
||||
savedLCBnk2State !byte 0
|
||||
|
||||
; Call MLI from main memory rather than LC, since it lives in aux LC.
|
||||
_callMLI: sta .cmd
|
||||
stx .params
|
||||
sty .params+1
|
||||
jsr mli
|
||||
.cmd !byte 0
|
||||
.params !word 0
|
||||
rts
|
||||
|
||||
; Our ProDOS param blocks can't be in LC ram
|
||||
openParams: !byte 3 ; param count
|
||||
!word filename ; pointer to file name
|
||||
!word fileBuf ; pointer to buffer
|
||||
openFileRef: !byte 0 ; returned file number
|
||||
|
||||
; ProDOS prefix of the boot disk
|
||||
prodosPrefix: !fill 16
|
||||
|
||||
; Buffer for forming the full filename
|
||||
filename: !fill 28 ; 16 for prefix plus 11 for "/GAME.PART.1"
|
||||
|
||||
readParams: !byte 4 ; param count
|
||||
readFileRef: !byte 0 ; file ref to read
|
||||
readAddr: !word 0
|
||||
readLen: !word 0
|
||||
readGot: !word 0
|
||||
|
||||
setMarkParams: !byte 2 ; param count
|
||||
setMarkFileRef: !byte 0 ; file reference to set mark in
|
||||
setMarkPos: !byte 0 ; mark position (3 byte integer)
|
||||
!byte 0
|
||||
!byte 0
|
||||
|
||||
closeParams: !byte 1 ; param count
|
||||
closeFileRef: !byte 0 ; file ref to close
|
||||
|
||||
getPfxParams: !byte 1 ; param count
|
||||
getPfxAddr: !word 0 ; pointer to buffer
|
||||
filename: !fill 12 ; 1 for len plus 11 for "GAME.PART.1"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Heap management routines
|
||||
@ -1101,12 +953,10 @@ gc2_sweep: !zone
|
||||
rts
|
||||
|
||||
closePartFile: !zone
|
||||
lda partFileRef ; close the partition file
|
||||
lda partFileOpen ; check if open
|
||||
beq .done
|
||||
!if DEBUG { +prStr : !text "ClosePart.",0 }
|
||||
jsr closeFile
|
||||
lda #0 ; zero out...
|
||||
sta partFileRef ; ... the file reference so we know it's no longer open
|
||||
dec partFileOpen
|
||||
.done rts
|
||||
|
||||
heapCollect: !zone
|
||||
@ -1233,10 +1083,11 @@ scanStart: !byte 0, 1 ; main, aux
|
||||
segNum: !byte 0
|
||||
nextLdVec: jmp diskLoader
|
||||
curPartition: !byte 0
|
||||
partFileRef: !byte 0
|
||||
partFileOpen: !byte 0
|
||||
curMarkPos: !fill 3
|
||||
setMarkPos: !fill 3
|
||||
nSegsQueued: !byte 0
|
||||
bufferDigest: !fill 4
|
||||
multiDiskMode: !byte 0 ; hardcoded to YES for now
|
||||
diskActState: !byte 0
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
@ -2071,27 +1922,9 @@ calcBufferDigest: !zone
|
||||
;------------------------------------------------------------------------------
|
||||
openPartition: !zone
|
||||
!if DEBUG { +prStr : !text "OpenPart ",0 : +prByte curPartition : +crout }
|
||||
; complete the partition file name, changing "1" to "2" if we're in multi-disk mode
|
||||
; and opening partition 2.
|
||||
.mkname ldx #1
|
||||
; complete the partition file name, changing "1" to "2" if opening partition 2.
|
||||
.mkname ldx #0
|
||||
ldy #1
|
||||
- lda prodosPrefix,x
|
||||
sta filename,y
|
||||
cmp #$31 ; "1"
|
||||
bne +
|
||||
lda multiDiskMode
|
||||
beq + ; don't change if single-disk mode
|
||||
lda curPartition
|
||||
cmp #2
|
||||
bcc +
|
||||
lda #$32 ; "2"
|
||||
sta filename,y
|
||||
+ cpx prodosPrefix ; done with full length of prefix?
|
||||
beq +
|
||||
inx
|
||||
iny
|
||||
bne - ; always taken
|
||||
+ ldx #0
|
||||
- lda .fileStr,x
|
||||
beq +++
|
||||
cmp #$31 ; "1"
|
||||
@ -2108,39 +1941,41 @@ openPartition: !zone
|
||||
+++ dey
|
||||
sty filename ; total length
|
||||
; open the file
|
||||
.open +callMLI MLI_OPEN, openParams
|
||||
bcc .opened
|
||||
cmp #$46 ; file not found?
|
||||
bne +
|
||||
lda #1 ; enter into
|
||||
sta multiDiskMode ; multi-disk mode
|
||||
bne .mkname ; and retry
|
||||
+ cmp #$45 ; volume not found?
|
||||
beq .insert ; ask user to insert the disk
|
||||
jmp prodosError ; no, misc error - print it and die
|
||||
; grab the file number, since we're going to keep it open
|
||||
.opened lda openFileRef
|
||||
sta partFileRef
|
||||
sta readFileRef
|
||||
; Read the first two bytes, which tells us how long the header is.
|
||||
.open lda #<filename
|
||||
sta pSrc
|
||||
lda #>filename
|
||||
sta pSrc+1
|
||||
lda #<headerBuf
|
||||
sta readAddr
|
||||
sta pDst
|
||||
lda #>headerBuf
|
||||
sta readAddr+1
|
||||
lda #2
|
||||
sta readLen
|
||||
sta pDst+1
|
||||
lda #2 ; read 2 bytes (which will tell us how long the header is)
|
||||
sta reqLen
|
||||
lda #0
|
||||
sta readLen+1
|
||||
jsr readToMain
|
||||
lda headerBuf ; grab header size
|
||||
sta readLen ; set to read that much. Will actually get 2 extra bytes,
|
||||
; but that's no biggie.
|
||||
sta reqLen+1
|
||||
lda #0 ; cmdread, for drive 1
|
||||
sta tmp
|
||||
jsr opendir
|
||||
lda tmp+1 ; get status
|
||||
bne .insert ; zero=ok, 1=err
|
||||
jsr disk_reseek ; by opening, we did an implicit seek
|
||||
lda #2 ; and we read 2 bytes
|
||||
sta curMarkPos
|
||||
; read the full header
|
||||
.opened lda headerBuf ; grab header size
|
||||
sec
|
||||
sbc #2 ; minus size of the size
|
||||
sta reqLen ; set to read that much.
|
||||
lda headerBuf+1 ; hi byte too
|
||||
sta readLen+1
|
||||
lda #2 ; read just after the 2-byte length
|
||||
sta readAddr
|
||||
jmp readToMain ; finish by reading the rest of the header
|
||||
sbc #0
|
||||
sta reqLen+1
|
||||
lda #<headerBuf
|
||||
sta pDst
|
||||
lda #>headerBuf
|
||||
sta pDst+1
|
||||
jmp disk_read
|
||||
; ask user to insert the disk
|
||||
; TODO: handle dual drive configuration
|
||||
.insert +safeHome
|
||||
+prStr : !text "Insert disk ",0
|
||||
bit $c051
|
||||
@ -2152,34 +1987,15 @@ openPartition: !zone
|
||||
+safeHome
|
||||
bit $c050
|
||||
jmp .open ; try again
|
||||
.fileStr !raw "/GAME.PART.1",0 ; 'raw' chars to get lo-bit ascii that ProDOS likes.
|
||||
.fileStr !raw "GAME.PART.1",0 ; 'raw' chars to get lo-bit ascii that ProDOS likes.
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
sequenceError: !zone
|
||||
jsr inlineFatal : !text "BadSeq", 0
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
prodosError: !zone
|
||||
pha
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
jsr .digit
|
||||
sta .num
|
||||
pla
|
||||
jsr .digit
|
||||
sta .num+1
|
||||
jsr inlineFatal
|
||||
.msg: !text "ProDOSErr $"
|
||||
.num: !text "xx"
|
||||
!byte 0
|
||||
.digit: and #$F
|
||||
ora #$B0
|
||||
cmp #$BA
|
||||
bcc +
|
||||
adc #6
|
||||
+ rts
|
||||
diskError: !zone
|
||||
jsr inlineFatal : !text "DskErr", 0
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
disk_startLoad: !zone
|
||||
@ -2188,7 +2004,7 @@ disk_startLoad: !zone
|
||||
cpx curPartition ; switching partition?
|
||||
stx curPartition ; (and store the new part num in any case)
|
||||
bne .new ; if different, close the old one
|
||||
lda partFileRef
|
||||
lda partFileOpen
|
||||
beq .done ; if nothing already open, we're okay with that.
|
||||
jsr calcBufferDigest ; same partition - check that buffers are still intact
|
||||
beq .done ; if correct partition file already open, we're done.
|
||||
@ -2211,7 +2027,7 @@ disk_queueLoad: !zone
|
||||
lda #$FF
|
||||
jsr showDiskActivity ; graphical marker that disk activity happening
|
||||
inc nSegsQueued ; record the fact that we're queuing a seg
|
||||
lda partFileRef ; check if we've opened the file yet
|
||||
lda partFileOpen ; check if we've opened the file yet
|
||||
bne + ; yes, don't re-open
|
||||
jsr openPartition ; open the partition file
|
||||
+ jsr startHeaderScan ; start scanning the partition header
|
||||
@ -2285,20 +2101,85 @@ disk_queueLoad: !zone
|
||||
jsr adjYpTmp ; keep it small
|
||||
+ jmp .scan ; go for more
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
disk_reseek: !zone
|
||||
lda #0
|
||||
sta reseek_0 ; rewind the ProRWTS seek pointer
|
||||
sta reseek_1
|
||||
sta reseek_2
|
||||
sta curMarkPos
|
||||
sta curMarkPos+1
|
||||
sta curMarkPos+2
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
disk_seek: !zone
|
||||
lda #cmdseek
|
||||
sta tmp
|
||||
lda setMarkPos
|
||||
sec
|
||||
sbc curMarkPos
|
||||
sta reqLen
|
||||
lda setMarkPos+1
|
||||
sbc curMarkPos+1
|
||||
sta reqLen+1
|
||||
lda setMarkPos+2
|
||||
sbc curMarkPos+2
|
||||
bmi .back
|
||||
bne .far
|
||||
jmp rdwrpart
|
||||
.back jsr disk_reseek
|
||||
jmp disk_seek
|
||||
.far lda #$FF
|
||||
sta reqLen
|
||||
sta reqLen+1
|
||||
jsr rdwrpart
|
||||
lda #$FF
|
||||
tax
|
||||
jsr adjMark
|
||||
jmp disk_seek
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
adjMark: !zone
|
||||
clc
|
||||
adc curMarkPos
|
||||
sta curMarkPos
|
||||
txa
|
||||
adc curMarkPos+1
|
||||
sta curMarkPos+1
|
||||
bcc +
|
||||
inc curMarkPos+2
|
||||
+ rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
disk_read: !zone
|
||||
lda #cmdread
|
||||
sta tmp
|
||||
lda reqLen
|
||||
pha
|
||||
lda reqLen+1
|
||||
pha
|
||||
jsr rdwrpart
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
jsr adjMark
|
||||
+ lda tmp+1
|
||||
bne .err
|
||||
rts
|
||||
.err jmp diskError
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
disk_finishLoad: !zone
|
||||
lda nSegsQueued ; see if we actually queued anything
|
||||
beq .done ; if nothing queued, we're done
|
||||
lda partFileRef
|
||||
sta setMarkFileRef ; copy the file ref number to our MLI param blocks
|
||||
sta readFileRef
|
||||
lda headerBuf ; grab # header bytes
|
||||
sta setMarkPos ; set to start reading at first non-header byte in file
|
||||
lda headerBuf+1 ; hi byte too
|
||||
lda headerBuf ; grab # header bytes
|
||||
sta setMarkPos ; set to start reading at first non-header byte in file
|
||||
lda headerBuf+1 ; hi byte too
|
||||
sta setMarkPos+1
|
||||
lda #0
|
||||
sta setMarkPos+2
|
||||
sta .nFixups
|
||||
sta .nFixups ; might as well clear fixup count while we're at it
|
||||
jsr startHeaderScan ; start scanning the partition header
|
||||
.scan: lda (pTmp),y ; get resource type byte
|
||||
bne .notdone ; zero = end of header
|
||||
@ -2353,13 +2234,12 @@ disk_finishLoad: !zone
|
||||
+ sta ucLen+1 ; save uncomp len hi byte
|
||||
jsr scanForResource ; find the segment number allocated to this resource
|
||||
beq .addrErr ; it better have been allocated
|
||||
jsr disk_seek ; move the file pointer to the current block
|
||||
lda tSegAdrLo,x ; grab the address
|
||||
sta pDst ; and save it to the dest point for copy or decompress
|
||||
lda tSegAdrHi,x ; hi byte too
|
||||
sta pDst+1
|
||||
!if DEBUG { jsr .debug2 }
|
||||
+callMLI MLI_SET_MARK, setMarkParams ; move the file pointer to the current block
|
||||
bcs .prodosErr
|
||||
!if DEBUG >= 3 { +prStr : !text "Deco.",0 }
|
||||
jsr lz4Decompress ; decompress (or copy if uncompressed)
|
||||
!if DEBUG >= 3 { +prStr : !text "Done.",0 }
|
||||
@ -2382,8 +2262,6 @@ disk_finishLoad: !zone
|
||||
bpl + ; if Y index is is small, no need to adjust
|
||||
jsr adjYpTmp ; adjust pTmp and Y to make it small again
|
||||
+ jmp .scan ; back for more
|
||||
.prodosErr:
|
||||
jmp prodosError
|
||||
.addrErr:
|
||||
jmp invalParam
|
||||
|
||||
@ -2426,323 +2304,10 @@ adjYpTmp: !zone
|
||||
inc pTmp+1 ; go to next page
|
||||
+ rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
closeFile: !zone
|
||||
sta closeFileRef
|
||||
+callMLI MLI_CLOSE, closeParams
|
||||
bcs .prodosErr
|
||||
rts
|
||||
.prodosErr:
|
||||
jmp prodosError
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
readToMain: !zone
|
||||
+callMLI MLI_READ, readParams
|
||||
bcs .err
|
||||
rts
|
||||
.err: jmp prodosError
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
readToBuf: !zone
|
||||
; Read as much data as we can, up to min(compLen, bufferSize) into the diskBuf.
|
||||
lda #0
|
||||
sta readAddr ; buffer addr always on even page boundary
|
||||
sta pSrc
|
||||
lda #>diskBuf ; we're reading into a buffer in main mem
|
||||
sta readAddr+1
|
||||
sta pSrc+1 ; restart src pointer at start of buffer
|
||||
.nextGroup:
|
||||
ldx reqLen
|
||||
lda reqLen+1 ; see how many pages we want
|
||||
cmp #>DISK_BUF_SIZE ; less than our max?
|
||||
bcc + ; yes, read exact amount
|
||||
lda #>DISK_BUF_SIZE ; no, limit to size of buffer
|
||||
ldx #0
|
||||
+ stx readLen
|
||||
sta readLen+1 ; save number of pages
|
||||
jsr readToMain ; now read
|
||||
lda reqLen ; decrement reqLen by the amount we read
|
||||
sec
|
||||
sbc readLen
|
||||
sta reqLen
|
||||
lda reqLen+1 ; all 16 bits of reqLen
|
||||
sbc readLen+1
|
||||
sta reqLen+1
|
||||
ldy #0 ; index for reading first byte
|
||||
rts ; all done
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
lz4Decompress: !zone
|
||||
; Input: pSrc - pointer to source data
|
||||
; pDst - pointer to destination buffer
|
||||
; ucLen - length of *destination* data (16-bit)
|
||||
; isCompressed - if hi bit set, decompress; if not, just copy.
|
||||
; All inputs are destroyed by the process.
|
||||
|
||||
!macro LOAD_YSRC {
|
||||
lda (pSrc),y ; load byte
|
||||
iny ; inc low byte of ptr
|
||||
bne + ; non-zero, done
|
||||
jsr nextSrcPage ; zero, need to go to next page
|
||||
+
|
||||
}
|
||||
|
||||
!if DEBUG_DECOMP { jsr .debug1 }
|
||||
jsr readToBuf ; read first pages into buffer
|
||||
ldx #<clrAuxWr ; start by assuming write to main mem
|
||||
ldy #<clrAuxRd ; and read from main mem
|
||||
lda isAuxCmd ; if we're decompressing to aux...
|
||||
beq + ; no? keep those values
|
||||
inx ; yes, write to aux mem
|
||||
iny ; and read from aux mem
|
||||
+ stx .auxWr1+1 ; set all the write switches for aux/main
|
||||
stx .auxWr3+1
|
||||
stx .auxWr2+1
|
||||
sty .auxRd1+1 ; and the read switches too
|
||||
+ ldx pDst ; calculate the end of the dest buffer
|
||||
txa ; also put low byte of ptr in X (where we'll use it constantly)
|
||||
clc
|
||||
adc ucLen ; add in the uncompressed length
|
||||
sta .endChk1+1 ; that's what we'll need to check to see if we're done
|
||||
lda ucLen+1 ; grab, but don't add, hi byte of dest length
|
||||
adc #0 ; no, we don't add pDst+1 - see endChk2
|
||||
sta .endChk2+1 ; this is essentially a count of dest page bumps
|
||||
lda pDst+1 ; grab the hi byte of dest pointer
|
||||
sta .dstStore1+2 ; self-modify our storage routines
|
||||
sta .dstStore2+2
|
||||
ldy pSrc ; Y will always track the hi byte of the source ptr
|
||||
lda #0 ; so zero out the low byte of the ptr itself
|
||||
sta pSrc
|
||||
!if DO_COMP_CHECKSUMS {
|
||||
sta checksum
|
||||
}
|
||||
bit isCompressed ; check compression flag
|
||||
bpl .goLit ; not compressed? Treat as a single literal sequence.
|
||||
sta ucLen+1 ; ucLen+1 always needs to be zero
|
||||
; Grab the next token in the compressed data
|
||||
.getToken:
|
||||
+LOAD_YSRC ; load next source byte
|
||||
pha ; save the token byte. We use half now, and half later
|
||||
lsr ; shift to get the hi 4 bits...
|
||||
lsr
|
||||
lsr ; ...into the lo 4 bits
|
||||
lsr
|
||||
beq .endChk1 ; if ucLen=0, there is no literal data.
|
||||
cmp #$F ; ucLen=15 is a special marker
|
||||
bcc + ; not special, go copy the literals
|
||||
jsr .longLen ; special marker: extend the length
|
||||
+ sta ucLen ; record resulting length (lo byte)
|
||||
.goLit:
|
||||
!if DEBUG_DECOMP { jsr .debug2 }
|
||||
+
|
||||
.auxWr1 sta setAuxWr ; this gets self-modified depending on if target is in main or aux mem
|
||||
.litCopy: ; loop to copy the literals
|
||||
+LOAD_YSRC ; grab a literal source byte
|
||||
.dstStore1:
|
||||
sta $1100,x ; hi-byte gets self-modified to point to dest page
|
||||
!if DO_COMP_CHECKSUMS {
|
||||
eor checksum
|
||||
sta checksum
|
||||
}
|
||||
inx ; inc low byte of ptr
|
||||
bne + ; non-zero, done
|
||||
jsr .nextDstPage ; zero, need to go to next page
|
||||
+ dec ucLen ; count bytes
|
||||
bne + ; low count = 0?
|
||||
lda ucLen+1 ; hi count = 0?
|
||||
beq .endChk ; both zero - end of loop
|
||||
+ lda ucLen ; did low byte wrap around?
|
||||
cmp #$FF
|
||||
bne .litCopy ; no, go again
|
||||
dec ucLen+1 ; yes, decrement hi byte
|
||||
jmp .litCopy ; and go again
|
||||
.endChk sta clrAuxWr ; back to writing main mem
|
||||
.endChk1:
|
||||
cpx #11 ; end check - self-modified earlier
|
||||
bcc .decodeMatch ; if less, keep going
|
||||
.endChk2:
|
||||
lda #0 ; have we finished all pages? - self modified and decremented
|
||||
bmi .endBad ; negative? that's very bad (because we never have blocks >= 32Kbytes)
|
||||
bne .decodeMatch ; non-zero? keep going.
|
||||
bit isCompressed
|
||||
bpl + ; if not compressed, no extra work at end
|
||||
pla ; toss unused match length
|
||||
!if DO_COMP_CHECKSUMS { jsr .verifyCksum }
|
||||
+ rts ; all done!
|
||||
.endBad +internalErr 'O' ; barf out
|
||||
; Now that we've finished with the literals, decode the match section
|
||||
.decodeMatch:
|
||||
+LOAD_YSRC ; grab first byte of match offset
|
||||
sta tmp ; save for later
|
||||
cmp #0
|
||||
bmi .far ; if hi bit is set, there will be a second byte
|
||||
!if DO_COMP_CHECKSUMS { jsr .verifyCksum }
|
||||
lda #0 ; otherwise, second byte is assumed to be zero
|
||||
beq .doInv ; always taken
|
||||
.far: +LOAD_YSRC ; grab second byte of offset
|
||||
asl tmp ; toss the unused hi bit of the lo byte
|
||||
lsr ; shift out lo bit of the hi byte
|
||||
ror tmp ; to fill in the hi bit of the lo byte
|
||||
.doInv: sta tmp+1 ; got the hi byte of the offset now
|
||||
lda #0 ; calculate zero minus the offset, to obtain ptr diff
|
||||
sec
|
||||
sbc tmp
|
||||
sta .srcLoad+1 ; that's how much less to read from
|
||||
lda .dstStore2+2 ; same with hi byte of offset
|
||||
sbc tmp+1
|
||||
sta .srcLoad+2 ; to hi byte of offsetted pointer
|
||||
!if DEBUG_DECOMP { jsr .debug3 }
|
||||
.getMatchLen:
|
||||
pla ; recover the token byte
|
||||
and #$F ; mask to get just the match length
|
||||
clc
|
||||
adc #4 ; adjust: min match is 4 bytes
|
||||
cmp #$13 ; was it the special value $0F? ($F + 4 = $13)
|
||||
bne + ; if not, no need to extend length
|
||||
jsr .longLen ; need to extend the length
|
||||
+ sty tmp ; save index to source pointer, so we can use Y...
|
||||
!if DEBUG_DECOMP { sta ucLen : jsr .debug4 }
|
||||
tay ; ...to count bytes
|
||||
bne +
|
||||
dec ucLen+1 ; special case for len being an exact multiple of 256
|
||||
+
|
||||
sei ; prevent interrupts while we access aux mem
|
||||
.auxWr2 sta setAuxWr ; self-modified earlier, based on isAuxCmd
|
||||
.auxRd1 sta setAuxRd ; self-modified based on isAuxCmd
|
||||
.srcLoad:
|
||||
lda $1100,x ; self-modified earlier for offsetted source
|
||||
.dstStore2:
|
||||
sta $1100,x ; self-modified earlier for dest buffer
|
||||
!if DO_COMP_CHECKSUMS {
|
||||
eor checksum
|
||||
sta checksum
|
||||
}
|
||||
inx ; inc to next src/dst byte
|
||||
bne + ; non-zero, skip page bump
|
||||
jsr .nextDstPage ; do the bump
|
||||
+ dey ; count bytes -- first page yet?
|
||||
bne .srcLoad ; loop for more
|
||||
dec ucLen+1 ; count pages
|
||||
bpl .srcLoad ; loop for more. NOTE: this would fail if we had blocks >= 32K
|
||||
sta clrAuxRd ; back to reading main mem, for mem mgr code
|
||||
sta clrAuxWr ; back to writing main mem
|
||||
cli
|
||||
inc ucLen+1 ; to make it zero for the next match decode
|
||||
+ ldy tmp ; restore index to source pointer
|
||||
jmp .getToken ; go on to the next token in the compressed stream
|
||||
; Subroutine called when length token = $F, to extend the length by additional bytes
|
||||
.longLen:
|
||||
- sta ucLen ; save what we got so far
|
||||
+LOAD_YSRC ; get another byte
|
||||
cmp #$FF ; check for special there-is-more marker byte
|
||||
php ; save result of that
|
||||
clc
|
||||
adc ucLen ; add $FF to ucLen
|
||||
bcc + ; no carry, only lo byte has changed
|
||||
inc ucLen+1 ; increment hi byte of ucLen
|
||||
+ plp ; retrieve comparison status from earlier
|
||||
beq - ; if it was $FF, go back for more len bytes
|
||||
rts
|
||||
|
||||
!if DO_COMP_CHECKSUMS {
|
||||
.verifyCksum:
|
||||
+LOAD_YSRC
|
||||
!if DEBUG_DECOMP {
|
||||
+prStr : !text "cksum exp=",0
|
||||
pha
|
||||
jsr prbyte
|
||||
+prStr : !text " got=",0
|
||||
+prByte checksum
|
||||
+crout
|
||||
pla
|
||||
}
|
||||
cmp checksum ; get computed checksum
|
||||
beq + ; should be zero, because compressor stores checksum byte as part of stream
|
||||
+internalErr 'C' ; checksum doesn't match -- abort!
|
||||
+ rts
|
||||
}
|
||||
|
||||
nextSrcPage:
|
||||
pha ; save byte that was loaded
|
||||
inc pSrc+1 ; go to next page
|
||||
lda pSrc+1 ; check the resulting page num
|
||||
cmp #>diskBufEnd ; did we reach end of buffer?
|
||||
bne + ; if not, we're done
|
||||
sta clrAuxWr ; buffer is in main mem
|
||||
txa
|
||||
pha
|
||||
jsr readToBuf ; read more pages
|
||||
pla
|
||||
tax
|
||||
.auxWr3 sta setAuxWr ; go back to writing aux mem (self-modified for aux or main)
|
||||
+ pla ; restore loaded byte
|
||||
rts
|
||||
|
||||
.nextDstPage:
|
||||
inc .srcLoad+2 ; inc offset pointer for match copies
|
||||
inc .dstStore1+2 ; inc pointers for dest stores
|
||||
inc .dstStore2+2
|
||||
dec .endChk2+1 ; decrement total page counter
|
||||
rts
|
||||
|
||||
!if DEBUG_DECOMP {
|
||||
.debug1 +prStr : !text "Decompressing: isComp=",0
|
||||
+prByte isCompressed
|
||||
+prStr : !text "isAux=",0
|
||||
+prByte isAuxCmd
|
||||
+prStr : !text "compLen=",0
|
||||
+prWord reqLen
|
||||
+prStr : !text "uncompLen=",0
|
||||
+prWord ucLen
|
||||
+crout
|
||||
rts
|
||||
.debug2 +prStr : !text "Lit ptr=",0
|
||||
tya
|
||||
clc
|
||||
adc pSrc
|
||||
sta .dbgTmp
|
||||
lda pSrc+1
|
||||
adc #0
|
||||
sta .dbgTmp+1
|
||||
+prWord .dbgTmp
|
||||
+prStr : !text "len=",0
|
||||
+prWord ucLen
|
||||
+crout
|
||||
rts
|
||||
.debug3 +prStr : !text "Match src=",0
|
||||
txa ; calculate src address with X (not Y!) as offset
|
||||
clc
|
||||
adc .srcLoad+1
|
||||
sta .dbgTmp
|
||||
lda .srcLoad+2
|
||||
adc #0
|
||||
sta .dbgTmp+1
|
||||
+prWord .dbgTmp
|
||||
+prStr : !text "dst=",0
|
||||
txa ; calculate dest address with X as offset
|
||||
clc
|
||||
adc .dstStore2+1
|
||||
sta tmp
|
||||
lda .dstStore2+2
|
||||
adc #0
|
||||
sta tmp+1
|
||||
+prWord tmp
|
||||
+prStr : !text "offset=",0
|
||||
lda tmp ; now calculate the difference
|
||||
sec
|
||||
sbc .dbgTmp
|
||||
sta .dbgTmp
|
||||
lda tmp+1
|
||||
sbc .dbgTmp+1
|
||||
sta .dbgTmp+1
|
||||
+prWord .dbgTmp ; and print it
|
||||
rts
|
||||
.debug4 +prStr : !text "len=",0
|
||||
+prWord ucLen
|
||||
+crout
|
||||
rts
|
||||
.dbgTmp !word 0
|
||||
}
|
||||
; TODO: replace with LX47
|
||||
brk
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Apply fixups to all modules that were loaded this round, and free the fixup
|
||||
@ -3068,10 +2633,10 @@ advSingleAnim:
|
||||
iny ; now y=2, index number of frames
|
||||
lda (tmp),y
|
||||
adc #$FF ; minus one to get last frame (carry clear from prev add)
|
||||
sta checksum+1 ; save it for later reference
|
||||
sta .maxFrame ; save it for later reference
|
||||
iny ; now y=3, index current frame number
|
||||
lda (tmp),y
|
||||
sta checksum ; save it for comparison later
|
||||
sta .curFrame ; save it for comparison later
|
||||
!if DEBUG = 2 { jsr .dbgB1 }
|
||||
|
||||
.chkr ldy #0
|
||||
@ -3089,8 +2654,8 @@ advSingleAnim:
|
||||
.chkfs iny ; index of current dir
|
||||
cmp #3 ; is it a forward+stop anim?
|
||||
bne .chkfb
|
||||
lda checksum ; compare cur frame
|
||||
eor checksum+1 ; to (nFrames-1)
|
||||
lda .curFrame ; compare cur frame
|
||||
eor .maxFrame ; to (nFrames-1)
|
||||
bne .adv ; if not there yet, advance.
|
||||
rts ; we're at last frame; nothing left to do.
|
||||
|
||||
@ -3107,12 +2672,12 @@ advSingleAnim:
|
||||
jsr .fwbk ; advance the frame number in that direction
|
||||
.doptch ldy #3 ; index current frame
|
||||
lda (tmp),y
|
||||
cmp checksum ; compare to what it was
|
||||
cmp .curFrame ; compare to what it was
|
||||
bne + ; if not equal, we have work to do
|
||||
rts ; no change, all done.
|
||||
+ inc .ret2+1 ; advance count of number of things we actually changed
|
||||
pha
|
||||
lda checksum
|
||||
lda .curFrame
|
||||
jsr applyPatch ; un-patch old frame
|
||||
pla
|
||||
jmp applyPatch ; apply patch for the new frame
|
||||
@ -3123,7 +2688,7 @@ advSingleAnim:
|
||||
dey ; index of number of frames
|
||||
cmp #0
|
||||
bpl + ; can only be negative if dir=-1 and we wrapped around
|
||||
lda checksum+1 ; go to (previously saved) last frame number
|
||||
lda .maxFrame ; go to (previously saved) last frame number
|
||||
+ cmp (tmp),y ; are we at the limit of number of frames?
|
||||
bne +
|
||||
lda #0 ; back to start
|
||||
@ -3132,6 +2697,9 @@ advSingleAnim:
|
||||
!if DEBUG = 2 { jsr .dbgB2 }
|
||||
rts
|
||||
|
||||
.curFrame !byte 0
|
||||
.maxFrame !byte 0
|
||||
|
||||
!if DEBUG = 2 {
|
||||
.dbgin sta clrAuxRd
|
||||
sta clrAuxWr
|
||||
@ -3146,8 +2714,8 @@ advSingleAnim:
|
||||
+prStr : !text "single ",0
|
||||
+prWord pTmp
|
||||
+prWord tmp
|
||||
+prByte checksum
|
||||
+prByte checksum+1
|
||||
+prByte .curFrame
|
||||
+prByte .maxFrame
|
||||
jmp .dbgout
|
||||
.dbgB2 jsr .dbgin
|
||||
+prStr : !text "fwbk ",0
|
||||
|
@ -28,31 +28,6 @@ a2h = $3F
|
||||
inbuf = $200
|
||||
resetVec = $3F2
|
||||
|
||||
; PRODOS
|
||||
mli = $BF00
|
||||
MLI_QUIT = $65
|
||||
MLI_GET_TIME = $82
|
||||
MLI_CREATE = $C0
|
||||
MLI_DESTROY = $C1
|
||||
MLI_RENAME = $C2
|
||||
MLI_SET_FILE_INFO=$C3
|
||||
MLI_GET_FILE_INFO=$C4
|
||||
MLI_ONLINE = $C5
|
||||
MLI_SET_PREFIX = $C6
|
||||
MLI_GET_PREFIX = $C7
|
||||
MLI_OPEN = $C8
|
||||
MLI_NEWLINE = $C9
|
||||
MLI_READ = $CA
|
||||
MLI_WRITE = $CB
|
||||
MLI_CLOSE = $CC
|
||||
MLI_FLUSH = $CD
|
||||
MLI_SET_MARK = $CE
|
||||
MLI_GET_MARK = $CF
|
||||
MLI_SET_EOF = $D0
|
||||
MLI_GET_EOF = $D1
|
||||
MLI_SET_BUF = $D2
|
||||
MLI_GET_BUF = $D3
|
||||
|
||||
; I/O soft switches
|
||||
kbd = $C000
|
||||
clrAuxRd = $C002
|
||||
@ -62,21 +37,21 @@ setAuxWr = $C005
|
||||
clrAuxZP = $C008
|
||||
setAuxZP = $C009
|
||||
kbdStrobe = $C010
|
||||
rdLCBnk2 = $C011 ;reading from LC bank $Dx 2
|
||||
rdLCRam = $C012 ;reading from LC RAM
|
||||
rdRamRd = $C013 ;reading from aux/alt 48K
|
||||
rdRamWr = $C014 ;writing to aux/alt 48K
|
||||
rdCXRom = $C015 ;using internal Slot ROM
|
||||
rdAuxZP = $C016 ;using Slot zero page, stack, & LC
|
||||
rdC3Rom = $C017 ;using external (Slot) C3 ROM
|
||||
rd80Col = $C018 ;80STORE is On- using 80-column memory mapping
|
||||
rdVblBar = $C019 ;not VBL (VBL signal low)
|
||||
rdText = $C01A ;using text mode
|
||||
rdMixed = $C01B ;using mixed mode
|
||||
rdPage2 = $C01C ;using text/graphics page2
|
||||
rdHires = $C01D ;using Hi-res graphics mode
|
||||
rdAltCh = $C01E ;using alternate character set
|
||||
rd80Vid = $C01F ;using 80-column display mode
|
||||
rdLCBnk2 = $C011 ;reading from LC bank $Dx 2
|
||||
rdLCRam = $C012 ;reading from LC RAM
|
||||
rdRamRd = $C013 ;reading from aux/alt 48K
|
||||
rdRamWr = $C014 ;writing to aux/alt 48K
|
||||
rdCXRom = $C015 ;using internal Slot ROM
|
||||
rdAuxZP = $C016 ;using Slot zero page, stack, & LC
|
||||
rdC3Rom = $C017 ;using external (Slot) C3 ROM
|
||||
rd80Col = $C018 ;80STORE is On- using 80-column memory mapping
|
||||
rdVblBar = $C019 ;not VBL (VBL signal low)
|
||||
rdText = $C01A ;using text mode
|
||||
rdMixed = $C01B ;using mixed mode
|
||||
rdPage2 = $C01C ;using text/graphics page2
|
||||
rdHires = $C01D ;using Hi-res graphics mode
|
||||
rdAltCh = $C01E ;using alternate character set
|
||||
rd80Vid = $C01F ;using 80-column display mode
|
||||
|
||||
clrText = $C050
|
||||
setText = $C051
|
||||
|
@ -15,30 +15,6 @@ include "diskops.plh"
|
||||
include "gen_modules.plh"
|
||||
include "gen_players.plh"
|
||||
|
||||
// ProDOS MLI constants
|
||||
const MLI_QUIT = $65
|
||||
const MLI_GET_TIME = $82
|
||||
const MLI_CREATE = $C0
|
||||
const MLI_DESTROY = $C1
|
||||
const MLI_RENAME = $C2
|
||||
const MLI_SET_FILE_INFO = $C3
|
||||
const MLI_GET_FILE_INFO = $C4
|
||||
const MLI_ONLINE = $C5
|
||||
const MLI_SET_PREFIX = $C6
|
||||
const MLI_GET_PREFIX = $C7
|
||||
const MLI_OPEN = $C8
|
||||
const MLI_NEWLINE = $C9
|
||||
const MLI_READ = $CA
|
||||
const MLI_WRITE = $CB
|
||||
const MLI_CLOSE = $CC
|
||||
const MLI_FLUSH = $CD
|
||||
const MLI_SET_MARK = $CE
|
||||
const MLI_GET_MARK = $CF
|
||||
const MLI_SET_EOF = $D0
|
||||
const MLI_GET_EOF = $D1
|
||||
const MLI_SET_BUF = $D2
|
||||
const MLI_GET_BUF = $D3
|
||||
|
||||
// This pointer is the root of all heap-tracked (and garbage collected) objects.
|
||||
// See playtype.plh for definitions of all the datastructures and how they interconnect.
|
||||
word global
|
||||
@ -50,36 +26,6 @@ word[] funcTbl = @_saveGame, @_loadGame, @_newOrLoadGame
|
||||
|
||||
byte[] game1_filename = "GAME.1.SAVE"
|
||||
|
||||
// ProDOS command tables
|
||||
byte open_params = 3 // parameter count
|
||||
word open_filename
|
||||
word open_buffer
|
||||
byte open_fileref
|
||||
|
||||
byte create_params = 7 // parameter count
|
||||
word create_filename
|
||||
byte create_accessbits
|
||||
byte create_filetype
|
||||
word create_auxtype
|
||||
byte create_storagetype
|
||||
word create_date
|
||||
word create_time
|
||||
|
||||
byte write_params = 4 // parameter count
|
||||
byte write_fileref
|
||||
word write_addr
|
||||
word write_length
|
||||
word write_actual
|
||||
|
||||
byte read_params = 4 // parameter count
|
||||
byte read_fileref
|
||||
word read_addr
|
||||
word read_length
|
||||
word read_actual
|
||||
|
||||
byte close_params = 1 // parameter count
|
||||
byte close_fileref
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions used by assembly code
|
||||
asm __defs
|
||||
@ -127,40 +73,6 @@ asm copyHeap // params: dir (0=LCtoMain, 1=MainToLC)
|
||||
rts
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
asm mliStub
|
||||
; call MLI directly. Caller is expected to modify the command and param vectors
|
||||
; before calling.
|
||||
+asmPlasm 0 ; bytes 0-4
|
||||
jsr mli ; bytes 5-7
|
||||
!byte 0 ; byte 8
|
||||
!word 0 ; bytes 9-10
|
||||
bcs +
|
||||
lda #0
|
||||
+ bit setLcRW+lcBank2 ; Our crazy aux ProDOS stub doesn't preserve the LC bank; put PLASMA back.
|
||||
rts
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def callMLI(cmd, p_params)
|
||||
byte err
|
||||
//printf2("callMLI: cmd=$%x p_params=$%x\n", cmd, p_params)
|
||||
mliStub.8 = cmd
|
||||
mliStub:9 = p_params
|
||||
err = mliStub()
|
||||
return err
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def guaranteeMLI(cmd, p_params)
|
||||
byte err
|
||||
err = callMLI(cmd, p_params)
|
||||
if err > 0
|
||||
printf1("\nErr $%x\n", err)
|
||||
fatal("ProDOS error")
|
||||
fin
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def _saveGame()
|
||||
|
||||
@ -172,48 +84,48 @@ def _saveGame()
|
||||
copyHeap(0) // LC to low mem
|
||||
|
||||
// Open the file if it already exists...
|
||||
open_filename = @game1_filename
|
||||
open_buffer = $5C00
|
||||
if callMLI(MLI_OPEN, @open_params) > 0
|
||||
create_filename = open_filename
|
||||
create_accessbits = $C3 // full access
|
||||
create_filetype = $F1 // user type 1
|
||||
create_auxtype = 0
|
||||
create_storagetype = 1
|
||||
create_date = 0
|
||||
create_time = 0
|
||||
guaranteeMLI(MLI_CREATE, @create_params)
|
||||
guaranteeMLI(MLI_OPEN, @open_params)
|
||||
fin
|
||||
//open_filename = @game1_filename
|
||||
//open_buffer = $5C00
|
||||
//if callMLI(MLI_OPEN, @open_params) > 0
|
||||
//create_filename = open_filename
|
||||
//create_accessbits = $C3 // full access
|
||||
//create_filetype = $F1 // user type 1
|
||||
//create_auxtype = 0
|
||||
//create_storagetype = 1
|
||||
//create_date = 0
|
||||
//create_time = 0
|
||||
//guaranteeMLI(MLI_CREATE, @create_params)
|
||||
//guaranteeMLI(MLI_OPEN, @open_params)
|
||||
//fin
|
||||
|
||||
// Write the game data to it
|
||||
write_fileref = open_fileref
|
||||
write_addr = $5000
|
||||
write_length = HEAP_SIZE
|
||||
guaranteeMLI(MLI_WRITE, @write_params)
|
||||
//write_fileref = open_fileref
|
||||
//write_addr = $5000
|
||||
//write_length = HEAP_SIZE
|
||||
//guaranteeMLI(MLI_WRITE, @write_params)
|
||||
|
||||
// All done.
|
||||
close_fileref = open_fileref
|
||||
guaranteeMLI(MLI_CLOSE, @close_params)
|
||||
//close_fileref = open_fileref
|
||||
//guaranteeMLI(MLI_CLOSE, @close_params)
|
||||
end
|
||||
|
||||
def loadInternal()
|
||||
word p_loaded
|
||||
|
||||
// Open the file. If that fails, return FALSE (instead of halting)
|
||||
open_filename = @game1_filename
|
||||
open_buffer = $5C00
|
||||
if callMLI(MLI_OPEN, @open_params) > 0; return FALSE; fin
|
||||
//open_filename = @game1_filename
|
||||
//open_buffer = $5C00
|
||||
//if callMLI(MLI_OPEN, @open_params) > 0; return FALSE; fin
|
||||
|
||||
// Read the game data from it
|
||||
read_fileref = open_fileref
|
||||
read_addr = $5000
|
||||
read_length = HEAP_SIZE
|
||||
guaranteeMLI(MLI_READ, @read_params)
|
||||
//read_fileref = open_fileref
|
||||
//read_addr = $5000
|
||||
//read_length = HEAP_SIZE
|
||||
//guaranteeMLI(MLI_READ, @read_params)
|
||||
|
||||
// All done with the file
|
||||
close_fileref = open_fileref
|
||||
guaranteeMLI(MLI_CLOSE, @close_params)
|
||||
//close_fileref = open_fileref
|
||||
//guaranteeMLI(MLI_CLOSE, @close_params)
|
||||
|
||||
// Copy the heap up, and init it with the correct size.
|
||||
p_loaded = $5000
|
||||
@ -255,12 +167,7 @@ end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def gameExists()
|
||||
open_filename = @game1_filename
|
||||
open_buffer = $5000
|
||||
if callMLI(MLI_OPEN, @open_params) > 0; return FALSE; fin
|
||||
close_fileref = open_fileref
|
||||
guaranteeMLI(MLI_CLOSE, @close_params)
|
||||
return TRUE
|
||||
return FALSE // FIXME
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user