mirror of
https://github.com/irmen/prog8.git
synced 2024-09-30 00:55:52 +00:00
decide sim is not worth it-remove it again
This commit is contained in:
parent
61398ee8f8
commit
240e6835c2
@ -14,7 +14,6 @@
|
|||||||
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
|
<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$/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$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/simulator/simulator.iml" filepath="$PROJECT_DIR$/simulator/simulator.iml" />
|
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -26,7 +26,6 @@ compileTestKotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':compilerInterfaces')
|
implementation project(':compilerInterfaces')
|
||||||
implementation project(':compilerAst')
|
implementation project(':compilerAst')
|
||||||
implementation project(':simulator')
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.14"
|
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="compilerAst" />
|
||||||
<orderEntry type="module" module-name="compilerInterfaces" />
|
<orderEntry type="module" module-name="compilerInterfaces" />
|
||||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||||
<orderEntry type="module" module-name="simulator" />
|
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
@ -2,7 +2,6 @@ package prog8.codegen.experimental6502
|
|||||||
|
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.compilerinterface.*
|
import prog8.compilerinterface.*
|
||||||
import prog8.sim.Simulator
|
|
||||||
|
|
||||||
class AsmGen(internal val program: Program,
|
class AsmGen(internal val program: Program,
|
||||||
internal val errors: IErrorReporter,
|
internal val errors: IErrorReporter,
|
||||||
@ -20,9 +19,6 @@ class AsmGen(internal val program: Program,
|
|||||||
val intermediateAst = IntermediateAstMaker(program).transform()
|
val intermediateAst = IntermediateAstMaker(program).transform()
|
||||||
intermediateAst.print()
|
intermediateAst.print()
|
||||||
|
|
||||||
val sim = Simulator(intermediateAst, symbolTable)
|
|
||||||
sim.run()
|
|
||||||
|
|
||||||
println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
|
println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
|
||||||
return AssemblyProgram("dummy")
|
return AssemblyProgram("dummy")
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ include(
|
|||||||
':codeGenCpu6502',
|
':codeGenCpu6502',
|
||||||
':codeGenExperimental6502',
|
':codeGenExperimental6502',
|
||||||
':compiler',
|
':compiler',
|
||||||
':simulator',
|
|
||||||
':dbusCompilerService',
|
':dbusCompilerService',
|
||||||
':httpCompilerService'
|
':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…
Reference in New Issue
Block a user