stackvm functions

This commit is contained in:
Irmen de Jong 2018-09-18 00:31:11 +02:00
parent 54aeee2676
commit 63492a1805
7 changed files with 180 additions and 90 deletions

View File

@ -26,7 +26,9 @@ loop:
push_var main.textcolor push_var main.textcolor
syscall GFX_PIXEL syscall GFX_PIXEL
; syscall WRITE_VAR "input.prompt" ; syscall WRITE_VAR "input.prompt"
; syscall INPUT_VAR "input.result" ; push b:10
; syscall INPUT_STR
; pop_var input.result
; syscall WRITE_VAR "input.result" ; syscall WRITE_VAR "input.result"
; push b:8d ; push b:8d
; syscall WRITE_CHAR ; syscall WRITE_CHAR

View File

@ -1043,7 +1043,8 @@ class FunctionCall(override var target: IdentifierReference,
"asin" -> builtinAsin(arglist, position, namespace) "asin" -> builtinAsin(arglist, position, namespace)
"tan" -> builtinTan(arglist, position, namespace) "tan" -> builtinTan(arglist, position, namespace)
"atan" -> builtinAtan(arglist, position, namespace) "atan" -> builtinAtan(arglist, position, namespace)
"log" -> builtinLog(arglist, position, namespace) "ln" -> builtinLn(arglist, position, namespace)
"log2" -> builtinLog2(arglist, position, namespace)
"log10" -> builtinLog10(arglist, position, namespace) "log10" -> builtinLog10(arglist, position, namespace)
"sqrt" -> builtinSqrt(arglist, position, namespace) "sqrt" -> builtinSqrt(arglist, position, namespace)
"max" -> builtinMax(arglist, position, namespace) "max" -> builtinMax(arglist, position, namespace)

View File

@ -497,8 +497,8 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
return false return false
} }
val rangeSize=range.size() val rangeSize=range.size()
if(rangeSize!=null && (rangeSize<1 || rangeSize>255)) { if(rangeSize!=null && (rangeSize<0 || rangeSize>255)) {
checkResult.add(ExpressionError("size of range for string must be 1..255, instead of $rangeSize", range.position)) checkResult.add(ExpressionError("size of range for string must be 0..255, instead of $rangeSize", range.position))
return false return false
} }
return true return true

View File

