From 09d3451d9dd8a71aa575c94812161566a97ce37c Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 5 May 2022 21:24:44 +0200 Subject: [PATCH] vm: accept %asmbinary (but it is eventually ignored in code execution) --- .../prog8/codegen/virtual/AssemblyProgram.kt | 11 +++++++ .../src/prog8/codegen/virtual/CodeGen.kt | 5 +-- docs/source/todo.rst | 11 +++---- examples/test.p8 | 32 +++---------------- virtualmachine/src/prog8/vm/Assembler.kt | 4 +++ 5 files changed, 27 insertions(+), 36 deletions(-) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt b/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt index cd4f5f74a..166608239 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt @@ -8,6 +8,7 @@ import prog8.vm.Opcode import prog8.vm.OpcodesWithAddress import prog8.vm.VmDataType import java.io.BufferedWriter +import java.nio.file.Path import kotlin.io.path.bufferedWriter import kotlin.io.path.div @@ -53,6 +54,14 @@ internal class AssemblyProgram(override val name: String, allocations.get(name).toString() } write(asm+"\n") } + is VmCodeInlineBinary -> { + write("incbin \"${line.file}\"") + if(line.offset!=null) + write(",${line.offset}") + if(line.length!=null) + write(",${line.length}") + write("\n") + } else -> throw AssemblyError("invalid vm code line") } } @@ -131,3 +140,5 @@ internal class VmCodeChunk(initial: VmCodeLine? = null) { internal class VmCodeInlineAsm(asm: String): VmCodeLine() { val assembly: String = asm.trimIndent() } + +internal class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine() diff --git a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt index 73bc80218..3f3ec3eb2 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt @@ -6,6 +6,7 @@ import prog8.code.ast.* import prog8.code.core.* import prog8.vm.Opcode import prog8.vm.VmDataType +import java.nio.file.Path import kotlin.math.pow @@ -92,6 +93,8 @@ class CodeGen(internal val program: PtProgram, is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT)) is PtConditionalBranch -> translate(node) is PtInlineAssembly -> VmCodeChunk(VmCodeInlineAsm(node.assembly)) + is PtIncludeBinary -> VmCodeChunk(VmCodeInlineBinary(node.file, node.offset, node.length)) + is PtAsmSub -> TODO("asmsub not yet supported on virtual machine target ${node.position}") is PtAddressOf, is PtContainmentCheck, is PtMemoryByte, @@ -108,8 +111,6 @@ class CodeGen(internal val program: PtProgram, is PtNumber, is PtArray, is PtString -> throw AssemblyError("should not occur as separate statement node ${node.position}") - is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target ${node.position}") - is PtIncludeBinary -> throw AssemblyError("inline binary data not supported on virtual machine target ${node.position}") else -> TODO("missing codegen for $node") } if(code.lines.isNotEmpty() && node.position.line!=0) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index fdccd323b..9ff4391b2 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- vm: get rid of intermediate floats.xxx() functions somehow, instead generate the float instructions directly? - pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls. - allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type - make it possible to inline non-asmsub routines that just contain a single statement (return, functioncall, assignment) @@ -26,8 +25,9 @@ Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ Compiler: +- vm: add way more instructions operating directly on memory instead of only registers - vm: codeGen: various TODOs to tweak code -- vm: codeGen: optimize codegen for comparison expressions in if statements, such as if x==0 ... else ... +- vm: somehow deal with asmsubs otherwise the vm IR can't fully encode all of prog8 - vm: make registers typed? so that it's immediately obvious what type they represent. Much like regular variables in memory. so we have a set of byte registers, a set of word registers, and other sets if we introduce other types. - vm: don't store symbol names in instructions to make optimizing the IR easier? but what about jumps to labels. And it's no longer readable by humans. @@ -36,14 +36,12 @@ Compiler: - when the vm is stable and *if* its language can get promoted to prog8 IL, the variable allocation should be changed. It's now done before the vm code generation, but the IL should probably not depend on the allocations already performed. So the CodeGen doesn't do VariableAlloc *before* the codegen, but as a last step. -- vm code gen: don't reuse registers and don't pre allocate variables? (except strings + arrays) but instead put them into registers too - then we ALMOST have Static Single Assignment form in the VM code. But what can we use that for? - createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there. but probably better to rewrite the 6502 codegen on top of the new Ast. - make everything an expression? (get rid of Statements. Statements are expressions with void return types?). - simplifyConditionalExpression() should not split expression if it still results in stack-based evaluation, but how does it know? - simplifyConditionalExpression() sometimes introduces needless assignment to r9 tempvar (what scenarios?) -- consider adding McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value? +- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value? - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway) then we can get rid of the instruction lists in the machinedefinitions as well? - [problematic due to using 64tass:] add a compiler option to not remove unused subroutines. this allows for building library programs. But this won't work with 64tass's .proc ... @@ -61,13 +59,14 @@ Libraries: - optimize several inner loops in gfx2 even further? - add modes 2 and 3 to gfx2 (lowres 4 color and 16 color)? - add a flood fill routine to gfx2? -- add a diskio.f_seek() routine for the Cx16 that uses its seek dos api? (only if that's stable) - diskio: use cx16 MACPTR() to load stuff faster? (see it's use in X16edit to fast load blocks) note that it might fail on non sdcard files so have to make graceful degradation +- add a diskio.f_seek() routine for the Cx16 that uses its seek dos api? (only if that's stable) Expressions: - rethink the whole "isAugmentable" business. Because the way this is determined, should always also be exactly mirrorred in the AugmentableAssignmentAsmGen or you'll get a crash at code gen time. + note: new ast PtAssignment already has no knowledge about this anymore. - can we get rid of pieces of asmgen.AssignmentAsmGen by just reusing the AugmentableAssignment ? generated code should not suffer - rewrite expression tree evaluation suchthat it doesn't use an eval stack but flatten the tree into linear code that uses a fixed number of predetermined value 'variables'? "Three address code" was mentioned. https://en.wikipedia.org/wiki/Three-address_code diff --git a/examples/test.p8 b/examples/test.p8 index 050055516..e1d1f45dd 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,39 +1,15 @@ %import textio -%import floats -%import conv %zeropage dontuse ; NOTE: meant to test to virtual machine output target (use -target vitual) main { + sub start() { - float fl = -4.55 - floats.print_f(floats.fabs(fl)) - txt.nl() - floats.print_f(floats.sin(fl)) - txt.nl() - floats.print_f(floats.cos(fl)) - txt.nl() - floats.print_f(floats.tan(fl)) - txt.nl() - floats.print_f(floats.atan(fl)) - txt.nl() - floats.print_f(floats.round(fl)) - txt.nl() - floats.print_f(floats.floor(fl)) - txt.nl() - floats.print_f(floats.ceil(fl)) - txt.nl() - fl = 4.55 - floats.print_f(floats.ln(fl)) - txt.nl() - floats.print_f(floats.log2(fl)) - txt.nl() - floats.print_f(floats.sqrt(fl)) - txt.nl() - floats.print_f(floats.pow(fl, 2.2)) ; TODO fix illegal quantity error - txt.nl() + ubyte xx=10 + xx = xx>9 + txt.print_ub(xx) sys.exit(42) ; floats.print_f(-42.42) ; float f1 = 1.2345 diff --git a/virtualmachine/src/prog8/vm/Assembler.kt b/virtualmachine/src/prog8/vm/Assembler.kt index 7aa06986c..5cdec251e 100644 --- a/virtualmachine/src/prog8/vm/Assembler.kt +++ b/virtualmachine/src/prog8/vm/Assembler.kt @@ -80,6 +80,10 @@ class Assembler { } } else { val (_, instr, typestr, rest) = match.groupValues + if(instr=="incbin") { + println("warning: ignoring incbin command: $rest") + continue + } val opcode = Opcode.valueOf(instr.uppercase()) var type: VmDataType? = convertType(typestr) val formats = instructionFormats.getValue(opcode)