diff --git a/compiler/res/prog8lib/buffers.p8 b/compiler/res/prog8lib/buffers.p8 new file mode 100644 index 000000000..d4a800256 --- /dev/null +++ b/compiler/res/prog8lib/buffers.p8 @@ -0,0 +1,69 @@ +; experimental buffer data structures + +smallringbuffer { + ; -- A ringbuffer (FIFO queue) that occupies a single page in memory, containing 255 bytes maximum. + ; You can store and retrieve words too. + ; It's optimized for speed and depends on the byte-wrap-around feature when doing incs and decs. + + ubyte fill + ubyte head + ubyte tail + ubyte[256] buffer + + sub init() { + ; -- (re)initialize the ringbuffer, you must call this before using the other routines + head = fill = 0 + tail = 255 + } + + sub put(ubyte value) -> bool { + ; -- store a byte in the buffer, returns success + if fill==255 + return false + buffer[head] = value + head++ + fill++ + } + + sub putw(uword value) -> bool { + ; -- store a word in the buffer, returns success + if fill>=254 + return false + fill+=2 + buffer[head] = lsb(value) + head++ + buffer[head] = msb(value) + head++ + } + + sub get() -> ubyte { + ; -- retrieves a byte from the buffer. Also sets Carry flag: set=success, clear=buffer was empty + if fill==0 { + sys.clear_carry() + return 0 + } + fill-- + tail++ + sys.set_carry() + return buffer[tail] + } + + sub getw() -> uword { + ; -- retrieves a word from the buffer. Also sets Carry flag: set=success, clear=buffer was empty + if fill<2 { + sys.clear_carry() + return 0 + } + fill-=2 + tail++ + cx16.r0L = buffer[tail] + tail++ + cx16.r0H = buffer[tail] + sys.set_carry() + return cx16.r0 + } +} + + +; TODO ringbuffer (FIFO queue) using more than 1 page of ram (maybe even banked ram on the x16) +; TODO stack (LIFO queue) using more than 1 page of ram (maybe even banked ram on the x16) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index f14de46f8..d39ef3de2 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,8 @@ TODO See open issues on github. +IR: add SEC and CLC instructions in place of call to sys.set_carry() and sys.clear_carry(). (check more inline sub calls that should be a single instruction?) + optimize signed byte/word division by powers of 2 (and shift right?), it's now using divmod routine. (also % ?) see inplacemodificationByteVariableWithLiteralval() and inplacemodificationSomeWordWithLiteralval() and for IR: see divideByConst() in IRCodeGen diff --git a/examples/test.p8 b/examples/test.p8 index af9b00870..d4f96fcb5 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,52 +1,102 @@ + %import textio %zeropage basicsafe %option no_sysinit main { sub start() { - signed() - unsigned() - } + ringbuffer256.init() - sub signed() { - byte @shared bvalue = -100 - word @shared wvalue = -20000 - - bvalue /= 2 ; TODO should be a simple bit shift? - wvalue /= 2 ; TODO should be a simple bit shift? - - txt.print_b(bvalue) - txt.nl() - txt.print_w(wvalue) - txt.nl() - - bvalue *= 2 - wvalue *= 2 - - txt.print_b(bvalue) - txt.nl() - txt.print_w(wvalue) - txt.nl() - } - - sub unsigned() { - ubyte @shared ubvalue = 100 - uword @shared uwvalue = 20000 - - ubvalue /= 2 - uwvalue /= 2 - - txt.print_ub(ubvalue) - txt.nl() - txt.print_uw(uwvalue) - txt.nl() - - ubvalue *= 2 - uwvalue *= 2 - - txt.print_ub(ubvalue) - txt.nl() - txt.print_uw(uwvalue) - txt.nl() + cx16.r0L = ringbuffer256.get() + if_cs { + txt.print_ub(cx16.r0L) + txt.nl() + } else { + txt.print("buffer empty\n") + } } } + +ringbuffer256 { + uword size + ubyte head + ubyte tail + ubyte[256] buffer + + sub init() { + size = head = 0 + tail = 255 + } + + sub add(ubyte value) -> bool { + if size==256 + return false + + buffer[head] = value + head++ + size++ + } + + sub get() -> ubyte { + if size==0 { + sys.clear_carry() + return 0 + } + + size-- + tail++ + sys.set_carry() + return buffer[tail] + } + +} + +; +;main { +; sub start() { +; signed() +; unsigned() +; } +; +; sub signed() { +; byte @shared bvalue = -100 +; word @shared wvalue = -20000 +; +; bvalue /= 2 ; TODO should be a simple bit shift? +; wvalue /= 2 ; TODO should be a simple bit shift? +; +; txt.print_b(bvalue) +; txt.nl() +; txt.print_w(wvalue) +; txt.nl() +; +; bvalue *= 2 +; wvalue *= 2 +; +; txt.print_b(bvalue) +; txt.nl() +; txt.print_w(wvalue) +; txt.nl() +; } +; +; sub unsigned() { +; ubyte @shared ubvalue = 100 +; uword @shared uwvalue = 20000 +; +; ubvalue /= 2 +; uwvalue /= 2 +; +; txt.print_ub(ubvalue) +; txt.nl() +; txt.print_uw(uwvalue) +; txt.nl() +; +; ubvalue *= 2 +; uwvalue *= 2 +; +; txt.print_ub(ubvalue) +; txt.nl() +; txt.print_uw(uwvalue) +; txt.nl() +; } +;} diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index f8e8ddf6f..fa05628dd 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -118,12 +118,12 @@ fun parseIRCodeLine(line: String): Either { operands.forEach { oper -> if (oper[0] == '&') throw IRParseException("address-of should be done with normal LOAD ") - else if (oper[0] in "rR") { + else if (isRegisterName(oper)) { if (reg1 == null) reg1 = oper.substring(1).toInt() else if (reg2 == null) reg2 = oper.substring(1).toInt() else if (reg3 == null) reg3 = oper.substring(1).toInt() else throw IRParseException("too many register operands") - } else if (oper[0] in "fF" && oper[1] in "rR") { + } else if (isFloatRegisterName(oper)) { if (fpReg1 == null) fpReg1 = oper.substring(2).toInt() else if (fpReg2 == null) fpReg2 = oper.substring(2).toInt() else throw IRParseException("too many fp register operands") @@ -212,6 +212,30 @@ fun parseIRCodeLine(line: String): Either { return left(IRInstruction(opcode, type, reg1, reg2, reg3, fpReg1, fpReg2, immediateInt, immediateFp, address, labelSymbol = labelSymbol, symbolOffset = offset)) } +private fun isRegisterName(oper: String): Boolean { + if(oper[0] in "rR") { + try { + oper.substring(1).toInt() + return true + } catch(_: NumberFormatException) { + return false + } + } + return false +} + +private fun isFloatRegisterName(oper: String): Boolean { + if(oper[0] in "fF" && oper[1] in "rR") { + try { + oper.substring(2).toInt() + return true + } catch(_: NumberFormatException) { + return false + } + } + return false +} + private class ParsedCall( val target: String?, val address: Int?,