implementing more of the vm

This commit is contained in:
Irmen de Jong 2022-03-27 21:59:46 +02:00
parent 4e33ab1e89
commit 30cbb6c9a8
8 changed files with 153 additions and 91 deletions

View File

@ -56,9 +56,9 @@ class CodeGen(internal val program: PtProgram,
is PtNop -> VmCodeChunk() is PtNop -> VmCodeChunk()
is PtReturn -> translate(node) is PtReturn -> translate(node)
is PtJump -> translate(node) is PtJump -> translate(node)
is PtWhen -> TODO() is PtWhen -> TODO("when")
is PtPipe -> expressionEval.translate(node, regUsage.nextFree(), regUsage) is PtPipe -> expressionEval.translate(node, regUsage.nextFree(), regUsage)
is PtForLoop -> TODO() is PtForLoop -> TODO("for-loop")
is PtIfElse -> translate(node, regUsage) is PtIfElse -> translate(node, regUsage)
is PtPostIncrDecr -> translate(node, regUsage) is PtPostIncrDecr -> translate(node, regUsage)
is PtRepeatLoop -> translate(node, regUsage) is PtRepeatLoop -> translate(node, regUsage)
@ -219,7 +219,19 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(ins) code += VmCodeInstruction(ins)
} }
else if(array!=null) { else if(array!=null) {
TODO("assign to array") val variable = array.variable.targetName
var variableAddr = allocations.get(variable)
val itemsize = program.memsizer.memorySize(array.type)
val fixedIndex = (array.index as? PtNumber)?.number?.toInt()
val vmDtArrayIdx = vmType(array.type)
if(fixedIndex!=null) {
variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(Instruction(Opcode.LOADM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr))
} else {
val indexReg = regUsage.nextFree()
code += expressionEval.translateExpression(array.index, indexReg, regUsage)
code += VmCodeInstruction(Instruction(Opcode.LOADX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr))
}
} }
else if(memory!=null) { else if(memory!=null) {
val ins = val ins =

View File

@ -365,16 +365,58 @@ internal class ExpressionGen(val codeGen: CodeGen) {
val name = (call.args[0] as PtString).value val name = (call.args[0] as PtString).value
val size = (call.args[1] as PtNumber).number.toUInt() val size = (call.args[1] as PtNumber).number.toUInt()
val align = (call.args[2] as PtNumber).number.toUInt() val align = (call.args[2] as PtNumber).number.toUInt()
TODO("Memory($name, $size, $align)") val existing = codeGen.allocations.getMemorySlab(name)
val address = if(existing==null)
codeGen.allocations.allocateMemorySlab(name, size, align)
else if(existing.second!=size || existing.third!=align) {
codeGen.errors.err("memory slab '$name' already exists with a different size or alignment", call.position)
return VmCodeChunk()
}
else
existing.first
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt()))
} }
"rnd" -> { "rnd" -> {
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=Syscall.RND.ordinal)) code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=Syscall.RND.ordinal))
if(resultRegister!=0) if(resultRegister!=0)
code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)) code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0))
} }
"peek" -> {
val addressReg = regUsage.nextFree()
code += translateExpression(call.args.single(), addressReg, regUsage)
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg))
}
"peekw" -> {
val addressReg = regUsage.nextFree()
code += translateExpression(call.args.single(), addressReg, regUsage)
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg))
}
"memory" -> {
val memname = (call.args[0] as PtString).value
val size = (call.args[1] as PtNumber).number.toInt()
val align = (call.args[2] as PtNumber).number.toInt()
TODO("memory '$memname', $size, $align")
}
else -> { else -> {
// TODO builtin functions...
TODO("builtinfunc ${call.name}") TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Instruction(Opcode.NOP))
// for (arg in call.args) {
// code += translateExpression(arg, resultRegister, regUsage)
// code += when(arg.type) {
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister))
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister))
// else -> throw AssemblyError("weird arg dt")
// }
// }
// code += VmCodeInstruction(Instruction(Opcode.CALL), labelArg = listOf("_prog8_builtin", call.name))
// for (arg in call.args) {
// code += when(arg.type) {
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1=resultRegister))
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1=resultRegister))
// else -> throw AssemblyError("weird arg dt")
// }
// }
// code += VmCodeInstruction(Instruction(Opcode.NOP))
} }
} }
return code return code

