mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
vm tweaks
This commit is contained in:
parent
e382be89db
commit
c05cd72d23
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user