mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
decide sim is not worth it-remove it again
This commit is contained in:
parent
61398ee8f8
commit
240e6835c2
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@ -14,7 +14,6 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/httpCompilerService/httpCompilerService.iml" filepath="$PROJECT_DIR$/httpCompilerService/httpCompilerService.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/simulator/simulator.iml" filepath="$PROJECT_DIR$/simulator/simulator.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -26,7 +26,6 @@ compileTestKotlin {
|
||||
dependencies {
|
||||
implementation project(':compilerInterfaces')
|
||||
implementation project(':compilerAst')
|
||||
implementation project(':simulator')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.14"
|
||||
|
@ -12,6 +12,5 @@
|
||||
<orderEntry type="module" module-name="compilerAst" />
|
||||
<orderEntry type="module" module-name="compilerInterfaces" />
|
||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||
<orderEntry type="module" module-name="simulator" />
|
||||
</component>
|
||||
</module>
|
@ -2,7 +2,6 @@ package prog8.codegen.experimental6502
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.compilerinterface.*
|
||||
import prog8.sim.Simulator
|
||||
|
||||
class AsmGen(internal val program: Program,
|
||||
internal val errors: IErrorReporter,
|
||||
@ -20,9 +19,6 @@ class AsmGen(internal val program: Program,
|
||||
val intermediateAst = IntermediateAstMaker(program).transform()
|
||||
intermediateAst.print()
|
||||
|
||||
val sim = Simulator(intermediateAst, symbolTable)
|
||||
sim.run()
|
||||
|
||||
println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
|
||||
return AssemblyProgram("dummy")
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ include(
|
||||
':codeGenCpu6502',
|
||||
':codeGenExperimental6502',
|
||||
':compiler',
|
||||
':simulator',
|
||||
':dbusCompilerService',
|
||||
':httpCompilerService'
|
||||
)
|
||||
|
@ -1,73 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'application'
|
||||
id "org.jetbrains.kotlin.jvm"
|
||||
id "io.kotest" version "0.3.9"
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
}
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion
|
||||
}
|
||||
}
|
||||
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':compilerInterfaces')
|
||||
implementation project(':compilerAst')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.4'
|
||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.14"
|
||||
|
||||
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.1.0'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs = ["${project.projectDir}/src"]
|
||||
}
|
||||
resources {
|
||||
srcDirs = ["${project.projectDir}/res"]
|
||||
}
|
||||
}
|
||||
test {
|
||||
java {
|
||||
srcDir "${project.projectDir}/test"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startScripts.enabled = true
|
||||
|
||||
application {
|
||||
mainClass = 'prog8.SimulatorMainKt'
|
||||
applicationName = 'p8sim'
|
||||
}
|
||||
|
||||
test {
|
||||
// Enable JUnit 5 (Gradle 4.6+).
|
||||
useJUnitPlatform()
|
||||
|
||||
// Always run tests, even when nothing changed.
|
||||
dependsOn 'cleanTest'
|
||||
|
||||
// Show test results.
|
||||
testLogging {
|
||||
events "skipped", "failed"
|
||||
}
|
||||
}
|
||||
|
||||
build.finalizedBy installDist
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
<orderEntry type="module" module-name="compilerInterfaces" />
|
||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
||||
<orderEntry type="library" name="io.kotest.assertions.core.jvm" level="project" />
|
||||
<orderEntry type="module" module-name="compilerAst" />
|
||||
</component>
|
||||
</module>
|
@ -1,45 +0,0 @@
|
||||
package prog8
|
||||
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.statements.AssignmentOrigin
|
||||
import prog8.compilerinterface.Encoding
|
||||
import prog8.compilerinterface.SymbolTable
|
||||
import prog8.compilerinterface.intermediate.*
|
||||
import prog8.sim.MemSizer
|
||||
import prog8.sim.Simulator
|
||||
import prog8.sim.StringEncoding
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println("\nProg8 simulator by Irmen de Jong (irmen@razorvine.net)")
|
||||
println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n")
|
||||
println("...todo: run from file...")
|
||||
|
||||
val program = PtProgram("test", MemSizer, StringEncoding)
|
||||
val module = PtModule("test", 0u, false, Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), emptyList(), false, Position.DUMMY)
|
||||
block.add(sub)
|
||||
module.add(block)
|
||||
program.add(module)
|
||||
val fcall = PtBuiltinFunctionCall("print", Position.DUMMY).also {
|
||||
it.add(PtString("Hello, world! From the program.\n", Encoding.DEFAULT, Position.DUMMY))
|
||||
}
|
||||
sub.add(fcall)
|
||||
val memwrite = PtAssignment(false, AssignmentOrigin.USERCODE, Position.DUMMY).also { assign ->
|
||||
assign.add(PtAssignTarget(Position.DUMMY).also { tgt ->
|
||||
tgt.add(PtMemoryByte(Position.DUMMY).also { mb ->
|
||||
mb.add(PtNumber(DataType.UWORD, 1000.0, Position.DUMMY))
|
||||
})
|
||||
})
|
||||
assign.add(PtNumber(DataType.UBYTE, 99.0, Position.DUMMY))
|
||||
}
|
||||
sub.add(memwrite)
|
||||
sub.add(PtReturn(Position.DUMMY))
|
||||
val symboltable = SymbolTable()
|
||||
|
||||
val sim = Simulator(program, symboltable)
|
||||
println("memory at $1000=${sim.memory[1000u]}")
|
||||
sim.run()
|
||||
println("memory at $1000=${sim.memory[1000u]}")
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package prog8.sim
|
||||
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.StringLiteral
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.compilerinterface.Encoding
|
||||
import prog8.compilerinterface.IMemSizer
|
||||
import prog8.compilerinterface.IStringEncoding
|
||||
|
||||
internal object MemSizer: IMemSizer {
|
||||
override fun memorySize(dt: DataType): Int {
|
||||
return when(dt) {
|
||||
in ByteDatatypes -> 1
|
||||
in WordDatatypes, in PassByReferenceDatatypes -> 2
|
||||
DataType.FLOAT -> Double.SIZE_BYTES
|
||||
else -> Int.MIN_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
override fun memorySize(decl: VarDecl): Int {
|
||||
return when(decl.type) {
|
||||
VarDeclType.CONST -> 0
|
||||
VarDeclType.VAR, VarDeclType.MEMORY -> {
|
||||
when(val dt = decl.datatype) {
|
||||
in NumericDatatypes -> return memorySize(dt)
|
||||
in ArrayDatatypes -> decl.arraysize!!.constIndex()!! * memorySize(ArrayToElementTypes.getValue(dt))
|
||||
DataType.STR -> (decl.value as StringLiteral).value.length + 1
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object StringEncoding: IStringEncoding {
|
||||
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
package prog8.sim
|
||||
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.PassByReferenceDatatypes
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.expressions.AddressOf
|
||||
import prog8.compilerinterface.Encoding
|
||||
import prog8.compilerinterface.StNodeType
|
||||
import prog8.compilerinterface.StStaticVariable
|
||||
import prog8.compilerinterface.SymbolTable
|
||||
import prog8.compilerinterface.intermediate.*
|
||||
|
||||
class Evaluator(
|
||||
val symboltable: SymbolTable,
|
||||
val memory: Memory,
|
||||
val variables: Variables,
|
||||
val simulator: Simulator
|
||||
) {
|
||||
|
||||
fun evaluateExpression(expr: PtNode): Pair<Double, DataType> {
|
||||
return when(expr) {
|
||||
is PtAddressOf -> evaluate(expr)
|
||||
is PtArrayIndexer -> evaluate(expr)
|
||||
is PtArrayLiteral -> throw IllegalArgumentException("arrayliteral $expr")
|
||||
is PtBinaryExpression -> evaluate(expr)
|
||||
is PtBuiltinFunctionCall -> evaluate(expr)
|
||||
is PtConstant -> Pair(expr.value, expr.type)
|
||||
is PtContainmentCheck -> TODO()
|
||||
is PtFunctionCall -> evaluate(expr)
|
||||
is PtIdentifier -> evaluate(expr)
|
||||
is PtMemoryByte -> evaluate(expr)
|
||||
is PtNumber -> Pair(expr.number, expr.type)
|
||||
is PtPipe -> TODO()
|
||||
is PtPrefix -> TODO()
|
||||
is PtRange -> throw IllegalArgumentException("range $expr")
|
||||
is PtString -> throw IllegalArgumentException("string $expr")
|
||||
is PtTypeCast -> TODO()
|
||||
else -> TODO("missing evaluator for $expr")
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluate(memoryByte: PtMemoryByte): Pair<Double, DataType> {
|
||||
val address = evaluateExpression(memoryByte.address).first.toUInt()
|
||||
val value = memory[address]
|
||||
return Pair(value.toDouble(), DataType.UBYTE)
|
||||
}
|
||||
|
||||
private fun evaluate(arrayIdx: PtArrayIndexer): Pair<Double, DataType> {
|
||||
val index = evaluateExpression(arrayIdx.index)
|
||||
println("TODO: get array value ${arrayIdx.variable.ref}[${index.first.toInt()}]")
|
||||
return Pair(0.0, DataType.UBYTE)
|
||||
}
|
||||
|
||||
internal fun evaluate(expr: PtBinaryExpression): Pair<Double, DataType> {
|
||||
val left = evaluateExpression(expr.left)
|
||||
val right = evaluateExpression(expr.right)
|
||||
require(left.second==right.second)
|
||||
|
||||
// TODO implement 8/16 bit maths
|
||||
|
||||
return when(expr.operator) {
|
||||
"+" -> Pair(left.first+right.first, left.second)
|
||||
"-" -> Pair(left.first-right.first, left.second)
|
||||
"*" -> Pair(left.first*right.first, left.second)
|
||||
"/" -> Pair(left.first/right.first, left.second)
|
||||
"==" -> {
|
||||
val bool = if(left.first==right.first) 1 else 0
|
||||
Pair(bool.toDouble(), DataType.UBYTE)
|
||||
}
|
||||
"!=" -> {
|
||||
val bool = if(left.first!=right.first) 1 else 0
|
||||
Pair(bool.toDouble(), DataType.UBYTE)
|
||||
}
|
||||
"<" -> {
|
||||
val bool = if(left.first<right.first) 1 else 0
|
||||
Pair(bool.toDouble(), DataType.UBYTE)
|
||||
}
|
||||
">" -> {
|
||||
val bool = if(left.first>right.first) 1 else 0
|
||||
Pair(bool.toDouble(), DataType.UBYTE)
|
||||
}
|
||||
"<=" -> {
|
||||
val bool = if(left.first<=right.first) 1 else 0
|
||||
Pair(bool.toDouble(), DataType.UBYTE)
|
||||
}
|
||||
">=" -> {
|
||||
val bool = if(left.first>=right.first) 1 else 0
|
||||
Pair(bool.toDouble(), DataType.UBYTE)
|
||||
}
|
||||
|
||||
else -> TODO("binexpr operator ${expr.operator}")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun evaluate(fcall: PtFunctionCall): Pair<Double, DataType> {
|
||||
val ref = fcall.target.ref
|
||||
val args = fcall.args.children.map { evaluateExpression(it) }
|
||||
return when(fcall.target.targetName) {
|
||||
listOf("sys", "memset") -> {
|
||||
memory.memset(args[0].first.toUInt(), args[1].first.toUInt(), args[2].first.toInt().toUByte())
|
||||
Pair(0.0, DataType.UBYTE)
|
||||
}
|
||||
listOf("txt", "print") -> {
|
||||
print(memory.getString(args.single().first.toUInt())) // strings are passed as a memory address
|
||||
Pair(0.0, DataType.UBYTE)
|
||||
}
|
||||
listOf("txt", "print_uw") -> {
|
||||
print(args.single().first.toUInt())
|
||||
Pair(0.0, DataType.UBYTE)
|
||||
}
|
||||
else -> {
|
||||
val node = findPtNode(fcall.target.targetName, fcall)
|
||||
if(node is PtAsmSub)
|
||||
throw NotImplementedError("simulator can't run asmsub ${node.name}")
|
||||
node as PtSub
|
||||
passCallArgs(node, args)
|
||||
simulator.instructionPtrStack.push(simulator.ip)
|
||||
simulator.ip = InstructionPointer(node.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun evaluate(fcall: PtBuiltinFunctionCall): Pair<Double, DataType> {
|
||||
println("TODO: builtin function call ${fcall.name}")
|
||||
return Pair(0.0, DataType.UBYTE)
|
||||
}
|
||||
|
||||
private fun passCallArgs(sub: PtSub, args: List<Pair<Double, DataType>>) {
|
||||
require(sub.parameters.size==args.size)
|
||||
for ((param, arg) in sub.parameters.zip(args)) {
|
||||
require(param.type==arg.second)
|
||||
println("ARG ${param.name} = ${arg.first}") // TODO assign arg
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluate(ident: PtIdentifier): Pair<Double, DataType> {
|
||||
val target = symboltable.flat.getValue(ident.targetName)
|
||||
when(target.type) {
|
||||
StNodeType.STATICVAR -> {
|
||||
val variable = target as StStaticVariable
|
||||
val value = variables.getValue(variable)
|
||||
if(value.number==null){
|
||||
if(variable.dt in PassByReferenceDatatypes) {
|
||||
// return the address instead
|
||||
val addrof = PtAddressOf(ident.position)
|
||||
addrof.add(PtIdentifier(ident.ref, ident.targetName, ident.position))
|
||||
return evaluate(addrof)
|
||||
} else
|
||||
throw IllegalArgumentException("invalid dt")
|
||||
}
|
||||
return Pair(value.number, target.dt)
|
||||
}
|
||||
StNodeType.CONSTANT -> throw IllegalArgumentException("constants should have been const folded")
|
||||
else -> throw IllegalArgumentException("weird ref target")
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluate(addressOf: PtAddressOf): Pair<Double, DataType> {
|
||||
val target = symboltable.flat.getValue(addressOf.identifier.targetName) as StStaticVariable
|
||||
return Pair(variables.getAddress(target).toDouble(), DataType.UWORD)
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package prog8.sim
|
||||
|
||||
import prog8.compilerinterface.intermediate.PtNode
|
||||
|
||||
class InstructionPointer(var instructions: List<PtNode>, start: Int=0) {
|
||||
var currentIdx = start
|
||||
val current: PtNode
|
||||
get() {
|
||||
if(currentIdx<instructions.size)
|
||||
return instructions[currentIdx]
|
||||
else
|
||||
throw IllegalArgumentException("expected Return statement at end of statement list")
|
||||
}
|
||||
|
||||
init {
|
||||
require(instructions.isNotEmpty())
|
||||
}
|
||||
|
||||
fun next() {
|
||||
currentIdx++
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package prog8.sim
|
||||
|
||||
class Memory {
|
||||
val mem = ByteArray(65536)
|
||||
|
||||
operator fun get(addresss: UInt): UByte = getSByte(addresss).toUByte()
|
||||
|
||||
operator fun set(address: UInt, value: UByte) = setSByte(address, value.toByte())
|
||||
|
||||
fun getSByte(address: UInt): Byte = mem[address.toInt()]
|
||||
|
||||
fun setSByte(address: UInt, value: Byte) {
|
||||
mem[address.toInt()] = value
|
||||
}
|
||||
|
||||
fun getSWord(address: UInt): Int {
|
||||
val word = getWord(address).toInt()
|
||||
return if(word>=32768)
|
||||
-(65536-word)
|
||||
else
|
||||
word
|
||||
}
|
||||
|
||||
fun setSWord(address: UInt, value: Int) = setWord(address, value.toUInt())
|
||||
|
||||
fun getWord(address: UInt): UInt {
|
||||
val lsb = mem[address.toInt()].toUByte()
|
||||
val msb = mem[address.toInt()+1].toUByte()
|
||||
return lsb + msb*256u
|
||||
}
|
||||
|
||||
fun setWord(address: UInt, value: UInt) {
|
||||
val lsb = value.toByte()
|
||||
val msb = (value shr 8).toByte()
|
||||
mem[address.toInt()] = lsb
|
||||
mem[address.toInt()+1] = msb
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
for(i in 0..65535)
|
||||
mem[i]=0
|
||||
}
|
||||
|
||||
fun setString(address: UInt, str: String, zeroTerminate: Boolean=true) {
|
||||
var addr = address.toInt()
|
||||
for (it in str.toByteArray(Charsets.ISO_8859_1)) {
|
||||
mem[addr] = it
|
||||
addr++
|
||||
}
|
||||
if(zeroTerminate)
|
||||
mem[addr] = 0
|
||||
}
|
||||
|
||||
fun getString(address: UInt): String {
|
||||
var addr = address.toInt()
|
||||
while(mem[addr] != 0.toByte()) addr++
|
||||
return String(mem, address.toInt(), addr-address.toInt(), Charsets.ISO_8859_1)
|
||||
}
|
||||
|
||||
fun memset(address: UInt, length: UInt, value: UByte) {
|
||||
var addr=address.toInt()
|
||||
val byteval = value.toByte()
|
||||
repeat(length.toInt()) {
|
||||
mem[addr] = byteval
|
||||
addr++
|
||||
}
|
||||
}
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
package prog8.sim
|
||||
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.compilerinterface.StStaticVariable
|
||||
import prog8.compilerinterface.SymbolTable
|
||||
import prog8.compilerinterface.intermediate.*
|
||||
import java.util.*
|
||||
|
||||
|
||||
sealed class FlowcontrolException : Exception()
|
||||
|
||||
class ExitProgram(val status: Int): FlowcontrolException()
|
||||
|
||||
|
||||
class Simulator(val program: PtProgram, val symboltable: SymbolTable) {
|
||||
val memory = Memory()
|
||||
private val variables = Variables(symboltable)
|
||||
private val eval = Evaluator(symboltable, memory, variables, this)
|
||||
internal val instructionPtrStack = Stack<InstructionPointer>()
|
||||
internal var ip = InstructionPointer(emptyList())
|
||||
|
||||
fun run() {
|
||||
memory.clear()
|
||||
val start = program.entrypoint() ?: throw NoSuchElementException("no main.start() found")
|
||||
|
||||
ip = InstructionPointer(start.children)
|
||||
try {
|
||||
while(true)
|
||||
executeStatement(ip.current)
|
||||
} catch (exit: ExitProgram) {
|
||||
println("Program Exit! Status code: ${exit.status}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun executeStatement(node: PtNode) {
|
||||
return when(node) {
|
||||
is PtAsmSub -> throw NotImplementedError("can't run assembly subroutine in simulator at this time")
|
||||
is PtAssignment -> execute(node)
|
||||
is PtBuiltinFunctionCall -> {
|
||||
eval.evaluate(node) // throw away any result
|
||||
ip.next()
|
||||
}
|
||||
is PtConditionalBranch -> TODO()
|
||||
is PtDirective -> execute(node)
|
||||
is PtForLoop -> TODO()
|
||||
is PtFunctionCall -> {
|
||||
eval.evaluate(node) // throw away any result
|
||||
ip.next()
|
||||
}
|
||||
is PtGosub -> execute(node)
|
||||
is PtIfElse -> execute(node)
|
||||
is PtInlineAssembly -> throw NotImplementedError("can't run inline assembly in simulator at this time")
|
||||
is PtJump -> execute(node)
|
||||
is PtLabel -> ip.next()
|
||||
is PtPipe -> execute(node)
|
||||
is PtPostIncrDecr -> execute(node)
|
||||
is PtRepeatLoop -> execute(node)
|
||||
is PtReturn -> execute(node)
|
||||
is PtSub -> ip.next() // this simulator doesn't "fall through" into nested subroutines
|
||||
is PtVariable -> ip.next()
|
||||
is PtWhen -> TODO()
|
||||
else -> TODO("missing code for node $node")
|
||||
}
|
||||
}
|
||||
|
||||
private fun execute(jump: PtJump) {
|
||||
if(jump.address!=null)
|
||||
throw NotImplementedError("simulator can't jump into memory machine code")
|
||||
else if(jump.generatedLabel!=null)
|
||||
throw NotImplementedError("simulator can't jump into generated label")
|
||||
else {
|
||||
ip = findTargetNode(jump.identifier!!.targetName)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun findTargetNode(targetName: List<String>): InstructionPointer {
|
||||
val target = findPtNode(targetName, ip.current)
|
||||
val nodes = target.parent.children
|
||||
return InstructionPointer(nodes, nodes.indexOf(target))
|
||||
}
|
||||
|
||||
private fun execute(gosub: PtGosub) {
|
||||
if(gosub.address!=null)
|
||||
throw NotImplementedError("simulator can't jump into memory machine code")
|
||||
else if(gosub.generatedLabel!=null)
|
||||
throw NotImplementedError("simulator can't jump into generated label")
|
||||
else {
|
||||
instructionPtrStack.push(ip)
|
||||
ip = findTargetNode(gosub.identifier!!.targetName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun execute(post: PtPostIncrDecr) {
|
||||
val identifier = post.target.identifier
|
||||
val memoryAddr = post.target.memory
|
||||
val array = post.target.array
|
||||
if(identifier!=null) {
|
||||
val variable = symboltable.lookup(identifier.targetName) as StStaticVariable
|
||||
var value = variables.getValue(variable).number!!
|
||||
if(post.operator=="++") value++ else value--
|
||||
variables.setValue(variable, Variables.Value(value, null, null))
|
||||
} else if(memoryAddr!=null) {
|
||||
val addr = eval.evaluateExpression(memoryAddr.address).first.toUInt()
|
||||
if(post.operator=="++")
|
||||
memory[addr] = (memory[addr]+1u).toUByte()
|
||||
else
|
||||
memory[addr] = (memory[addr]-1u).toUByte()
|
||||
} else if(array!=null) {
|
||||
println("TODO: ${array.variable.ref}[] ${post.operator}")
|
||||
}
|
||||
ip.next()
|
||||
}
|
||||
|
||||
private fun execute(ifelse: PtIfElse) {
|
||||
val condition = eval.evaluateExpression(ifelse.condition)
|
||||
ip = if(condition.first!=0.0) {
|
||||
InstructionPointer(ifelse.ifScope.children)
|
||||
} else {
|
||||
InstructionPointer(ifelse.elseScope.children)
|
||||
}
|
||||
// TODO how to handle the exiting of the subscopes, and continue after the ifelse statement.
|
||||
}
|
||||
|
||||
private fun execute(repeat: PtRepeatLoop) {
|
||||
val count = eval.evaluateExpression(repeat.count).first.toInt()
|
||||
// TODO how to handle the exiting of the subscopes, and continue after the repeat statement.
|
||||
TODO("repeat $count ${repeat.position}")
|
||||
ip.next()
|
||||
}
|
||||
|
||||
private fun execute(pipe: PtPipe) {
|
||||
TODO("pipe stmt $pipe")
|
||||
ip.next()
|
||||
}
|
||||
|
||||
private fun execute(ret: PtReturn) {
|
||||
if(ret.hasValue) {
|
||||
// TODO how to handle the actual return value
|
||||
}
|
||||
ip = instructionPtrStack.pop()
|
||||
ip.next()
|
||||
}
|
||||
|
||||
private fun execute(directive: PtDirective) {
|
||||
// TODO handle directive
|
||||
ip.next()
|
||||
}
|
||||
|
||||
private fun execute(assign: PtAssignment) {
|
||||
val value = eval.evaluateExpression(assign.value)
|
||||
val identifier = assign.target.identifier
|
||||
val memoryAddr = assign.target.memory
|
||||
val array = assign.target.array
|
||||
if(identifier!=null) {
|
||||
val targetvar = symboltable.flat.getValue(identifier.targetName) as StStaticVariable
|
||||
variables.setValue(targetvar, Variables.Value(value.first, null, null))
|
||||
}
|
||||
else if(memoryAddr!=null) {
|
||||
val address = eval.evaluateExpression(memoryAddr.address)
|
||||
require(address.second==DataType.UWORD)
|
||||
require(value.second==DataType.UBYTE)
|
||||
memory[address.first.toUInt()] = value.first.toInt().toUByte()
|
||||
}
|
||||
else if(array!=null)
|
||||
TODO("assign $value to array $array")
|
||||
else
|
||||
throw IllegalArgumentException("missing assign target")
|
||||
ip.next()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal fun findPtNode(scopedName: List<String>, scope: PtNode): PtNode {
|
||||
var root = scope
|
||||
while(root !is PtProgram) {
|
||||
root=root.parent
|
||||
}
|
||||
val block = root.allBlocks().first {
|
||||
it.name == scopedName.first()
|
||||
}
|
||||
var node: PtNode = block
|
||||
scopedName.drop(1).forEach { namepart->
|
||||
val nodes = node.children.filterIsInstance<PtNamedNode>()
|
||||
node = nodes.first { it.name==namepart }
|
||||
}
|
||||
return node
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package prog8.sim
|
||||
|
||||
import prog8.ast.base.ArrayDatatypes
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.base.NumericDatatypes
|
||||
import prog8.compilerinterface.Encoding
|
||||
import prog8.compilerinterface.StStaticVariable
|
||||
import prog8.compilerinterface.SymbolTable
|
||||
|
||||
class Variables(symboltable: SymbolTable) {
|
||||
|
||||
class Value(
|
||||
val number: Double?,
|
||||
val string: Pair<String, Encoding>?,
|
||||
val array: DoubleArray?
|
||||
)
|
||||
|
||||
val allVars = symboltable.allVariables
|
||||
val flatSymbolTable = symboltable.flat
|
||||
val allocations = mutableMapOf<StStaticVariable, UInt>()
|
||||
val values = mutableMapOf<StStaticVariable, Value>()
|
||||
|
||||
init {
|
||||
var address = 0x1000u
|
||||
for (variable in allVars) {
|
||||
allocations[variable] = address
|
||||
address += MemSizer.memorySize(variable.dt).toUInt()
|
||||
when(variable.dt) {
|
||||
in NumericDatatypes -> {
|
||||
val number = if(variable.initialNumericValue==null) 0.0 else variable.initialNumericValue!!
|
||||
values[variable] = Value(number, null, null)
|
||||
}
|
||||
DataType.STR -> {
|
||||
values[variable] = Value(null, variable.initialStringValue!!, null)
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
val array = if(variable.initialArrayValue==null) DoubleArray(variable.arraysize!!) else variable.initialArrayValue!!
|
||||
values[variable] = Value(null, null, array)
|
||||
}
|
||||
else -> throw FatalAstException("weird dt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAddress(variable: StStaticVariable): UInt = allocations.getValue(variable)
|
||||
|
||||
fun getValue(variable: StStaticVariable): Value = values.getValue(variable)
|
||||
|
||||
fun setValue(variable: StStaticVariable, value: Value) {
|
||||
when(variable.dt) {
|
||||
in NumericDatatypes-> require(value.number!=null)
|
||||
DataType.STR -> require(value.string!=null)
|
||||
in ArrayDatatypes -> require(value.array!=null)
|
||||
else -> throw FatalAstException("weird dt")
|
||||
}
|
||||
values[variable] = value
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package prog8simulatortests
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import prog8.sim.Memory
|
||||
|
||||
class TestMemory : FunSpec({
|
||||
|
||||
val mem = Memory()
|
||||
|
||||
test("unsigned byte") {
|
||||
mem.clear()
|
||||
mem[100u] shouldBe 0u
|
||||
mem[100u] = 99u
|
||||
mem[100u] shouldBe 99u
|
||||
mem[100u] = 254u
|
||||
mem[100u] shouldBe 254u
|
||||
mem.getSByte(100u) shouldBe -2
|
||||
}
|
||||
|
||||
test("signed byte") {
|
||||
mem.clear()
|
||||
mem.getSByte(100u) shouldBe 0
|
||||
mem.setSByte(100u, 99)
|
||||
mem.getSByte(100u) shouldBe 99
|
||||
mem.setSByte(100u, -2)
|
||||
mem.getSByte(100u) shouldBe -2
|
||||
mem[100u] shouldBe 254u
|
||||
}
|
||||
|
||||
test("unsigned word") {
|
||||
mem.clear()
|
||||
mem.getWord(100u) shouldBe 0u
|
||||
mem.setWord(100u, 12345u)
|
||||
mem.getWord(100u) shouldBe 12345u
|
||||
mem.getSWord(100u) shouldBe 12345
|
||||
mem.setWord(100u, 54321u)
|
||||
mem.getWord(100u) shouldBe 54321u
|
||||
mem.getSWord(100u) shouldBe -11215
|
||||
mem[100u] shouldBe 0x31u
|
||||
mem[101u] shouldBe 0xd4u
|
||||
}
|
||||
|
||||
test("signed word") {
|
||||
mem.clear()
|
||||
mem.getSWord(100u) shouldBe 0
|
||||
mem.setSWord(100u, 12345)
|
||||
mem.getSWord(100u) shouldBe 12345
|
||||
mem.getWord(100u) shouldBe 12345u
|
||||
mem.setSWord(100u, -12345)
|
||||
mem.getSWord(100u) shouldBe -12345
|
||||
mem.getWord(100u) shouldBe 53191u
|
||||
mem[100u] shouldBe 0xc7u
|
||||
mem[101u] shouldBe 0xcfu
|
||||
}
|
||||
|
||||
test("string") {
|
||||
mem.clear()
|
||||
mem[105u] = 1u
|
||||
mem.setString(100u, "Hello")
|
||||
mem[100u] shouldBe 'H'.code.toUByte()
|
||||
mem[104u] shouldBe 'o'.code.toUByte()
|
||||
mem[105u] shouldBe 0u
|
||||
|
||||
mem.getString(100u) shouldBe "Hello"
|
||||
}
|
||||
})
|
@ -1,46 +0,0 @@
|
||||
package prog8simulatortests
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.statements.AssignmentOrigin
|
||||
import prog8.compilerinterface.Encoding
|
||||
import prog8.compilerinterface.SymbolTable
|
||||
import prog8.compilerinterface.intermediate.*
|
||||
import prog8.sim.MemSizer
|
||||
import prog8.sim.Simulator
|
||||
import prog8.sim.StringEncoding
|
||||
|
||||
class TestSim : FunSpec({
|
||||
test("simple program simulation") {
|
||||
val program = PtProgram("test", MemSizer, StringEncoding)
|
||||
val module = PtModule("test", 0u, false, Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), emptyList(), false, Position.DUMMY)
|
||||
block.add(sub)
|
||||
module.add(block)
|
||||
program.add(module)
|
||||
val fcall = PtBuiltinFunctionCall("print", Position.DUMMY).also {
|
||||
it.add(PtString("Hello, world! From the program.\n", Encoding.DEFAULT, Position.DUMMY))
|
||||
}
|
||||
sub.add(fcall)
|
||||
val memwrite = PtAssignment(false, AssignmentOrigin.USERCODE, Position.DUMMY).also { assign ->
|
||||
assign.add(PtAssignTarget(Position.DUMMY).also { tgt ->
|
||||
tgt.add(PtMemoryByte(Position.DUMMY).also { mb ->
|
||||
mb.add(PtNumber(DataType.UWORD, 1000.0, Position.DUMMY))
|
||||
})
|
||||
})
|
||||
assign.add(PtNumber(DataType.UBYTE, 99.0, Position.DUMMY))
|
||||
}
|
||||
sub.add(memwrite)
|
||||
sub.add(PtReturn(Position.DUMMY))
|
||||
|
||||
val symboltable = SymbolTable()
|
||||
|
||||
val sim = Simulator(program, symboltable)
|
||||
sim.memory[1000u] shouldBe 0u
|
||||
sim.run()
|
||||
sim.memory[1000u] shouldBe 99u
|
||||
}
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user