View File

@ -7,7 +7,10 @@ import prog8.code.core.*
class VariableAllocator(private val st: SymbolTable, private val program: PtProgram, errors: IErrorReporter) { class VariableAllocator(private val st: SymbolTable, private val program: PtProgram, errors: IErrorReporter) {
private val allocations = mutableMapOf<List<String>, Int>() private val allocations = mutableMapOf<List<String>, Int>()
val freeStart: Int private var freeMemoryStart: Int
val freeMem: Int
get() = freeMemoryStart
init { init {
var nextLocation = 0 var nextLocation = 0
@ -24,7 +27,7 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg
nextLocation += memsize nextLocation += memsize
} }
freeStart = nextLocation freeMemoryStart = nextLocation
} }
fun get(name: List<String>) = allocations.getValue(name) fun get(name: List<String>) = allocations.getValue(name)
@ -68,4 +71,21 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg
} }
return mm return mm
} }
private val memorySlabsInternal = mutableMapOf<String, Triple<UInt, UInt, UInt>>()
internal val memorySlabs: Map<String, Triple<UInt, UInt, UInt>> = memorySlabsInternal
fun allocateMemorySlab(name: String, size: UInt, align: UInt): UInt {
val address =
if(align==0u || align==1u)
freeMemoryStart.toUInt()
else
(freeMemoryStart.toUInt() + align-1u) and (0xffffffffu xor (align-1u))
memorySlabsInternal[name] = Triple(address, size, align)
freeMemoryStart = (address + size).toInt()
return address
}
fun getMemorySlab(name: String): Triple<UInt, UInt, UInt>? = memorySlabsInternal[name]
} }

View File