@ -183,11 +183,15 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
private fun translate(stmt: Continue) { private fun translate(stmt: Continue) {
stackvmProg.line(stmt.position) stackvmProg.line(stmt.position)
TODO("translate CONTINUE") TODO("translate CONTINUE")
// * ..continue statement: goto continue
// we somehow have to know what the correct 'continue' label is
} }
private fun translate(stmt: Break) { private fun translate(stmt: Break) {
stackvmProg.line(stmt.position) stackvmProg.line(stmt.position)
TODO("translate BREAK") TODO("translate BREAK")
// * ..break statement: goto break
// we somehow have to know what the correct 'break' label is
} }
private fun translate(branch: BranchStatement) { private fun translate(branch: BranchStatement) {

View File

@ -1,17 +1,16 @@
package prog8.functions package prog8.functions
import prog8.ast.* import prog8.ast.*
import kotlin.math.abs import kotlin.math.log2
import kotlin.math.floor
val BuiltinFunctionNames = setOf( val BuiltinFunctionNames = setOf(
"P_carry", "P_irqd", "rol", "ror", "rol2", "ror2", "lsl", "lsr", "P_carry", "P_irqd", "rol", "ror", "rol2", "ror2", "lsl", "lsr",
"sin", "cos", "abs", "acos", "asin", "tan", "atan", "rnd", "rndw", "rndf", "sin", "cos", "abs", "acos", "asin", "tan", "atan", "rnd", "rndw", "rndf",
"log", "log10", "sqrt", "rad", "deg", "round", "floor", "ceil", "ln", "log2", "log10", "sqrt", "rad", "deg", "round", "floor", "ceil",
"max", "min", "avg", "sum", "len", "any", "all", "lsb", "msb", "max", "min", "avg", "sum", "len", "any", "all", "lsb", "msb",
"_vm_write_memchr", "_vm_write_memstr", "_vm_write_num", "_vm_write_char", "_vm_write_memchr", "_vm_write_memstr", "_vm_write_num", "_vm_write_char",
"_vm_write_str", "_vm_input_var", "_vm_gfx_clearscr", "_vm_gfx_pixel", "_vm_gfx_text" "_vm_write_str", "_vm_input_str", "_vm_gfx_clearscr", "_vm_gfx_pixel", "_vm_gfx_text"
) )
@ -46,15 +45,25 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
} }
return when (function) { return when (function) {
"sin", "cos", "tan", "asin", "acos", "atan", "log", "log10", "sqrt", "rad", "deg", "avg", "rndf" -> DataType.FLOAT "sin", "cos", "tan", "asin", "acos", "atan", "ln", "log2", "log10", "sqrt", "rad", "deg", "avg", "rndf" -> DataType.FLOAT
"lsb", "msb", "any", "all", "rnd" -> DataType.BYTE "lsb", "msb", "any", "all", "rnd" -> DataType.BYTE
"rndw" -> DataType.WORD "rndw" -> DataType.WORD
"rol", "rol2", "ror", "ror2", "P_carry", "P_irqd" -> null // no return value so no datatype "rol", "rol2", "ror", "ror2", "P_carry", "P_irqd" -> null // no return value so no datatype
"abs" -> args.single().resultingDatatype(namespace) "abs" -> args.single().resultingDatatype(namespace)
"max", "min", "sum" -> datatypeFromListArg(args.single()) "max", "min" -> datatypeFromListArg(args.single())
"round", "floor", "ceil", "lsl", "lsr" -> integerDatatypeFromArg(args.single()) "round", "floor", "ceil", "lsl", "lsr" -> integerDatatypeFromArg(args.single())
"sum" -> {
val dt=datatypeFromListArg(args.single())
when(dt) {
DataType.BYTE, DataType.WORD -> DataType.WORD
DataType.FLOAT -> DataType.FLOAT
DataType.ARRAY, DataType.ARRAY_W -> DataType.WORD
DataType.MATRIX -> DataType.BYTE
else -> throw FatalAstException("cannot sum over type $dt")
}
}
"len" -> { "len" -> {
// len of a str is always 1..255 so always a byte, // len of a str is always 0..255 so always a byte,
// len of other things is assumed to need a word (even though the actual length could be less than 256) // len of other things is assumed to need a word (even though the actual length could be less than 256)
val arg = args.single() val arg = args.single()
when(arg) { when(arg) {
@ -64,7 +73,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
is VarDecl -> { is VarDecl -> {
val value = stmt.value val value = stmt.value
if(value is LiteralValue) { if(value is LiteralValue) {
if(value.isString) return DataType.BYTE // strings are 1..255 if(value.isString) return DataType.BYTE // strings are 0..255
} }
} }
} }
@ -76,7 +85,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
} }
"_vm_write_memchr", "_vm_write_memstr", "_vm_write_num", "_vm_write_char", "_vm_write_memchr", "_vm_write_memstr", "_vm_write_num", "_vm_write_char",
"_vm_write_str", "_vm_gfx_clearscr", "_vm_gfx_pixel", "_vm_gfx_text" -> null // no return value for these "_vm_write_str", "_vm_gfx_clearscr", "_vm_gfx_pixel", "_vm_gfx_text" -> null // no return value for these
"_vm_input_var" -> DataType.STR "_vm_input_str" -> DataType.STR
else -> throw FatalAstException("invalid builtin function $function") else -> throw FatalAstException("invalid builtin function $function")
} }
} }
@ -173,9 +182,12 @@ fun builtinTan(args: List<IExpression>, position: Position, namespace:INameScope
fun builtinAtan(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue fun builtinAtan(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
= oneDoubleArg(args, position, namespace, Math::atan) = oneDoubleArg(args, position, namespace, Math::atan)
fun builtinLog(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue fun builtinLn(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
= oneDoubleArg(args, position, namespace, Math::log) = oneDoubleArg(args, position, namespace, Math::log)
fun builtinLog2(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
= oneDoubleArg(args, position, namespace, ::log2)
fun builtinLog10(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue fun builtinLog10(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
= oneDoubleArg(args, position, namespace, Math::log10) = oneDoubleArg(args, position, namespace, Math::log10)
@ -196,8 +208,8 @@ fun builtinAbs(args: List<IExpression>, position: Position, namespace:INameScope
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException() val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
val number = constval.asNumericValue val number = constval.asNumericValue
return when (number) { return when (number) {
is Int, is Byte, is Short -> numericLiteral(abs(number.toInt()), args[0].position) is Int, is Byte, is Short -> numericLiteral(Math.abs(number.toInt()), args[0].position)
is Double -> numericLiteral(abs(number.toDouble()), args[0].position) is Double -> numericLiteral(Math.abs(number.toDouble()), args[0].position)
else -> throw SyntaxError("abs requires one numeric argument", position) else -> throw SyntaxError("abs requires one numeric argument", position)
} }
} }
@ -258,7 +270,7 @@ fun builtinAll(args: List<IExpression>, position: Position, namespace:INameScope
private fun numericLiteral(value: Number, position: Position): LiteralValue { private fun numericLiteral(value: Number, position: Position): LiteralValue {
val floatNum=value.toDouble() val floatNum=value.toDouble()
val tweakedValue: Number = val tweakedValue: Number =
if(floatNum==floor(floatNum) && floatNum in -32768..65535) if(floatNum==Math.floor(floatNum) && floatNum in -32768..65535)
floatNum.toInt() // we have an integer disguised as a float. floatNum.toInt() // we have an integer disguised as a float.
else else
floatNum floatNum

View File

@ -128,46 +128,42 @@ enum class Syscall(val callNr: Short) {
WRITE_NUM(12), // pop from the evaluation stack and print it as a number WRITE_NUM(12), // pop from the evaluation stack and print it as a number
WRITE_CHAR(13), // pop from the evaluation stack and print it as a single petscii character WRITE_CHAR(13), // pop from the evaluation stack and print it as a single petscii character
WRITE_STR(14), // pop from the evaluation stack and print it as a string WRITE_STR(14), // pop from the evaluation stack and print it as a string
INPUT_VAR(15), // user input a string into a variable INPUT_STR(15), // user input a string onto the stack, with max length (truncated) given by value on stack
GFX_PIXEL(16), // plot a pixel at (x,y,color) pushed on stack in that order 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_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 GFX_TEXT(18), // write text on screen at (x,y,color,text) pushed on stack in that order
FUNC_P_CARRY(64), FUNC_P_CARRY(64),
FUNC_P_IRQD(65), FUNC_P_IRQD(65),
FUNC_ROL(66), FUNC_SIN(66),
FUNC_ROR(67), FUNC_COS(67),
FUNC_ROL2(68), FUNC_ABS(68),
FUNC_ROR2(69), FUNC_ACOS(69),
FUNC_LSL(70), FUNC_ASIN(70),
FUNC_LSR(71), FUNC_TAN(71),
FUNC_SIN(72), FUNC_ATAN(72),
FUNC_COS(73), FUNC_LN(73),
FUNC_ABS(74), FUNC_LOG2(74),
FUNC_ACOS(75), FUNC_LOG10(75),
FUNC_ASIN(76), FUNC_SQRT(76),
FUNC_TAN(77), FUNC_RAD(77),
FUNC_ATAN(78), FUNC_DEG(78),
FUNC_LOG(79), FUNC_ROUND(79),
FUNC_LOG10(80), FUNC_FLOOR(80),
FUNC_SQRT(81), FUNC_CEIL(81),
FUNC_RAD(82), FUNC_MAX(82),
FUNC_DEG(83), FUNC_MIN(83),
FUNC_ROUND(84), FUNC_AVG(84),
FUNC_FLOOR(85), FUNC_SUM(85),
FUNC_CEIL(86), FUNC_LEN(86),
FUNC_MAX(87), FUNC_ANY(87),
FUNC_MIN(88), FUNC_ALL(88),
FUNC_AVG(89), FUNC_RND(89), // push a random byte on the stack
FUNC_SUM(90), FUNC_RNDW(90), // push a random word on the stack
FUNC_LEN(91), FUNC_RNDF(91) // push a random float on the stack (between 0.0 and 1.0)
FUNC_ANY(92),
FUNC_ALL(93), // note: not all builtin functions of the Prog8 language are present as functions:
FUNC_LSB(94), // some of them are already opcodes (such as MSB and ROL)!
FUNC_MSB(95),
FUNC_RND(96), // push a random byte on the stack
FUNC_RNDW(97), // push a random word on the stack
FUNC_RNDF(98) // push a random float on the stack (between 0.0 and 1.0)
} }
class Memory { class Memory {
@ -814,7 +810,8 @@ class StackVm(val traceOutputFile: String?) {
private val evalstack = MyStack<Value>() // evaluation stack private val evalstack = MyStack<Value>() // evaluation stack
private val callstack = MyStack<Instruction>() // subroutine call stack private val callstack = MyStack<Instruction>() // subroutine call stack
private var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name private var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name
private var carry: Boolean = false private var P_carry: Boolean = false
private var P_irqd: Boolean = false
private var program = listOf<Instruction>() private var program = listOf<Instruction>()
private var traceOutput = if(traceOutputFile!=null) PrintStream(File(traceOutputFile), "utf-8") else null private var traceOutput = if(traceOutputFile!=null) PrintStream(File(traceOutputFile), "utf-8") else null
private lateinit var currentIns: Instruction private lateinit var currentIns: Instruction
@ -924,7 +921,7 @@ class StackVm(val traceOutputFile: String?) {
Opcode.ARRAY -> { Opcode.ARRAY -> {
val amount = ins.arg!!.integerValue() val amount = ins.arg!!.integerValue()
val array = mutableListOf<Int>() val array = mutableListOf<Int>()
for (i in 0..amount) { for (i in 1..amount) {
val value = evalstack.pop() val value = evalstack.pop()
if(value.type!=DataType.BYTE && value.type!=DataType.WORD) if(value.type!=DataType.BYTE && value.type!=DataType.WORD)
throw VmExecutionException("array requires values to be all byte/word") throw VmExecutionException("array requires values to be all byte/word")
@ -986,8 +983,8 @@ class StackVm(val traceOutputFile: String?) {
} }
Opcode.ROL -> { Opcode.ROL -> {
val v = evalstack.pop() val v = evalstack.pop()
val (result, newCarry) = v.rol(carry) val (result, newCarry) = v.rol(P_carry)
this.carry = newCarry this.P_carry = newCarry
evalstack.push(result) evalstack.push(result)
} }
Opcode.ROL2 -> { Opcode.ROL2 -> {
@ -996,8 +993,8 @@ class StackVm(val traceOutputFile: String?) {
} }
Opcode.ROR -> { Opcode.ROR -> {
val v = evalstack.pop() val v = evalstack.pop()
val (result, newCarry) = v.ror(carry) val (result, newCarry) = v.ror(P_carry)
this.carry = newCarry this.P_carry = newCarry
evalstack.push(result) evalstack.push(result)
} }
Opcode.ROR2 -> { Opcode.ROR2 -> {
@ -1054,19 +1051,10 @@ class StackVm(val traceOutputFile: String?) {
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> print(value.arrayvalue) DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> print(value.arrayvalue)
} }
} }
Syscall.INPUT_VAR -> { Syscall.INPUT_STR -> {
// TODO: replace with regular INPUT_STR that simply puts a str on the stack (1 argument: the max. length of the input) val maxlen = evalstack.pop().integerValue()
val varname = ins.callLabel ?: throw VmExecutionException("$syscall expects string argument (the variable name)") val input = readLine()?.substring(0, maxlen) ?: ""
val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") evalstack.push(Value(DataType.STR, null, input))
val input = readLine() ?: throw VmExecutionException("expected user input")
val value = when(variable.type) {
DataType.BYTE -> Value(DataType.BYTE, input.toShort())
DataType.WORD -> Value(DataType.WORD, input.toInt())
DataType.FLOAT -> Value(DataType.FLOAT, input.toDouble())
DataType.STR -> Value(DataType.STR, null, input)
else -> throw VmExecutionException("invalid datatype")
}
variables[varname] = value
} }
Syscall.GFX_PIXEL -> { Syscall.GFX_PIXEL -> {
// plot pixel at (x, y, color) from stack // plot pixel at (x, y, color) from stack
@ -1100,13 +1088,93 @@ class StackVm(val traceOutputFile: String?) {
Syscall.FUNC_SIN -> evalstack.push(Value(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_SIN -> evalstack.push(Value(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt())) Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt()))
// todo: implement remaining functions Syscall.FUNC_P_CARRY -> P_carry = evalstack.pop().asBooleanValue
Syscall.FUNC_P_IRQD -> P_irqd = evalstack.pop().asBooleanValue
Syscall.FUNC_ABS -> {
val value = evalstack.pop()
val absValue=
when(value.type) {
DataType.BYTE -> Value(DataType.BYTE, value.numericValue())
DataType.WORD -> Value(DataType.WORD, value.numericValue())
DataType.FLOAT -> Value(DataType.FLOAT, value.numericValue())
else -> throw VmExecutionException("cannot get abs of $value")
}
evalstack.push(absValue)
}
Syscall.FUNC_ACOS -> evalstack.push(Value(DataType.FLOAT, acos(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_ASIN -> evalstack.push(Value(DataType.FLOAT, asin(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_TAN -> evalstack.push(Value(DataType.FLOAT, tan(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_ATAN -> evalstack.push(Value(DataType.FLOAT, atan(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_LN -> evalstack.push(Value(DataType.FLOAT, ln(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_LOG2 -> evalstack.push(Value(DataType.FLOAT, log2(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_LOG10 -> evalstack.push(Value(DataType.FLOAT, log10(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_SQRT -> evalstack.push(Value(DataType.FLOAT, sqrt(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_RAD -> evalstack.push(Value(DataType.FLOAT, Math.toRadians(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_DEG -> evalstack.push(Value(DataType.FLOAT, Math.toDegrees(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_FLOOR -> {
val value = evalstack.pop()
val result =
when(value.type) {
DataType.BYTE -> Value(DataType.BYTE, value.numericValue())
DataType.WORD -> Value(DataType.WORD, value.numericValue())
DataType.FLOAT -> Value(DataType.WORD, floor(value.numericValue().toDouble()))
else -> throw VmExecutionException("cannot get floor of $value")
}
evalstack.push(result)
}
Syscall.FUNC_CEIL -> {
val value = evalstack.pop()
val result =
when(value.type) {
DataType.BYTE -> Value(DataType.BYTE, value.numericValue())
DataType.WORD -> Value(DataType.WORD, value.numericValue())
DataType.FLOAT -> Value(DataType.WORD, ceil(value.numericValue().toDouble()))
else -> throw VmExecutionException("cannot get ceil of $value")
}
evalstack.push(result)
}
Syscall.FUNC_MAX -> {
val array = evalstack.pop()
val dt =
when {
array.type==DataType.ARRAY -> DataType.BYTE
array.type==DataType.ARRAY_W -> DataType.WORD
else -> throw VmExecutionException("invalid array datatype $array")
}
evalstack.push(Value(dt, array.arrayvalue!!.max()))
}
Syscall.FUNC_MIN -> {
val array = evalstack.pop()
val dt =
when {
array.type==DataType.ARRAY -> DataType.BYTE
array.type==DataType.ARRAY_W -> DataType.WORD
else -> throw VmExecutionException("invalid array datatype $array")
}
evalstack.push(Value(dt, array.arrayvalue!!.min()))
}
Syscall.FUNC_AVG -> {
val array = evalstack.pop()
evalstack.push(Value(DataType.FLOAT, array.arrayvalue!!.average()))
}
Syscall.FUNC_SUM -> {
val array = evalstack.pop()
evalstack.push(Value(DataType.WORD, array.arrayvalue!!.sum()))
}
Syscall.FUNC_ANY -> {
val array = evalstack.pop()
evalstack.push(Value(DataType.BYTE, if(array.arrayvalue!!.any{ v -> v != 0}) 1 else 0))
}
Syscall.FUNC_ALL -> {
val array = evalstack.pop()
evalstack.push(Value(DataType.BYTE, if(array.arrayvalue!!.all{ v -> v != 0}) 1 else 0))
}
else -> throw VmExecutionException("unimplemented syscall $syscall") else -> throw VmExecutionException("unimplemented syscall $syscall")
} }
} }
Opcode.SEC -> carry = true Opcode.SEC -> P_carry = true
Opcode.CLC -> carry = false Opcode.CLC -> P_carry = false
Opcode.TERMINATE -> throw VmTerminationException("terminate instruction") Opcode.TERMINATE -> throw VmTerminationException("terminate instruction")
Opcode.BREAKPOINT -> throw VmBreakpointException() Opcode.BREAKPOINT -> throw VmBreakpointException()
@ -1157,30 +1225,30 @@ class StackVm(val traceOutputFile: String?) {
Opcode.ROL_MEM -> { Opcode.ROL_MEM -> {
val addr = ins.arg!!.integerValue() val addr = ins.arg!!.integerValue()
val value = Value(DataType.BYTE, mem.getByte(addr)) val value = Value(DataType.BYTE, mem.getByte(addr))
val (newValue, newCarry) = value.rol(carry) val (newValue, newCarry) = value.rol(P_carry)
mem.setByte(addr, newValue.integerValue().toShort()) mem.setByte(addr, newValue.integerValue().toShort())
carry = newCarry P_carry = newCarry
} }
Opcode.ROL_MEM_W -> { Opcode.ROL_MEM_W -> {
val addr = ins.arg!!.integerValue() val addr = ins.arg!!.integerValue()
val value = Value(DataType.WORD, mem.getWord(addr)) val value = Value(DataType.WORD, mem.getWord(addr))
val (newValue, newCarry) = value.rol(carry) val (newValue, newCarry) = value.rol(P_carry)
mem.setWord(addr, newValue.integerValue()) mem.setWord(addr, newValue.integerValue())
carry = newCarry P_carry = newCarry
} }
Opcode.ROR_MEM -> { Opcode.ROR_MEM -> {
val addr = ins.arg!!.integerValue() val addr = ins.arg!!.integerValue()
val value = Value(DataType.BYTE, mem.getByte(addr)) val value = Value(DataType.BYTE, mem.getByte(addr))
val (newValue, newCarry) = value.ror(carry) val (newValue, newCarry) = value.ror(P_carry)
mem.setByte(addr, newValue.integerValue().toShort()) mem.setByte(addr, newValue.integerValue().toShort())
carry = newCarry P_carry = newCarry
} }
Opcode.ROR_MEM_W -> { Opcode.ROR_MEM_W -> {
val addr = ins.arg!!.integerValue() val addr = ins.arg!!.integerValue()
val value = Value(DataType.WORD, mem.getWord(addr)) val value = Value(DataType.WORD, mem.getWord(addr))
val (newValue, newCarry) = value.ror(carry) val (newValue, newCarry) = value.ror(P_carry)
mem.setWord(addr, newValue.integerValue()) mem.setWord(addr, newValue.integerValue())
carry = newCarry P_carry = newCarry
} }
Opcode.ROL2_MEM -> { Opcode.ROL2_MEM -> {
val addr = ins.arg!!.integerValue() val addr = ins.arg!!.integerValue()
@ -1209,9 +1277,9 @@ class StackVm(val traceOutputFile: String?) {
Opcode.JUMP -> {} // do nothing; the next instruction is wired up already to the jump target Opcode.JUMP -> {} // do nothing; the next instruction is wired up already to the jump target
Opcode.BCS -> Opcode.BCS ->
return if(carry) ins.next else ins.nextAlt!! return if(P_carry) ins.next else ins.nextAlt!!
Opcode.BCC -> Opcode.BCC ->
return if(carry) ins.nextAlt!! else ins.next return if(P_carry) ins.nextAlt!! else ins.next
Opcode.BEQ -> Opcode.BEQ ->
return if(evalstack.pop().numericValue().toDouble()==0.0) ins.next else ins.nextAlt!! return if(evalstack.pop().numericValue().toDouble()==0.0) ins.next else ins.nextAlt!!
Opcode.BNE -> Opcode.BNE ->
@ -1253,16 +1321,16 @@ class StackVm(val traceOutputFile: String?) {
Opcode.ROL_VAR -> { Opcode.ROL_VAR -> {
val varname = ins.arg!!.stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") val varname = ins.arg!!.stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)")
val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname")
val (newValue, newCarry) = variable.rol(carry) val (newValue, newCarry) = variable.rol(P_carry)
variables[varname] = newValue variables[varname] = newValue
carry = newCarry P_carry = newCarry
} }
Opcode.ROR_VAR -> { Opcode.ROR_VAR -> {
val varname = ins.arg!!.stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") val varname = ins.arg!!.stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)")
val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname")
val (newValue, newCarry) = variable.ror(carry) val (newValue, newCarry) = variable.ror(P_carry)
variables[varname] = newValue variables[varname] = newValue
carry = newCarry P_carry = newCarry
} }
Opcode.ROL2_VAR -> { Opcode.ROL2_VAR -> {
val varname = ins.arg!!.stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") val varname = ins.arg!!.stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)")

View File

@ -443,11 +443,14 @@ tan(x)
atan(x) atan(x)
Arctangent. Arctangent.
log(x) ln(x)
Natural logarithm. Natural logarithm (base E).
log2(x)
Base 2 logarithm.
log10(x) log10(x)
Base-10 logarithm. Base 10 logarithm.
sqrt(x) sqrt(x)
Square root. Square root.