vm tweaks

This commit is contained in:
Irmen de Jong 2018-09-15 18:43:23 +02:00
parent e382be89db
commit c05cd72d23
5 changed files with 105 additions and 26 deletions

View File

@ -19,6 +19,7 @@
const float round1 = len([1,2,3])
const float sin1 = len([1,2,3])
float cos1 = len([1,2,3])
}
~ main $c003 {
@ -41,7 +42,7 @@
const byte wa2b= abs(-99.w)
const byte wa2c = abs(-99)
const word wa2d = abs(-999)
const float wa3 = abs(-1.23456)
float wa3 = abs(-1.23456)
const float wa4 = abs(-133)
const float avg1 = avg([-1.23456, 99999])
const float sum1 = sum([-1.23456, 99999])
@ -59,6 +60,15 @@
const word min1 = min([1,2,3,99+22])
word dinges = round(not_main.len1)
wa3 = rnd()
wa3 = rndw()
wa3 = rndf(22)
A += 8
A += rnd()
A =A+ rnd()
A = X>2
X = Y>Y
@ -177,11 +187,12 @@
blerp3 = blerp2
A=blerp2
A=$02
A=$002
A=$00ff
;A=$02.w ; @todo error word/byte
;A=$002 ; @todo error word/byte
;A=$00ff ; @todo error word/byte
A=%11001100
A=%0010011001
A=99.w
; A=%0010011001 ;@todo error word/byte
; A=99.w ; @todo error word/byte
XY=blerp1
X=blerp2
return

View File

@ -142,7 +142,10 @@ class Compiler(private val options: CompilationOptions) {
when(directive.directive) {
"%asminclude" -> throw CompilerException("can't use %asminclude in stackvm")
"%asmbinary" -> throw CompilerException("can't use %asmbinary in stackvm")
"%breakpoint" -> stackvmProg.instruction("break")
"%breakpoint" -> {
stackvmProg.line(directive.position)
stackvmProg.instruction("break")
}
}
return super.process(directive)
}
@ -154,7 +157,7 @@ class Compiler(private val options: CompilationOptions) {
is AnonymousStatementList -> translate(stmt.statements)
is Label -> translate(stmt)
is Return -> translate(stmt)
is Assignment -> translate(stmt)
is Assignment -> translate(stmt) // normal and augmented assignments
is PostIncrDecr -> translate(stmt)
is Jump -> translate(stmt)
is FunctionCallStatement -> translate(stmt)
@ -179,6 +182,7 @@ class Compiler(private val options: CompilationOptions) {
* _stmt_999_continue:
* ...
*/
stackvmProg.line(branch.position)
val labelElse = makeLabel("else")
val labelContinue = makeLabel("continue")
val opcode = when(branch.condition) {
@ -220,6 +224,7 @@ class Compiler(private val options: CompilationOptions) {
* _stmt_999_continue:
* ...
*/
stackvmProg.line(stmt.position)
translate(stmt.condition)
val labelElse = makeLabel("else")
val labelContinue = makeLabel("continue")
@ -255,7 +260,9 @@ class Compiler(private val options: CompilationOptions) {
stackvmProg.instruction("syscall FUNC_${expr.target.nameInSource[0].toUpperCase()}") // call builtin function
} else {
when(target) {
is Subroutine -> stackvmProg.instruction("call ${target.scopedname}")
is Subroutine -> {
stackvmProg.instruction("call ${target.scopedname}")
}
else -> TODO("non-builtin-function call to $target")
}
}
@ -263,7 +270,9 @@ class Compiler(private val options: CompilationOptions) {
is IdentifierReference -> {
val target = expr.targetStatement(namespace)
when(target) {
is VarDecl -> stackvmProg.instruction("push_var ${target.scopedname}")
is VarDecl -> {
stackvmProg.instruction("push_var ${target.scopedname}")
}
else -> throw CompilerException("expression identifierref should be a vardef, not $target")
}
}
@ -309,6 +318,7 @@ class Compiler(private val options: CompilationOptions) {
}
private fun translate(stmt: FunctionCallStatement) {
stackvmProg.line(stmt.position)
val targetStmt = stmt.target.targetStatement(namespace)!!
if(targetStmt is BuiltinFunctionStatementPlaceholder) {
stmt.arglist.forEach { translate(it) }
@ -337,10 +347,12 @@ class Compiler(private val options: CompilationOptions) {
else -> throw CompilerException("invalid jump target type ${target::class}")
}
}
stackvmProg.line(stmt.position)
stackvmProg.instruction(instr)
}
private fun translate(stmt: PostIncrDecr) {
stackvmProg.line(stmt.position)
if(stmt.target.register!=null) {
when(stmt.operator) {
"++" -> stackvmProg.instruction("inc_var ${stmt.target.register}")
@ -356,7 +368,33 @@ class Compiler(private val options: CompilationOptions) {
}
private fun translate(stmt: Assignment) {
stackvmProg.line(stmt.position)
translate(stmt.value)
val valueDt = stmt.value.resultingDatatype(namespace)
val targetDt = stmt.target.determineDatatype(namespace, stmt)
if(valueDt!=targetDt) {
// convert value to target datatype if possible
when(targetDt) {
DataType.BYTE -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.WORD -> {
if(valueDt==DataType.BYTE)
stackvmProg.instruction("b2word")
else
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
}
DataType.FLOAT -> {
when (valueDt) {
DataType.BYTE -> stackvmProg.instruction("b2float")
DataType.WORD -> stackvmProg.instruction("w2float")
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
}
}
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
// todo: maybe if you assign byte or word to array/matrix, clear it with that value?
}
}
if(stmt.aug_op!=null) {
// augmented assignment
if(stmt.target.identifier!=null) {
@ -402,6 +440,7 @@ class Compiler(private val options: CompilationOptions) {
if(stmt.values.isNotEmpty()) {
TODO("return with value(s) not yet supported: $stmt")
}
stackvmProg.line(stmt.position)
stackvmProg.instruction("return")
}
@ -472,6 +511,10 @@ class StackVmProgram(val name: String) {
fun label(name: String) {
instructions.add("$name:")
}
fun line(position: Position) {
instructions.add(" _line ${position.line} ${position.file}")
}
}
enum class OutputType {

View File

@ -7,7 +7,7 @@ import kotlin.math.floor
val BuiltinFunctionNames = setOf(
"P_carry", "P_irqd", "rol", "ror", "rol2", "ror2", "lsl", "lsr",
"sin", "cos", "abs", "acos", "asin", "tan", "atan",
"sin", "cos", "abs", "acos", "asin", "tan", "atan", "rnd", "rndw", "rndf",
"log", "log10", "sqrt", "rad", "deg", "round", "floor", "ceil",
"max", "min", "avg", "sum", "len", "any", "all", "lsb", "msb")
@ -40,8 +40,9 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
}
return when (function) {
"sin", "cos", "tan", "asin", "acos", "atan", "log", "log10", "sqrt", "rad", "deg", "avg" -> DataType.FLOAT
"len", "lsb", "msb", "any", "all" -> DataType.BYTE
"sin", "cos", "tan", "asin", "acos", "atan", "log", "log10", "sqrt", "rad", "deg", "avg", "rndf" -> DataType.FLOAT
"len", "lsb", "msb", "any", "all", "rnd" -> DataType.BYTE
"rndw" -> DataType.WORD
"rol", "rol2", "ror", "ror2", "P_carry", "P_irqd" -> null // no return value so no datatype
"abs" -> args.single().resultingDatatype(namespace)
"max", "min", "sum" -> datatypeFromListArg(args.single())

View File

@ -118,7 +118,8 @@ enum class Opcode {
CLC, // clear carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations
NOP,
BREAK, // breakpoint
TERMINATE // end the program
TERMINATE, // end the program
_LINE // record source file line number
}
enum class Syscall(val callNr: Short) {
@ -131,10 +132,6 @@ enum class Syscall(val callNr: Short) {
GFX_PIXEL(16), // plot a pixel at (x,y,color) pushed on stack in that order
GFX_CLEARSCR(17), // clear the screen with color pushed on stack
GFX_TEXT(18), // write text on screen at (x,y,color,text) pushed on stack in that order
RANDOM(19), // push a random byte on the stack
RANDOM_W(20), // push a random word on the stack
RANDOM_F(21), // push a random float on the stack (between 0.0 and 1.0)
FUNC_P_CARRY(100),
FUNC_P_IRQD(101),
@ -167,8 +164,10 @@ enum class Syscall(val callNr: Short) {
FUNC_ANY(128),
FUNC_ALL(129),
FUNC_LSB(130),
FUNC_MSB(131)
FUNC_MSB(131),
FUNC_RND(132), // push a random byte on the stack
FUNC_RNDW(133), // push a random word on the stack
FUNC_RNDF(134) // push a random float on the stack (between 0.0 and 1.0)
}
class Memory {
@ -575,6 +574,7 @@ class Program (prog: MutableList<Instruction>,
val opcode=Opcode.valueOf(parts[0].toUpperCase())
val args = if(parts.size==2) parts[1] else null
val instruction = when(opcode) {
Opcode._LINE -> Instruction(opcode, Value(DataType.STR, null, stringvalue = args))
Opcode.JUMP, Opcode.CALL, Opcode.BMI, Opcode.BPL,
Opcode.BEQ, Opcode.BNE, Opcode.BCS, Opcode.BCC -> {
if(args!!.startsWith('$')) {
@ -608,7 +608,7 @@ class Program (prog: MutableList<Instruction>,
labels[nextInstructionLabelname] = instruction
nextInstructionLabelname = ""
}
}
} else throw VmExecutionException("syntax error at line ${lineNr+1}")
}
}
@ -770,6 +770,7 @@ class StackVm(val traceOutputFile: String?) {
private lateinit var currentIns: Instruction
private lateinit var canvas: BitmapScreenPanel
private val rnd = Random()
private var sourceLine = ""
fun load(program: Program, canvas: BitmapScreenPanel) {
this.program = program.program
@ -809,7 +810,11 @@ class StackVm(val traceOutputFile: String?) {
throw VmExecutionException("too many nested/recursive calls")
} catch (bp: VmBreakpointException) {
currentIns = currentIns.next
println("breakpoint encountered, source line: $sourceLine")
throw bp
} catch (es: EmptyStackException) {
System.err.println("stack error! source line: $sourceLine")
throw es
}
}
val time = System.currentTimeMillis()-start
@ -1012,16 +1017,16 @@ class StackVm(val traceOutputFile: String?) {
val (y, x) = evalstack.pop2()
canvas.writeText(x.integerValue(), y.integerValue(), text.stringvalue!!, color.integerValue())
}
Syscall.RANDOM -> evalstack.push(Value(DataType.BYTE, rnd.nextInt() and 255))
Syscall.RANDOM_W -> evalstack.push(Value(DataType.WORD, rnd.nextInt() and 65535))
Syscall.RANDOM_F -> evalstack.push(Value(DataType.FLOAT, rnd.nextDouble()))
Syscall.FUNC_RND -> evalstack.push(Value(DataType.BYTE, rnd.nextInt() and 255))
Syscall.FUNC_RNDW -> evalstack.push(Value(DataType.WORD, rnd.nextInt() and 65535))
Syscall.FUNC_RNDF -> evalstack.push(Value(DataType.FLOAT, rnd.nextDouble()))
else -> throw VmExecutionException("unimplemented syscall $syscall")
}
}
Opcode.SEC -> carry = true
Opcode.CLC -> carry = false
Opcode.TERMINATE -> throw VmTerminationException("execution terminated")
Opcode.TERMINATE -> throw VmTerminationException("terminate instruction")
Opcode.BREAK -> throw VmBreakpointException()
Opcode.INC_MEM -> {
@ -1129,7 +1134,11 @@ class StackVm(val traceOutputFile: String?) {
Opcode.BMI -> return if(evalstack.pop().numericValue().toDouble()<0.0) ins.next else ins.nextAlt!!
Opcode.BPL -> return if(evalstack.pop().numericValue().toDouble()>=0.0) ins.next else ins.nextAlt!!
Opcode.CALL -> callstack.push(ins.nextAlt)
Opcode.RETURN -> return callstack.pop()
Opcode.RETURN -> {
if(callstack.empty())
throw VmTerminationException("return instruction with empty call stack")
return callstack.pop()
}
Opcode.PUSH_VAR -> {
val varname = ins.arg!!.stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)")
val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname")
@ -1262,6 +1271,9 @@ class StackVm(val traceOutputFile: String?) {
throw VmExecutionException("attempt to make a float from a non-word value $byte")
}
}
Opcode._LINE -> {
sourceLine = ins.arg!!.stringvalue!!
}
else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}")
}
@ -1292,12 +1304,15 @@ fun main(args: Array<String>) {
dialog.isVisible = true
dialog.start()
val programTimer = Timer(10) { _ ->
val programTimer = Timer(10) { a ->
try {
vm.step()
} catch(bp: VmBreakpointException) {
println("Breakpoint: execution halted. Press enter to resume.")
readLine()
} catch (tx: VmTerminationException) {
println("Execution halted: ${tx.message}")
(a.source as Timer).stop()
}
}
programTimer.start()

View File

@ -486,6 +486,15 @@ any(x)
all(x)
1 ('true') if all of the values in the non-scalar (array or matrix) value x are 'true' (not zero), else 0 ('false')
rnd()
returns a pseudo-random byte from 0..255
rndw()
returns a pseudo-random word from 0..65535
rndf()
returns a pseudo-random float between 0.0 and 1.0
lsl(x)
Shift the bits in x (byte or word) one position to the left.
Bit 0 is set to 0 (and the highest bit is shifted into the status register's Carry flag)