mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
stackvm functions
This commit is contained in:
parent
54aeee2676
commit
63492a1805
@ -26,7 +26,9 @@ loop:
|
||||
push_var main.textcolor
|
||||
syscall GFX_PIXEL
|
||||
; 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"
|
||||
; push b:8d
|
||||
; syscall WRITE_CHAR
|
||||
|
@ -1043,7 +1043,8 @@ class FunctionCall(override var target: IdentifierReference,
|
||||
"asin" -> builtinAsin(arglist, position, namespace)
|
||||
"tan" -> builtinTan(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)
|
||||
"sqrt" -> builtinSqrt(arglist, position, namespace)
|
||||
"max" -> builtinMax(arglist, position, namespace)
|
||||
|
@ -497,8 +497,8 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
||||
return false
|
||||
}
|
||||
val rangeSize=range.size()
|
||||
if(rangeSize!=null && (rangeSize<1 || rangeSize>255)) {
|
||||
checkResult.add(ExpressionError("size of range for string must be 1..255, instead of $rangeSize", range.position))
|
||||
if(rangeSize!=null && (rangeSize<0 || rangeSize>255)) {
|
||||
checkResult.add(ExpressionError("size of range for string must be 0..255, instead of $rangeSize", range.position))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@ -183,11 +183,15 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
||||
private fun translate(stmt: Continue) {
|
||||
stackvmProg.line(stmt.position)
|
||||
TODO("translate CONTINUE")
|
||||
// * ..continue statement: goto continue
|
||||
// we somehow have to know what the correct 'continue' label is
|
||||
}
|
||||
|
||||
private fun translate(stmt: Break) {
|
||||
stackvmProg.line(stmt.position)
|
||||
TODO("translate BREAK")
|
||||
// * ..break statement: goto break
|
||||
// we somehow have to know what the correct 'break' label is
|
||||
}
|
||||
|
||||
private fun translate(branch: BranchStatement) {
|
||||
|
@ -1,17 +1,16 @@
|
||||
package prog8.functions
|
||||
|
||||
import prog8.ast.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.log2
|
||||
|
||||
|
||||
val BuiltinFunctionNames = setOf(
|
||||
"P_carry", "P_irqd", "rol", "ror", "rol2", "ror2", "lsl", "lsr",
|
||||
"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",
|
||||
"_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) {
|
||||
"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
|
||||
"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())
|
||||
"max", "min" -> datatypeFromListArg(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 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)
|
||||
val arg = args.single()
|
||||
when(arg) {
|
||||
@ -64,7 +73,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
||||
is VarDecl -> {
|
||||
val value = stmt.value
|
||||
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_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")
|
||||
}
|
||||
}
|
||||
@ -173,9 +182,12 @@ fun builtinTan(args: List<IExpression>, position: Position, namespace:INameScope
|
||||
fun builtinAtan(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||
= 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)
|
||||
|
||||
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
|
||||
= 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 number = constval.asNumericValue
|
||||
return when (number) {
|
||||
is Int, is Byte, is Short -> numericLiteral(abs(number.toInt()), args[0].position)
|
||||
is Double -> numericLiteral(abs(number.toDouble()), args[0].position)
|
||||
is Int, is Byte, is Short -> numericLiteral(Math.abs(number.toInt()), args[0].position)
|
||||
is Double -> numericLiteral(Math.abs(number.toDouble()), args[0].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 {
|
||||
val floatNum=value.toDouble()
|
||||
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.
|
||||
else
|
||||
floatNum
|
||||
|
@ -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_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
|
||||
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_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
|
||||
|
||||
FUNC_P_CARRY(64),
|
||||
FUNC_P_IRQD(65),
|
||||
FUNC_ROL(66),
|
||||
FUNC_ROR(67),
|
||||
FUNC_ROL2(68),
|
||||
FUNC_ROR2(69),
|
||||
FUNC_LSL(70),
|
||||
FUNC_LSR(71),
|
||||
FUNC_SIN(72),
|
||||
FUNC_COS(73),
|
||||
FUNC_ABS(74),
|
||||
FUNC_ACOS(75),
|
||||
FUNC_ASIN(76),
|
||||
FUNC_TAN(77),
|
||||
FUNC_ATAN(78),
|
||||
FUNC_LOG(79),
|
||||
FUNC_LOG10(80),
|
||||
FUNC_SQRT(81),
|
||||
FUNC_RAD(82),
|
||||
FUNC_DEG(83),
|
||||
FUNC_ROUND(84),
|
||||
FUNC_FLOOR(85),
|
||||
FUNC_CEIL(86),
|
||||
FUNC_MAX(87),
|
||||
FUNC_MIN(88),
|
||||
FUNC_AVG(89),
|
||||
FUNC_SUM(90),
|
||||
FUNC_LEN(91),
|
||||
FUNC_ANY(92),
|
||||
FUNC_ALL(93),
|
||||
FUNC_LSB(94),
|
||||
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)
|
||||
FUNC_SIN(66),
|
||||
FUNC_COS(67),
|
||||
FUNC_ABS(68),
|
||||
FUNC_ACOS(69),
|
||||
FUNC_ASIN(70),
|
||||
FUNC_TAN(71),
|
||||
FUNC_ATAN(72),
|
||||
FUNC_LN(73),
|
||||
FUNC_LOG2(74),
|
||||
FUNC_LOG10(75),
|
||||
FUNC_SQRT(76),
|
||||
FUNC_RAD(77),
|
||||
FUNC_DEG(78),
|
||||
FUNC_ROUND(79),
|
||||
FUNC_FLOOR(80),
|
||||
FUNC_CEIL(81),
|
||||
FUNC_MAX(82),
|
||||
FUNC_MIN(83),
|
||||
FUNC_AVG(84),
|
||||
FUNC_SUM(85),
|
||||
FUNC_LEN(86),
|
||||
FUNC_ANY(87),
|
||||
FUNC_ALL(88),
|
||||
FUNC_RND(89), // push a random byte on the stack
|
||||
FUNC_RNDW(90), // push a random word on the stack
|
||||
FUNC_RNDF(91) // push a random float on the stack (between 0.0 and 1.0)
|
||||
|
||||
// note: not all builtin functions of the Prog8 language are present as functions:
|
||||
// some of them are already opcodes (such as MSB and ROL)!
|
||||
}
|
||||
|
||||
class Memory {
|
||||
@ -814,7 +810,8 @@ class StackVm(val traceOutputFile: String?) {
|
||||
private val evalstack = MyStack<Value>() // evaluation 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 carry: Boolean = false
|
||||
private var P_carry: Boolean = false
|
||||
private var P_irqd: Boolean = false
|
||||
private var program = listOf<Instruction>()
|
||||
private var traceOutput = if(traceOutputFile!=null) PrintStream(File(traceOutputFile), "utf-8") else null
|
||||
private lateinit var currentIns: Instruction
|
||||
@ -924,7 +921,7 @@ class StackVm(val traceOutputFile: String?) {
|
||||
Opcode.ARRAY -> {
|
||||
val amount = ins.arg!!.integerValue()
|
||||
val array = mutableListOf<Int>()
|
||||
for (i in 0..amount) {
|
||||
for (i in 1..amount) {
|
||||
val value = evalstack.pop()
|
||||
if(value.type!=DataType.BYTE && value.type!=DataType.WORD)
|
||||
throw VmExecutionException("array requires values to be all byte/word")
|
||||
@ -986,8 +983,8 @@ class StackVm(val traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.ROL -> {
|
||||
val v = evalstack.pop()
|
||||
val (result, newCarry) = v.rol(carry)
|
||||
this.carry = newCarry
|
||||
val (result, newCarry) = v.rol(P_carry)
|
||||
this.P_carry = newCarry
|
||||
evalstack.push(result)
|
||||
}
|
||||
Opcode.ROL2 -> {
|
||||
@ -996,8 +993,8 @@ class StackVm(val traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.ROR -> {
|
||||
val v = evalstack.pop()
|
||||
val (result, newCarry) = v.ror(carry)
|
||||
this.carry = newCarry
|
||||
val (result, newCarry) = v.ror(P_carry)
|
||||
this.P_carry = newCarry
|
||||
evalstack.push(result)
|
||||
}
|
||||
Opcode.ROR2 -> {
|
||||
@ -1054,19 +1051,10 @@ class StackVm(val traceOutputFile: String?) {
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> print(value.arrayvalue)
|
||||
}
|
||||
}
|
||||
Syscall.INPUT_VAR -> {
|
||||
// TODO: replace with regular INPUT_STR that simply puts a str on the stack (1 argument: the max. length of the input)
|
||||
val varname = ins.callLabel ?: throw VmExecutionException("$syscall expects string argument (the variable name)")
|
||||
val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname")
|
||||
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.INPUT_STR -> {
|
||||
val maxlen = evalstack.pop().integerValue()
|
||||
val input = readLine()?.substring(0, maxlen) ?: ""
|
||||
evalstack.push(Value(DataType.STR, null, input))
|
||||
}
|
||||
Syscall.GFX_PIXEL -> {
|
||||
// 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_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble())))
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
Opcode.SEC -> carry = true
|
||||
Opcode.CLC -> carry = false
|
||||
Opcode.SEC -> P_carry = true
|
||||
Opcode.CLC -> P_carry = false
|
||||
Opcode.TERMINATE -> throw VmTerminationException("terminate instruction")
|
||||
Opcode.BREAKPOINT -> throw VmBreakpointException()
|
||||
|
||||
@ -1157,30 +1225,30 @@ class StackVm(val traceOutputFile: String?) {
|
||||
Opcode.ROL_MEM -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
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())
|
||||
carry = newCarry
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROL_MEM_W -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
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())
|
||||
carry = newCarry
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROR_MEM -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
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())
|
||||
carry = newCarry
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROR_MEM_W -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
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())
|
||||
carry = newCarry
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROL2_MEM -> {
|
||||
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.BCS ->
|
||||
return if(carry) ins.next else ins.nextAlt!!
|
||||
return if(P_carry) ins.next else ins.nextAlt!!
|
||||
Opcode.BCC ->
|
||||
return if(carry) ins.nextAlt!! else ins.next
|
||||
return if(P_carry) ins.nextAlt!! else ins.next
|
||||
Opcode.BEQ ->
|
||||
return if(evalstack.pop().numericValue().toDouble()==0.0) ins.next else ins.nextAlt!!
|
||||
Opcode.BNE ->
|
||||
@ -1253,16 +1321,16 @@ class StackVm(val traceOutputFile: String?) {
|
||||
Opcode.ROL_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")
|
||||
val (newValue, newCarry) = variable.rol(carry)
|
||||
val (newValue, newCarry) = variable.rol(P_carry)
|
||||
variables[varname] = newValue
|
||||
carry = newCarry
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROR_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")
|
||||
val (newValue, newCarry) = variable.ror(carry)
|
||||
val (newValue, newCarry) = variable.ror(P_carry)
|
||||
variables[varname] = newValue
|
||||
carry = newCarry
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROL2_VAR -> {
|
||||
val varname = ins.arg!!.stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)")
|
||||
|
@ -443,11 +443,14 @@ tan(x)
|
||||
atan(x)
|
||||
Arctangent.
|
||||
|
||||
log(x)
|
||||
Natural logarithm.
|
||||
ln(x)
|
||||
Natural logarithm (base E).
|
||||
|
||||
log2(x)
|
||||
Base 2 logarithm.
|
||||
|
||||
log10(x)
|
||||
Base-10 logarithm.
|
||||
Base 10 logarithm.
|
||||
|
||||
sqrt(x)
|
||||
Square root.
|
||||
|
Loading…
x
Reference in New Issue
Block a user