diff --git a/compiler/res/prog8lib/prog8_lib.asm b/compiler/res/prog8lib/prog8_lib.asm index a995e102d..3dbefccea 100644 --- a/compiler/res/prog8lib/prog8_lib.asm +++ b/compiler/res/prog8lib/prog8_lib.asm @@ -1071,3 +1071,18 @@ sign_extend_AY_byte .proc pla rts .pend + + +peekw .proc + ; -- read the word value on the address in AY + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + ldy #0 + lda (P8ZP_SCRATCH_W1),y + pha + iny + lda (P8ZP_SCRATCH_W1),y + tay + pla + rts + .pend diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index efd3d3d29..b5782ab30 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -2,6 +2,8 @@ package prog8.compiler.astprocessing import prog8.ast.INameScope import prog8.ast.Node +import prog8.ast.expressions.DirectMemoryRead +import prog8.ast.expressions.FunctionCall import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.TypecastExpression import prog8.ast.statements.AnonymousScope @@ -43,4 +45,14 @@ internal class VariousCleanups: AstWalker() { return noModifications } + + override fun before(functionCall: FunctionCall, parent: Node): Iterable { + if(functionCall.target.nameInSource==listOf("peek")) { + // peek is synonymous with @ + val memread = DirectMemoryRead(functionCall.args.single(), functionCall.position) + return listOf(IAstModification.ReplaceNode(functionCall, memread, parent)) + } + return noModifications + } + } diff --git a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt index c48b9aaa8..2de697fae 100644 --- a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt @@ -132,6 +132,8 @@ private val functionSignatures: List = listOf( FSignature("lsb" , true, listOf(FParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> x and 255 } }, FSignature("msb" , true, listOf(FParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> x ushr 8 and 255} }, FSignature("mkword" , true, listOf(FParam("msb", setOf(DataType.UBYTE)), FParam("lsb", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword), + FSignature("peek" , true, listOf(FParam("address", setOf(DataType.UWORD))), DataType.UBYTE), + FSignature("peekw" , true, listOf(FParam("address", setOf(DataType.UWORD))), DataType.UWORD), FSignature("rnd" , false, emptyList(), DataType.UBYTE), FSignature("rndw" , false, emptyList(), DataType.UWORD), FSignature("rndf" , false, emptyList(), DataType.FLOAT), diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index c73edfaf0..398a7ac2d 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -56,6 +56,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val "sort" -> funcSort(fcall) "reverse" -> funcReverse(fcall) "memory" -> funcMemory(fcall, discardResult, resultToStack, resultRegister) + "peekw" -> funcPeekW(fcall, resultToStack, resultRegister) + "peek" -> throw AssemblyError("peek() should have been replaced by @()") else -> TODO("missing asmgen for builtin func ${func.name}") } } @@ -958,6 +960,22 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val } } + private fun funcPeekW(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY) + asmgen.out(" jsr prog8_lib.peekw") + if(resultToStack){ + asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") + } else { + when(resultRegister ?: RegisterOrPair.AY) { + RegisterOrPair.AY -> {} + RegisterOrPair.AX -> asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") + RegisterOrPair.XY -> asmgen.out(" tax") + in Cx16VirtualRegisters -> asmgen.out(" sta cx16.${resultRegister.toString().toLowerCase()} | sty cx16.${resultRegister.toString().toLowerCase()}+1") + else -> throw AssemblyError("invalid reg") + } + } + } + private fun funcMkword(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { if(resultToStack) { asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb diff --git a/compilerAst/src/prog8/ast/AstToSourceCode.kt b/compilerAst/src/prog8/ast/AstToSourceCode.kt index 7e0869afc..25372e9aa 100644 --- a/compilerAst/src/prog8/ast/AstToSourceCode.kt +++ b/compilerAst/src/prog8/ast/AstToSourceCode.kt @@ -413,10 +413,6 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): outputlni("}}") } - override fun visit(builtinFunctionStatementPlaceholder: BuiltinFunctionStatementPlaceholder) { - output(builtinFunctionStatementPlaceholder.name) - } - override fun visit(whenStatement: WhenStatement) { output("when ") whenStatement.condition.accept(this) diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index df1923fb5..8a7d6aeb3 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -34,8 +34,8 @@ sealed class Statement : Node { class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position) : Statement() { override var parent: Node = ParentSentinel override fun linkParents(parent: Node) {} - override fun accept(visitor: IAstVisitor) = visitor.visit(this) - override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun accept(visitor: IAstVisitor) = throw FatalAstException("should not iterate over this node") + override fun accept(visitor: AstWalker, parent: Node) = throw FatalAstException("should not iterate over this node") override fun definingScope(): INameScope = BuiltinFunctionScopePlaceholder override fun replaceChildNode(node: Node, replacement: Node) { replacement.parent = this diff --git a/compilerAst/src/prog8/ast/walk/AstWalker.kt b/compilerAst/src/prog8/ast/walk/AstWalker.kt index 09d2e48c7..09b6c0594 100644 --- a/compilerAst/src/prog8/ast/walk/AstWalker.kt +++ b/compilerAst/src/prog8/ast/walk/AstWalker.kt @@ -84,7 +84,6 @@ abstract class AstWalker { open fun before(block: Block, parent: Node): Iterable = emptyList() open fun before(branchStatement: BranchStatement, parent: Node): Iterable = emptyList() open fun before(breakStmt: Break, parent: Node): Iterable = emptyList() - open fun before(builtinFunctionStatementPlaceholder: BuiltinFunctionStatementPlaceholder, parent: Node): Iterable = emptyList() open fun before(decl: VarDecl, parent: Node): Iterable = emptyList() open fun before(directive: Directive, parent: Node): Iterable = emptyList() open fun before(expr: BinaryExpression, parent: Node): Iterable = emptyList() @@ -395,11 +394,6 @@ abstract class AstWalker { track(after(inlineAssembly, parent), inlineAssembly, parent) } - fun visit(builtinFunctionStatementPlaceholder: BuiltinFunctionStatementPlaceholder, parent: Node) { - track(before(builtinFunctionStatementPlaceholder, parent), builtinFunctionStatementPlaceholder, parent) - track(after(builtinFunctionStatementPlaceholder, parent), builtinFunctionStatementPlaceholder, parent) - } - fun visit(nopStatement: NopStatement, parent: Node) { track(before(nopStatement, parent), nopStatement, parent) track(after(nopStatement, parent), nopStatement, parent) diff --git a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt index c46b9e7ab..8a2838e7d 100644 --- a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt +++ b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt @@ -158,9 +158,6 @@ interface IAstVisitor { fun visit(inlineAssembly: InlineAssembly) { } - fun visit(builtinFunctionStatementPlaceholder: BuiltinFunctionStatementPlaceholder) { - } - fun visit(nopStatement: NopStatement) { } diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 9ce1bfc5d..1a60b7e7e 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -803,6 +803,11 @@ mkword(msb, lsb) Don't get confused by how the system actually stores this 16-bit word value in memory (which is in little-endian format, so lsb first then msb) +peek(address) + same as @(address) - reads the byte at the given address in memory. + +peekw(address) + reads the word value at the given address in memory. Word is assumed to be stored in usual lsb/msb byte order. rnd() returns a pseudo-random byte from 0..255 diff --git a/examples/test.p8 b/examples/test.p8 index 93d7cc7ec..24150777c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -10,16 +10,16 @@ main { @(ptr) = $34 @(ptr+1) = $ea - txt.print_ubhex(@(ptr), 1) - txt.print_ubhex(@(ptr+1), 1) + txt.print_ubhex(peek(ptr), 1) + txt.print_ubhex(peek(ptr+1), 1) txt.nl() - uword ww = mkword(@(ptr+1), @(ptr)) ; TODO FIX + uword ww = peekw(ptr) txt.print_uwhex(ww,1) txt.nl() - ubyte low = @(ptr) - ubyte high = @(ptr+1) + ubyte low = peek(ptr) + ubyte high = peek(ptr+1) ww = mkword(high, low) txt.print_uwhex(ww,1) txt.nl()