@ -399,7 +399,7 @@ class StatementOptimizer(private val program: Program,
if (rightCv == 0.0) { if (rightCv == 0.0) {
return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) return listOf(IAstModification.Remove(assignment, parent as IStatementContainer))
} else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) { } else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) {
if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0) { if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0 && compTarget.name!=VMTarget.NAME) {
// replace by several INCs if it's not a memory address (inc on a memory mapped register doesn't work very well) // replace by several INCs if it's not a memory address (inc on a memory mapped register doesn't work very well)
val incs = AnonymousScope(mutableListOf(), assignment.position) val incs = AnonymousScope(mutableListOf(), assignment.position)
repeat(rightCv.toInt()) { repeat(rightCv.toInt()) {
@ -413,7 +413,7 @@ class StatementOptimizer(private val program: Program,
if (rightCv == 0.0) { if (rightCv == 0.0) {
return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) return listOf(IAstModification.Remove(assignment, parent as IStatementContainer))
} else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) { } else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) {
if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0) { if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0 && compTarget.name!=VMTarget.NAME) {
// replace by several DECs if it's not a memory address (dec on a memory mapped register doesn't work very well) // replace by several DECs if it's not a memory address (dec on a memory mapped register doesn't work very well)
val decs = AnonymousScope(mutableListOf(), assignment.position) val decs = AnonymousScope(mutableListOf(), assignment.position)
repeat(rightCv.toInt()) { repeat(rightCv.toInt()) {

View File

@ -8,33 +8,33 @@ prog8_lib {
%option force_output %option force_output
sub string_contains(ubyte needle, str haystack) -> ubyte { sub string_contains(ubyte needle, str haystack) -> ubyte {
txt.print(">>>string elt check: ") repeat {
txt.print_ub(needle) if @(haystack)==0
txt.spc() return false
txt.print_uwhex(haystack, true) if @(haystack)==needle
txt.nl() return true
return 0 haystack++
}
} }
sub bytearray_contains(ubyte needle, uword haystack_ptr, ubyte num_elements) -> ubyte { sub bytearray_contains(ubyte needle, uword haystack_ptr, ubyte num_elements) -> ubyte {
txt.print(">>>bytearray elt check: ") haystack_ptr--
txt.print_ub(needle) while num_elements {
txt.spc() if haystack_ptr[num_elements]==needle
txt.print_uwhex(haystack_ptr, true) return true
txt.spc() num_elements--
txt.print_ub(num_elements) }
txt.nl() return false
return 0
} }
sub wordarray_contains(ubyte needle, uword haystack_ptr, ubyte num_elements) -> ubyte { sub wordarray_contains(ubyte needle, uword haystack_ptr, ubyte num_elements) -> ubyte {
txt.print(">>>wordarray elt check: ") haystack_ptr += (num_elements-1) * 2
txt.print_ub(needle) while num_elements {
txt.spc() if peekw(haystack_ptr)==needle
txt.print_uwhex(haystack_ptr, true) return true
txt.spc() haystack_ptr -= 2
txt.print_ub(num_elements) num_elements--
txt.nl() }
return 0 return false
} }
} }

View File

@ -1,5 +1,5 @@
%import textio %import textio
%import test_stack ; %import test_stack
%zeropage basicsafe %zeropage basicsafe
; Note: this program is compatible with C64 and CX16. ; Note: this program is compatible with C64 and CX16.

View File

@ -1,4 +1,3 @@
%import floats
%import textio %import textio
; NOTE: meant to test to virtual machine output target (use -target vitual) ; NOTE: meant to test to virtual machine output target (use -target vitual)
@ -8,67 +7,55 @@ main {
txt.clear_screen() txt.clear_screen()
txt.print("Welcome to a prog8 pixel shader :-)\n") txt.print("Welcome to a prog8 pixel shader :-)\n")
float fl = 9.9 uword @shared chunk = memory("irmen", 4000, 256)
fl = floats.pow(fl, 3.3) txt.print_uwhex(chunk,true)
floats.print_f(fl)
txt.nl() txt.nl()
ubyte ww = 65
fl = ww ubyte bb = 4
fl += 0.1 ubyte[] array = [1,2,3,4,5,6]
floats.print_f(fl) uword[] warray = [1111,2222,3333]
str tekst = "test"
uword ww = 19
bb = bb in "teststring"
bb++
bb = bb in [1,2,3,4,5,6]
bb++
bb = bb in array
bb++
bb = bb in tekst
bb++
bb = ww in warray
bb++
bb = 666 in warray
bb ++
bb = '?' in tekst
bb++
txt.print("bb=")
txt.print_ub(bb)
txt.nl() txt.nl()
uword ww2 = 65432 sys.exit(99)
fl = ww2
fl += 0.1
floats.print_f(fl)
syscall1(8, 0) ; enable lo res creen
ubyte shifter
; ubyte bb = 4 shifter >>= 1
; ubyte[] array = [1,2,3,4,5,6]
; uword[] warray = [1111,2222,3333] repeat {
; str tekst = "test" uword xx
; uword ww = 19 uword yy = 0
; bb = bb in "teststring" repeat 240 {
; bb++ xx = 0
; bb = bb in [1,2,3,4,5,6] repeat 320 {
; bb++ syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel
; bb = bb in array xx++
; bb++ }
; bb = bb in tekst yy++
; bb++ }
; bb = ww in warray shifter+=4
; bb++
; bb = 666 in warray txt.print_ub(shifter)
; bb ++ txt.nl()
; bb = '?' in tekst }
; bb++
; txt.print("bb=")
; txt.print_ub(bb)
; txt.nl()
; sys.exit(99)
;
;
; syscall1(8, 0) ; enable lo res creen
; ubyte shifter
;
; shifter >>= 1
;
; repeat {
; uword xx
; uword yy = 0
; repeat 240 {
; xx = 0
; repeat 320 {
; syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel
; xx++
; }
; yy++
; }
; shifter+=4
;
; txt.print_ub(shifter)
; txt.nl()
; }
} }
} }

View File

@ -32,7 +32,7 @@ enum class Syscall {
GFX_ENABLE, GFX_ENABLE,
GFX_CLEAR, GFX_CLEAR,
GFX_PLOT, GFX_PLOT,
RND RND,
} }
object SysCalls { object SysCalls {
@ -82,6 +82,7 @@ object SysCalls {
Syscall.RND -> { Syscall.RND -> {
vm.registers.setB(0, (Random.nextInt() ushr 3).toUByte()) vm.registers.setB(0, (Random.nextInt() ushr 3).toUByte())
} }
else -> TODO("syscall ${call.name}")
} }
} }
} }