diff --git a/compiler/res/prog8lib/buffers.p8 b/compiler/res/prog8lib/buffers.p8 index a29f75278..ae5753950 100644 --- a/compiler/res/prog8lib/buffers.p8 +++ b/compiler/res/prog8lib/buffers.p8 @@ -70,7 +70,65 @@ smallringbuffer { } } -; note: for a "small stack" (256 bytes size) just use the CPU stack via sys.push[w] / sys.pop[w]. + +smallstack { + ; -- A small stack (LIFO) that uses just 256 bytes and is independent of the CPU stack. Stack is growing downward from the top of the buffer. + ; You can store and retrieve bytes and words. There are no guards against stack over/underflow. + ; note: for a "small stack" (256 bytes size) you might also perhaps just use the CPU stack via sys.push[w] / sys.pop[w]. + + ubyte[256] buffer + ubyte sp = 255 + + sub init() { + sp = 255 + } + + sub size() -> ubyte { + return 255-sp + } + + sub free() -> ubyte { + return sp + } + + sub isfull() -> bool { + return sp==0 + } + + sub isempty() -> bool { + return sp==255 + } + + sub push(ubyte value) { + ; -- put a byte on the stack + buffer[sp] = value + sp-- + } + + sub pushw(uword value) { + ; -- put a word on the stack (lsb first then msb) + buffer[sp] = lsb(value) + sp-- + buffer[sp] = msb(value) + sp-- + } + + sub pop() -> ubyte { + ; -- pops a byte off the stack + sp++ + return buffer[sp] + } + + sub popw() -> uword { + ; -- pops a word off the stack. + sp++ + cx16.r0H = buffer[sp] + sp++ + cx16.r0L = buffer[sp] + return cx16.r0 + } +} + stack { ; -- A stack (LIFO) that uses a block of 8 KB of memory. Growing downward from the top of the buffer. diff --git a/compiler/res/prog8lib/cx16/buffers.p8 b/compiler/res/prog8lib/cx16/buffers.p8 index c27c1195f..d47e94863 100644 --- a/compiler/res/prog8lib/cx16/buffers.p8 +++ b/compiler/res/prog8lib/cx16/buffers.p8 @@ -68,7 +68,65 @@ smallringbuffer { } } -; note: for a "small stack" (256 bytes size) just use the CPU stack via sys.push[w] / sys.pop[w]. + +smallstack { + ; -- A small stack (LIFO) that uses just 256 bytes and is independent of the CPU stack. Stack is growing downward from the top of the buffer. + ; You can store and retrieve bytes and words. There are no guards against stack over/underflow. + ; note: for a "small stack" (256 bytes size) you might also perhaps just use the CPU stack via sys.push[w] / sys.pop[w]. + + ubyte[256] buffer + ubyte sp = 255 + + sub init() { + sp = 255 + } + + sub size() -> ubyte { + return 255-sp + } + + sub free() -> ubyte { + return sp + } + + sub isfull() -> bool { + return sp==0 + } + + sub isempty() -> bool { + return sp==255 + } + + sub push(ubyte value) { + ; -- put a byte on the stack + buffer[sp] = value + sp-- + } + + sub pushw(uword value) { + ; -- put a word on the stack (lsb first then msb) + buffer[sp] = lsb(value) + sp-- + buffer[sp] = msb(value) + sp-- + } + + sub pop() -> ubyte { + ; -- pops a byte off the stack + sp++ + return buffer[sp] + } + + sub popw() -> uword { + ; -- pops a word off the stack. + sp++ + cx16.r0H = buffer[sp] + sp++ + cx16.r0L = buffer[sp] + return cx16.r0 + } +} + stack { ; -- A stack (LIFO) that uses a block of 8 KB of memory. Growing downward from the top of the buffer. @@ -78,7 +136,7 @@ stack { ubyte bank sub init(ubyte rambank) { - ; -- initialize the stack, must be called before use. Supply the HiRAM bank to use as buffer space. + ; -- initialize the stack, must be called before use. Supply the HIRAM bank to use as buffer space. sp = $bfff bank = rambank } @@ -157,7 +215,7 @@ ringbuffer { ubyte bank = 255 ; set via init() sub init(ubyte rambank) { - ; -- initialize the ringbuffer, must be called before use. Supply the HiRAM bank to use as buffer space. + ; -- initialize the ringbuffer, must be called before use. Supply the HIRAM bank to use as buffer space. head = $a000 tail = $bfff fill = 0 diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 4a2eb419b..7672ec30a 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -60,13 +60,13 @@ private fun compileMain(args: Array): Boolean { val quietAll by cli.option(ArgType.Boolean, fullName = "quiet", description = "don't print compiler and assembler messages, except warnings and errors") val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler messages") val slabsGolden by cli.option(ArgType.Boolean, fullName = "slabsgolden", description = "put memory() slabs in 'golden ram' memory area instead of at the end of the program. On the cx16 target this is $0400-07ff. This is unavailable on other systems.") - val slabsHighBank by cli.option(ArgType.Int, fullName = "slabshigh", description = "put memory() slabs in high memory area instead of at the end of the program. On the cx16 target the value specifies the HiRAM bank to use, on other systems this value is ignored.") + val slabsHighBank by cli.option(ArgType.Int, fullName = "slabshigh", description = "put memory() slabs in high memory area instead of at the end of the program. On the cx16 target the value specifies the HIRAM bank to use, on other systems this value is ignored.") val dontIncludeSourcelines by cli.option(ArgType.Boolean, fullName = "nosourcelines", description = "do not include original Prog8 source lines in generated asm code") val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator) val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of ${CompilationTargets.joinToString(",")} or a custom target properties file) (required)") val showTimings by cli.option(ArgType.Boolean, fullName = "timings", description = "show internal compiler timings (for performance analysis)") val varsGolden by cli.option(ArgType.Boolean, fullName = "varsgolden", description = "put uninitialized variables in 'golden ram' memory area instead of at the end of the program. On the cx16 target this is $0400-07ff. This is unavailable on other systems.") - val varsHighBank by cli.option(ArgType.Int, fullName = "varshigh", description = "put uninitialized variables in high memory area instead of at the end of the program. On the cx16 target the value specifies the HiRAM bank to use, on other systems this value is ignored.") + val varsHighBank by cli.option(ArgType.Int, fullName = "varshigh", description = "put uninitialized variables in high memory area instead of at the end of the program. On the cx16 target the value specifies the HIRAM bank to use, on other systems this value is ignored.") val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "run a .p8ir IR source file in the embedded VM") val warnSymbolShadowing by cli.option(ArgType.Boolean, fullName = "warnshadow", description="show assembler warnings about symbol shadowing") val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)") @@ -145,7 +145,7 @@ private fun compileMain(args: Array): Boolean { } if(varsHighBank==0 && compilationTarget==Cx16Target.NAME) { - System.err.println("On the Commander X16, HiRAM bank 0 is used by the kernal and can't be used.") + System.err.println("On the Commander X16, HIRAM bank 0 is used by the kernal and can't be used.") return false } diff --git a/docs/source/compiling.rst b/docs/source/compiling.rst index 17739689f..495e90698 100644 --- a/docs/source/compiling.rst +++ b/docs/source/compiling.rst @@ -228,7 +228,7 @@ One or more .p8 module files ``-slabshigh`` put memory() slabs in high memory area instead of at the end of the program. - On the cx16 target the value specifies the HiRAM bank to use, on other systems this value is ignored. + On the cx16 target the value specifies the HIRAM bank to use, on other systems this value is ignored. ``-nosourcelines`` Do not include the original prog8 source code lines as comments in the generated assembly code file, @@ -263,7 +263,7 @@ One or more .p8 module files c64: $C000 - $CFFF ; 4 kB, and the specified rambank number is ignored - cx16: $A000 - $BFFF ; 8 kB in the specified HiRAM bank (note: no auto bank switching is done, you must make sure yourself that this HiRAM bank is active when accessing these variables!) + cx16: $A000 - $BFFF ; 8 kB in the specified HIRAM bank (note: no auto bank switching is done, you must make sure yourself that this HIRAM bank is active when accessing these variables!) If you use this option, you can no longer use the part of the above memory area that is alotted to the variables, for your own purposes. The output of the 64tass assembler step at the diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 68682196e..6acd748a3 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -320,17 +320,21 @@ the :source:`bmx source code ` . There's also the "showbmx" example to look at. -buffers (experimental) -^^^^^^^^^^^^^^^^^^^^^^ +buffers +^^^^^^^ -A small library providing a 8 KB stack, an 8 KB ringbuffer, and a fast 256 bytes ringbuffer. -API is experimental and may change or disappear in a future version. -Stack is a LIFO container, ringbuffers are FIFO containers. -On the Commander X16 the stack and ringbuffer will use a HiRAM bank instead of system ram, -you have to initialize that via the init(bank) routine. +Provides few data buffer routines. These are available: + +- ``smallstack`` a fast 256 byte stack (LIFO) that is independent of the CPU stack. +- ``smallringbuffer`` a fast 256 byte ringbuffer (FIFO). +- ``stack`` a stack (LIFO) with up to 8Kb of data. +- ``ringbuffer`` a ringbuffer (FIFO) with up to 8Kb of data. + +On the Commander X16 the 8Kb stack and ringbuffer implementations use a HIRAM bank instead of regular system memory. +You tell it which bank to use by calling ``init(bank)`` with the bank number as argument. Read the :source:`buffers source code ` -to see what's in there. Note that the init() routines have that extra bank parameter on the X16. +to see what's in there. Note that on the X16, the init() routines have that extra bank parameter. compression (slightly experimental) diff --git a/examples/cx16/zsmkit_v2/README.txt b/examples/cx16/zsmkit_v2/README.txt index 7de6dc85b..8008af77d 100644 --- a/examples/cx16/zsmkit_v2/README.txt +++ b/examples/cx16/zsmkit_v2/README.txt @@ -13,7 +13,7 @@ The ZSMKIT-A000.BIN included here is release version 2.6 of zsmkit. DEMO PROGRAM ------------ -The demo program loads the zsmkit player program in HiRAM bank 1. +The demo program loads the zsmkit player program in HIRAM bank 1. The ZSM music file is read into memory too starting from bank 2. The zmskit library routines are defined in zsmkit.p8 as extsubs, using prog8's automatic ram banking mechanism. diff --git a/examples/test.p8 b/examples/test.p8 index 734ac9623..09164adc9 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,33 +1,26 @@ +%import buffers %import textio +%zeropage basicsafe main { sub start() { - ubyte[] array = ['h', 'e', 'l', 'l', 'o', 0] - str name = "hello" + smallstack.init() + txt.print("free ") + txt.print_ub(smallstack.free()) + txt.nl() - name[5] = '!' ; don't do this in real code... - name[5] = 0 - name[6] = 99 ; out of bounds - name[-1] = 99 ; ok - name[-5] = 99 ; ok + smallstack.push(123) + smallstack.pushw(55555) + txt.print("free ") + txt.print_ub(smallstack.free()) + txt.print(" size ") + txt.print_ub(smallstack.size()) + txt.nl() - cx16.r0L = name[5] - cx16.r1L = name[6] ; out of bounds - cx16.r1L = name[-1] ; ok - cx16.r1L = name[-5] ; ok - - array[5] = '!' - array[5] = 0 - array[6] = 99 ; out of bounds - array[-1] = 99 ; ok - array[-5] = 99 ; ok - array[-6] = 99 ; ok - - cx16.r0L = array[5] - cx16.r1L = array[6] ; out of bounds - cx16.r1L = array[-1] ; ok - cx16.r1L = array[-5] ; ok - cx16.r1L = array[-6] ; ok + txt.print_uw(smallstack.popw()) + txt.spc() + txt.print_ub(smallstack.pop()) + txt.nl() } }