mirror of
https://github.com/irmen/prog8.git
synced 2025-02-04 02:30:19 +00:00
added bonkram chunk to chunkfile example
This commit is contained in:
parent
390263a34e
commit
5268b05060
@ -1,6 +1,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- add a compiler switch to replace all calls to the math word mul routine on the X16 by the verafx call instead.
|
||||
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
|
||||
- [on branch: ir-less-branch-opcodes] IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction
|
||||
- IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified!
|
||||
|
@ -3,14 +3,17 @@ from typing import Sequence
|
||||
|
||||
# Chunk types:
|
||||
# user types: 0 - 239
|
||||
# reserved: 240 - 249
|
||||
CHUNK_DUMMY = 250
|
||||
# reserved: 240 - 248
|
||||
CHUNK_DUMMY = 249
|
||||
CHUNK_BONKRAM = 250
|
||||
CHUNK_SYSTEMRAM = 251
|
||||
CHUNK_VIDEORAM = 252
|
||||
CHUNK_PAUSE = 253
|
||||
CHUNK_EOF = 254
|
||||
CHUNK_IGNORE = 255
|
||||
|
||||
ChunksWithData = {CHUNK_DUMMY, CHUNK_SYSTEMRAM, CHUNK_VIDEORAM, CHUNK_BONKRAM}
|
||||
|
||||
|
||||
class LoadList:
|
||||
def __init__(self):
|
||||
@ -26,8 +29,8 @@ class LoadList:
|
||||
raise ValueError("chunktype must be 0 - 255")
|
||||
if size < 0 or size > 65535:
|
||||
raise ValueError(f"size must be 0 - 65535 bytes")
|
||||
if bank < 0 or bank > 31:
|
||||
raise ValueError("bank must be 0 - 31")
|
||||
if bank < 0 or bank > 255:
|
||||
raise ValueError("bank must be 0 - 255")
|
||||
if address < 0 or address > 65535:
|
||||
raise ValueError("address must be 0 - 65535")
|
||||
data = struct.pack("<BHBH", chunktype, size, bank, address)
|
||||
@ -88,7 +91,7 @@ class MultiChunkFile:
|
||||
for chunk in loadlist.parse():
|
||||
if chunk[0] == CHUNK_EOF:
|
||||
break
|
||||
elif chunk[0] in (CHUNK_DUMMY, CHUNK_SYSTEMRAM, CHUNK_VIDEORAM) or chunk[0] < 240:
|
||||
elif chunk[0] in ChunksWithData or chunk[0] < 240:
|
||||
data = inf.read(chunk[1])
|
||||
self.chunks.append(data)
|
||||
num_data += 1
|
||||
@ -141,7 +144,7 @@ class MultiChunkFile:
|
||||
if lc[0] == CHUNK_EOF:
|
||||
eof_found = True
|
||||
break
|
||||
elif lc[0] in (CHUNK_DUMMY, CHUNK_SYSTEMRAM, CHUNK_VIDEORAM) or lc[0] < 240:
|
||||
elif lc[0] in ChunksWithData or lc[0] < 240:
|
||||
size, bank, address = lc[1:]
|
||||
data = next(chunk_iter)
|
||||
if isinstance(data, bytes):
|
||||
@ -161,9 +164,11 @@ class MultiChunkFile:
|
||||
def add_Dummy(self, size: int) -> None:
|
||||
self.add_chunk(CHUNK_DUMMY, data=bytearray(size))
|
||||
|
||||
def add_SystemRam(self, bank: int, address: int, data: bytes, chunksize: int=0xfe00) -> None:
|
||||
def add_SystemRam(self, bank: int, address: int, data: bytes, chunksize: int = 0xfe00) -> None:
|
||||
if address >= 0xa000 and address < 0xc000:
|
||||
raise ValueError("use add_BankedRam instead to load chunks into banked ram $a000-$c000")
|
||||
if bank < 0 or bank > 31:
|
||||
raise ValueError("bank must be 0 - 31")
|
||||
while data:
|
||||
if address >= 65536:
|
||||
raise ValueError("data too large for system ram")
|
||||
@ -171,14 +176,14 @@ class MultiChunkFile:
|
||||
data = data[chunksize:]
|
||||
address += chunksize
|
||||
|
||||
def add_BankedRam(self, bank: int, address: int, data: bytes, chunksize: int=0x2000) -> None:
|
||||
def add_BankedRam(self, bank: int, address: int, data: bytes, chunksize: int = 0x2000) -> None:
|
||||
if address < 0xa000 or address >= 0xc000:
|
||||
raise ValueError("use add_SystemRam instead to load chunks into normal system ram")
|
||||
if chunksize>0x2000:
|
||||
raise ValueError("chunksize too large for banked ram")
|
||||
if chunksize > 0x2000:
|
||||
raise ValueError("chunksize too large for banked ram, max 8K")
|
||||
while data:
|
||||
if address >= 0xc000:
|
||||
address -= 0xc000
|
||||
address -= 0x2000
|
||||
bank += 1
|
||||
if bank >= 32:
|
||||
raise ValueError("data too large for banked ram")
|
||||
@ -186,7 +191,24 @@ class MultiChunkFile:
|
||||
data = data[chunksize:]
|
||||
address += chunksize
|
||||
|
||||
def add_VideoRam(self, bank: int, address: int, data: bytes, chunksize: int=0xfe00) -> None:
|
||||
def add_BonkRam(self, bonk: int, address: int, data: bytes, chunksize: int = 0x4000) -> None:
|
||||
if bonk < 32 or bonk > 255:
|
||||
raise ValueError("bank for bonk ram (cartridge ram) must be 32 - 255")
|
||||
if chunksize > 0x4000:
|
||||
raise ValueError("chunksize too large for bonk ram (cartridge ram), max 16K")
|
||||
if address < 0xc000 or address > 0xffff:
|
||||
raise ValueError("use add_SystemRam instead to load chunks into normal system ram")
|
||||
while data:
|
||||
if address > 0xffff:
|
||||
address -= 0x4000
|
||||
bonk += 1
|
||||
if bonk > 255:
|
||||
raise ValueError("data too large for bonk ram (cartridge ram)")
|
||||
self.add_chunk(CHUNK_BONKRAM, bonk, address, data[:chunksize])
|
||||
data = data[chunksize:]
|
||||
address += chunksize
|
||||
|
||||
def add_VideoRam(self, bank: int, address: int, data: bytes, chunksize: int = 0xfe00) -> None:
|
||||
if bank < 0 or bank > 1:
|
||||
raise ValueError("bank for videoram must be 0 or 1")
|
||||
while data:
|
||||
@ -245,7 +267,7 @@ if __name__ == "__main__":
|
||||
palette1 = open("testdata/ME-TITLESCREEN.PAL", "rb").read()
|
||||
palette2 = open("testdata/DS-TITLESCREEN.PAL", "rb").read()
|
||||
except IOError:
|
||||
print("""ERROR: cannot load the demo data files.
|
||||
print("""ERROR: cannot load the demo data files.
|
||||
You'll need to put the titlescreen data files from the 'musicdemo' project into the testdata directory.
|
||||
The musicdemo is on github: https://github.com/irmen/cx16musicdemo
|
||||
The four files are the two ME- and the two DS- TITLESCREEN.BIN and .PAL files, and are generated by running the makefile in that project.""")
|
||||
@ -268,6 +290,7 @@ The four files are the two ME- and the two DS- TITLESCREEN.BIN and .PAL files, a
|
||||
mcf.add_VideoRam(1, 0xfa00, palette2)
|
||||
mcf.add_VideoRam(0, 0, bitmap2)
|
||||
mcf.add_Pause(222)
|
||||
mcf.add_BonkRam(32, 0xc000, bytearray(32768))
|
||||
mcf.add_Pause(111)
|
||||
mcf.add_EOF()
|
||||
mcf.write("demo.mcf")
|
||||
|
@ -7,11 +7,14 @@ main {
|
||||
|
||||
sub start() {
|
||||
uword duration
|
||||
ubyte[256] bonkbuffer
|
||||
|
||||
set_screen_mode()
|
||||
cbm.SETTIM(0,0,0)
|
||||
|
||||
mcf.set_callbacks(mcf_get_buffer, mcf_process_chunk) ; not needed if the stream has no custom chunk types
|
||||
mcf.set_bonkbuffer(bonkbuffer)
|
||||
|
||||
if mcf.open("demo.mcf", 8, 2) {
|
||||
repeat {
|
||||
mcf.stream()
|
||||
|
@ -3,14 +3,16 @@
|
||||
|
||||
; Streaming routine for MCF files (multipurpose chunk format):
|
||||
; 1. call open()
|
||||
; 2. set callbacks if needed, set_callbacks()
|
||||
; 3. call stream() in a loop
|
||||
; 4. call close() if you want to cleanup halfway through for some reason
|
||||
; 2. set callbacks if needed; set_callbacks()
|
||||
; 3. set bonk ram (cartridge ram) load buffer, if needed; set_bonkbuffer()
|
||||
; 4. call stream() in a loop
|
||||
; 5. call close() if you want to cleanup halfway through for some reason
|
||||
|
||||
|
||||
mcf {
|
||||
uword loadlist_buf = memory("loadlist", 256, 0)
|
||||
uword @zp loadlist_ptr
|
||||
uword bonkbuffer
|
||||
bool needs_loadlist
|
||||
ubyte file_channel
|
||||
|
||||
@ -49,6 +51,11 @@ mcf {
|
||||
}}
|
||||
}
|
||||
|
||||
sub set_bonkbuffer(uword buffer) {
|
||||
; needs to be a buffer of 256 bytes (1 page)
|
||||
bonkbuffer = buffer
|
||||
}
|
||||
|
||||
sub stream() {
|
||||
repeat {
|
||||
if needs_loadlist {
|
||||
@ -89,6 +96,15 @@ mcf {
|
||||
loadlist_ptr+=6
|
||||
}
|
||||
250 -> {
|
||||
; bonk ram (cartridge ram)
|
||||
; This cannot use MACPTR (because the kernal rom isn't banked in)
|
||||
; so we have to load it into a buffer and copy it manually.
|
||||
; Because this will be rarely used, the buffer is not allocated here to save memory, and instead
|
||||
; the user has to set it with the config routine when the program wants to use this chunk type.
|
||||
blockload_bonkram(peekw(loadlist_ptr+1), peek(loadlist_ptr+3), peekw(loadlist_ptr+4))
|
||||
loadlist_ptr+=6
|
||||
}
|
||||
249 -> {
|
||||
; dummy chunk
|
||||
blockload_dummy(peekw(loadlist_ptr+1))
|
||||
loadlist_ptr+=6
|
||||
@ -158,6 +174,22 @@ processchunk_call jsr $ffff ; modified
|
||||
cx16.rambank(orig_ram_bank)
|
||||
}
|
||||
|
||||
sub blockload_bonkram(uword size, ubyte bonk, uword address) {
|
||||
ubyte orig_rom_bank = cx16.getrombank()
|
||||
cx16.r3 = address
|
||||
while size {
|
||||
ubyte readsize = 255
|
||||
if size < 255
|
||||
readsize = lsb(size)
|
||||
cx16.r2 = cx16.macptr(readsize, bonkbuffer, false) ; can't macptr directly to bonk ram
|
||||
cx16.rombank(bonk)
|
||||
sys.memcopy(bonkbuffer, cx16.r3, cx16.r2) ; copy to bonk ram
|
||||
cx16.rombank(orig_rom_bank)
|
||||
size -= cx16.r2
|
||||
cx16.r3 += cx16.r2
|
||||
}
|
||||
}
|
||||
|
||||
sub readblock(uword size, uword address, bool dontAdvance) -> uword {
|
||||
if msb(size)>=2
|
||||
return cx16.macptr(0, address, dontAdvance) ; read 512 bytes
|
||||
@ -165,4 +197,4 @@ processchunk_call jsr $ffff ; modified
|
||||
return cx16.macptr(255, address, dontAdvance) ; read 255 bytes
|
||||
return cx16.macptr(lsb(size), address, dontAdvance) ; read remaining number of bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ and so on.
|
||||
There is no limit to the number of chunks and the size of the file, as long as it fits on the disk.
|
||||
|
||||
|
||||
### LoadList chunk
|
||||
### LoadList chunk
|
||||
|
||||
This chunk is a list of what kinds of chunks occur in the file after it.
|
||||
It starts with a small identification header:
|
||||
@ -52,7 +52,7 @@ Then a sequence of 1 or more chunk specs (6 bytes each), as long as it still fit
|
||||
| data | meaning |
|
||||
|----------------------|--------------------------------------------|
|
||||
| byte | chunk type |
|
||||
| word (little-endian) | chunk size |
|
||||
| word (little-endian) | chunk size |
|
||||
| byte | bank number (used for some chunk types) |
|
||||
| word (little-endian) | memory address (used for some chunk types) |
|
||||
|
||||
@ -61,18 +61,19 @@ If there are more chunks in the file than fit in a single loadlist, we simply ad
|
||||
(The file only ends once an End Of File chunk type is encountered in a loadlist.)
|
||||
|
||||
|
||||
### Chunk types
|
||||
### Chunk types
|
||||
|
||||
| chunk type | meaning |
|
||||
|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0 - 239 | custom chunk types. See below. |
|
||||
| 240 - 249 | reserved for future system chunk types. |
|
||||
| 250 | dummy chunk: read a chunk of the specified number of bytes but don't do anything with it. Useful to realign the file I/O on disk block size. |
|
||||
| 251 | system ram load: use banknumber + address to set the RAM bank and load address and loads the chunk there, then continue streaming. |
|
||||
| 252 | video ram load: use banknumber + address to set the Vera VRAM bank (hi byte) and load address (mid+lo byte) and loads the chunk into video ram there, then continue streaming. |
|
||||
| 253 | pause streaming. Returns from stream routine with pause status: Carry=clear. And reg.r0=size. until perhaps the program calls the stream routine again to resume. |
|
||||
| 254 | end of file. Closes the file and stops streaming: returns from stream routine with exit status: Carry=set. |
|
||||
| 255 | ignore this byte. Used to pad out the loadlist chunk to 256 bytes. |
|
||||
| chunk type | meaning |
|
||||
|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0 - 239 | custom chunk types. See below. |
|
||||
| 240 - 248 | reserved for future system chunk types. |
|
||||
| 249 | dummy chunk: read a chunk of the specified number of bytes but don't do anything with it. Useful to realign the file I/O on disk block size. |
|
||||
| 250 | bonk ram load: use banknumber + address to set the Cartridge RAM ('bonk' RAM) bank and load address and loads the chunk there, then continue streaming. Note this is slower than other types of ram. Rquires 1 page of user chosen buffer area. |
|
||||
| 251 | system ram load: use banknumber + address to set the RAM bank and load address and loads the chunk there, then continue streaming. |
|
||||
| 252 | video ram load: use banknumber + address to set the Vera VRAM bank (hi byte) and load address (mid+lo byte) and loads the chunk into video ram there, then continue streaming. |
|
||||
| 253 | pause streaming. Returns from stream routine with pause status: Carry=clear. And reg.r0=size. until perhaps the program calls the stream routine again to resume. |
|
||||
| 254 | end of file. Closes the file and stops streaming: returns from stream routine with exit status: Carry=set. |
|
||||
| 255 | ignore this byte. Used to pad out the loadlist chunk to 256 bytes. |
|
||||
|
||||
|
||||
### Custom chunk types (0 - 239)
|
||||
@ -85,10 +86,10 @@ The first routine has the following signature:
|
||||
|
||||
**get_buffer()**:
|
||||
Arguments: reg.A = chunk type, reg.XY = chunksize.
|
||||
Returns: Carry flag=success (set = fail, clear = ok), ram bank in reg.A, memory address in reg.XY.
|
||||
Returns: Carry flag=success (set = fail, clear = ok), ram bank in reg.A, memory address in reg.XY.
|
||||
|
||||
The second routine has the following signature:
|
||||
|
||||
|
||||
**process_chunk()**:
|
||||
Arguments: none (save them from the get_buffer call if needed).
|
||||
Returns: Carry flag=success (set = fail, clear = ok).
|
||||
|
Loading…
x
Reference in New Issue
Block a user