This commit is contained in:
Irmen de Jong 2023-04-11 22:28:19 +02:00
parent 7c1d5cadd7
commit b55be093be
14 changed files with 63 additions and 62 deletions

View File

@ -383,10 +383,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
var resultFpReg = -1
if(fcall.type==DataType.FLOAT) {
resultFpReg = codeGen.registers.nextFreeFloat()
addInstr(result, IRInstruction(Opcode.CALLRVAL, IRDataType.FLOAT, fpReg1=resultFpReg, labelSymbol=fcall.name), null)
addInstr(result, IRInstruction(Opcode.CALLR, IRDataType.FLOAT, fpReg1=resultFpReg, labelSymbol=fcall.name), null)
} else {
resultReg = codeGen.registers.nextFree()
addInstr(result, IRInstruction(Opcode.CALLRVAL, codeGen.irType(fcall.type), reg1=resultReg, labelSymbol=fcall.name), null)
addInstr(result, IRInstruction(Opcode.CALLR, codeGen.irType(fcall.type), reg1=resultReg, labelSymbol=fcall.name), null)
}
ExpressionCodeResult(result, codeGen.irType(fcall.type), resultReg, resultFpReg)
}

View File

@ -1458,12 +1458,12 @@ class IRCodeGen(
if(value.type==DataType.FLOAT) {
val tr = expressionEval.translateExpression(value)
addToResult(result, tr, -1, tr.resultFpReg)
addInstr(result, IRInstruction(Opcode.RETURNREG, IRDataType.FLOAT, fpReg1 = tr.resultFpReg), null)
addInstr(result, IRInstruction(Opcode.RETURNR, IRDataType.FLOAT, fpReg1 = tr.resultFpReg), null)
}
else {
val tr = expressionEval.translateExpression(value)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.RETURNREG, irType(value.type) , reg1=tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.RETURNR, irType(value.type) , reg1=tr.resultReg), null)
}
}
return result

View File

@ -184,7 +184,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
}
// remove useless RETURN
if(idx>0 && (ins.opcode == Opcode.RETURN || ins.opcode==Opcode.RETURNREG)) {
if(idx>0 && (ins.opcode == Opcode.RETURN || ins.opcode==Opcode.RETURNR)) {
val previous = chunk.instructions[idx-1]
if(previous.opcode in OpcodesThatJump) {
chunk.instructions.removeAt(idx)
@ -204,7 +204,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
// replace call + return --> jump
if(idx>0 && ins.opcode==Opcode.RETURN) {
val previous = chunk.instructions[idx-1]
if(previous.opcode==Opcode.CALL || previous.opcode==Opcode.CALLRVAL) {
if(previous.opcode==Opcode.CALL || previous.opcode==Opcode.CALLR) {
chunk.instructions[idx-1] = IRInstruction(Opcode.JUMP, address = previous.address, labelSymbol = previous.labelSymbol, branchTarget = previous.branchTarget)
chunk.instructions.removeAt(idx)
changed = true

View File

@ -200,7 +200,7 @@ sub str2uword(str string) -> uword {
push.w r65535
syscall 11
pop.w r0
returnreg.w r0
returnr.w r0
}}
}
@ -213,7 +213,7 @@ sub str2word(str string) -> word {
push.w r65535
syscall 12
pop.w r0
returnreg.w r0
returnr.w r0
}}
}

View File

@ -22,7 +22,7 @@ sub pow(float value, float power) -> float {
loadm.f fr0,floats.pow.value
loadm.f fr1,floats.pow.power
fpow.f fr0,fr1
returnreg.f fr0
returnr.f fr0
}}
}
@ -30,7 +30,7 @@ sub fabs(float value) -> float {
%ir {{
loadm.f fr0,floats.fabs.value
fabs.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -38,7 +38,7 @@ sub sin(float angle) -> float {
%ir {{
loadm.f fr0,floats.sin.angle
fsin.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -46,7 +46,7 @@ sub cos(float angle) -> float {
%ir {{
loadm.f fr0,floats.cos.angle
fcos.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -54,7 +54,7 @@ sub tan(float value) -> float {
%ir {{
loadm.f fr0,floats.tan.value
ftan.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -62,7 +62,7 @@ sub atan(float value) -> float {
%ir {{
loadm.f fr0,floats.atan.value
fatan.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -70,7 +70,7 @@ sub ln(float value) -> float {
%ir {{
loadm.f fr0,floats.ln.value
fln.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -78,7 +78,7 @@ sub log2(float value) -> float {
%ir {{
loadm.f fr0,floats.log2.value
flog.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -86,7 +86,7 @@ sub sqrt(float value) -> float {
%ir {{
loadm.f fr0,floats.sqrt.value
sqrt.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -104,7 +104,7 @@ sub round(float value) -> float {
%ir {{
loadm.f fr0,floats.round.value
fround.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -112,7 +112,7 @@ sub floor(float value) -> float {
%ir {{
loadm.f fr0,floats.floor.value
ffloor.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -121,7 +121,7 @@ sub ceil(float value) -> float {
%ir {{
loadm.f fr0,floats.ceil.value
fceil.f fr0,fr0
returnreg.f fr0
returnr.f fr0
}}
}
@ -129,7 +129,7 @@ sub rndf() -> float {
%ir {{
syscall 35
pop.f fr0
returnreg.f fr0
returnr.f fr0
}}
}

View File

@ -163,7 +163,7 @@ math {
%ir {{
syscall 33
pop.b r0
returnreg.b r0
returnr.b r0
}}
}
@ -171,7 +171,7 @@ math {
%ir {{
syscall 34
pop.w r0
returnreg.w r0
returnr.w r0
}}
}

View File

@ -90,7 +90,7 @@ string {
push.w r65535
syscall 29
pop.b r0
returnreg.b r0
returnr.b r0
}}
}

View File

@ -118,7 +118,7 @@ sys {
push.w r65535
syscall 30
pop.b r0
returnreg.b r0
returnr.b r0
}}
}
}

View File

@ -131,7 +131,7 @@ sub input_chars (uword buffer) -> ubyte {
push.b r65535
syscall 6
pop.b r0
returnreg.b r0
returnr.b r0
}}
}

View File

@ -3,11 +3,15 @@ TODO
For next minor release
^^^^^^^^^^^^^^^^^^^^^^
- try to optimize newexpr a bit more
...
For 9.0 major changes
^^^^^^^^^^^^^^^^^^^^^
- try to reintroduce builtin functions max/maxw/min/minw that take 2 args and return the largest/smallest of them.
This is a major change because it will likely break existing code that is now using min and max as variable names.
- get rid of the disknumber parameter everywhere in diskio, make it a configurable variable that defaults to 8.
the large majority of users will only deal with a single disk drive so why not make it easier for them.
- duplicate diskio for cx16 (get rid of cx16diskio, just copy diskio and tweak everything) + documentation
@ -33,9 +37,9 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- ir: investigate passing parameters to function calls using fixed set of regs r60000,r60001, etc.
these have to be offset somehow by the subroutine number (?) somehow to have a unique list of them per subroutine.
also only if we can optimize the subroutine to replace the parameter variables to those registers.
- ir: idea? (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
global initialization values are simply a list of LOAD instructions.
Variables replaced include all subroutine parameters! So the only variables that remain as variables are arrays and strings.
- ir: can we determine for the loop variable in forloops if it could be kept in a (virtual) register instead of a real variable? Need to be able to check if the variable is used by another statement beside just the for loop.
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)

View File

@ -17,8 +17,11 @@ Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by t
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.
Most instructions have an associated data type 'b','w','f'. (omitting it defaults to 'b' - byte).
Currently NO support for 24 or 32 bits integers.
Value types: integers (.b=byte=8 bits, .w=word=16 bits) and float (.f=32 bits). Omitting it defaults to b.
Currently ther is NO support for 24 or 32 bits integers.
There is no distinction between signed and unsigned integers.
Instead, a different instruction is used if a distinction should be made (for example div and divs).
Floating point operations are just 'f' typed regular instructions, however there are a few unique fp conversion instructions.
Instructions taking more than 1 register cannot take the same register multiple times! (to avoid confusing different datatypes)
@ -50,11 +53,11 @@ CONTROL FLOW
------------
jump location - continue running at instruction number given by location
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction)
call location - save current instruction location+1, continue execution at instruction nr given by location. Expect no return value.
callrval reg1, location - like call but expects a return value from a returnreg instruction, and puts that in reg1
call location - save current instruction location+1, continue execution at instruction nr given by location. No return value is expected.
callr reg1, location - like call but expects the routine to return a value with a returnr instruction, it then puts that in reg1
syscall value - do a systemcall identified by call number, result value(s) are pushed on value stack so need to be POPped off (depends on syscall)
return - restore last saved instruction location and continue at that instruction. No return value.
returnreg reg1 - like return, but also returns a value to the caller via reg1
returnr reg1 - like return, but also returns the value in reg1 to the caller
BRANCHING and CONDITIONALS
@ -112,12 +115,12 @@ dec reg1 - reg1 = reg1-1
decm address - memory at address -= 1
neg reg1 - reg1 = sign negation of reg1
negm address - sign negate memory at address
addr reg1, reg2 - reg1 += reg2 (unsigned + signed)
add reg1, value - reg1 += value (unsigned + signed)
addm reg1, address - memory at address += reg1 (unsigned + signed)
subr reg1, reg2 - reg1 -= reg2 (unsigned + signed)
sub reg1, value - reg1 -= value (unsigned + signed)
subm reg1, address - memory at address -= reg1 (unsigned + signed)
addr reg1, reg2 - reg1 += reg2
add reg1, value - reg1 += value
addm reg1, address - memory at address += reg1
subr reg1, reg2 - reg1 -= reg2
sub reg1, value - reg1 -= value
subm reg1, address - memory at address -= reg1
mulr reg1, reg2 - unsigned multiply reg1 *= reg2 note: byte*byte->byte, no type extension to word!
mul reg1, value - unsigned multiply reg1 *= value note: byte*byte->byte, no type extension to word!
mulm reg1, address - memory at address *= reg2 note: byte*byte->byte, no type extension to word!
@ -235,10 +238,10 @@ enum class Opcode {
JUMP,
JUMPA,
CALL,
CALLRVAL,
CALLR,
SYSCALL,
RETURN,
RETURNREG,
RETURNR,
BSTCC,
BSTCS,
@ -375,16 +378,16 @@ val OpcodesThatJump = setOf(
Opcode.JUMP,
Opcode.JUMPA,
Opcode.RETURN,
Opcode.RETURNREG
Opcode.RETURNR
)
val OpcodesThatBranch = setOf(
Opcode.JUMP,
Opcode.JUMPA,
Opcode.RETURN,
Opcode.RETURNREG,
Opcode.RETURNR,
Opcode.CALL,
Opcode.CALLRVAL,
Opcode.CALLR,
Opcode.SYSCALL,
Opcode.BSTCC,
Opcode.BSTCS,
@ -515,10 +518,10 @@ val instructionFormats = mutableMapOf(
Opcode.JUMP to InstructionFormat.from("N,<a"),
Opcode.JUMPA to InstructionFormat.from("N,<a"),
Opcode.CALL to InstructionFormat.from("N,<a"),
Opcode.CALLRVAL to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
Opcode.CALLR to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
Opcode.SYSCALL to InstructionFormat.from("N,<i"),
Opcode.RETURN to InstructionFormat.from("N"),
Opcode.RETURNREG to InstructionFormat.from("BW,>r1 | F,>fr1"),
Opcode.RETURNR to InstructionFormat.from("BW,>r1 | F,>fr1"),
Opcode.BSTCC to InstructionFormat.from("N,<a"),
Opcode.BSTCS to InstructionFormat.from("N,<a"),
Opcode.BSTEQ to InstructionFormat.from("N,<a"),

View File

@ -134,7 +134,7 @@ class IRProgram(val name: String,
// link all jump and branching instructions to their target
chunk.instructions.forEach {
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNREG && it.labelSymbol!=null)
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNR && it.labelSymbol!=null)
it.branchTarget = labeledChunks.getValue(it.labelSymbol)
// note: branches with an address value cannot be linked to something...
}

View File

@ -89,7 +89,7 @@ internal class BitmapScreenPanel(private val drawImage: BufferedImage, val pixel
override fun paint(graphics: Graphics) {
val g2d = graphics as Graphics2D
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
g2d.drawImage(drawImage, 0, 0, size.width, size.height, null)
Toolkit.getDefaultToolkit().sync()
}

View File

@ -17,7 +17,7 @@ Virtual machine specs:
Program to execute is not stored in the system memory, it's just a separate list of instructions.
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
65536 bytes of memory, thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each.
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
@ -176,11 +176,10 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.STOREZI -> InsSTOREZI(ins)
Opcode.JUMP -> InsJUMP(ins)
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
Opcode.CALL -> InsCALL(ins)
Opcode.CALLRVAL -> InsCALLRVAL(ins)
Opcode.CALL, Opcode.CALLR -> InsCALL(ins)
Opcode.SYSCALL -> InsSYSCALL(ins)
Opcode.RETURN -> InsRETURN()
Opcode.RETURNREG -> InsRETURNREG(ins)
Opcode.RETURNR -> InsRETURNR(ins)
Opcode.BSTCC -> InsBSTCC(ins)
Opcode.BSTCS -> InsBSTCS(ins)
Opcode.BSTEQ -> InsBSTEQ(ins)
@ -591,11 +590,6 @@ class VirtualMachine(irProgram: IRProgram) {
}
private fun InsCALL(i: IRInstruction) {
callStack.push(CallSiteContext(pcChunk, pcIndex+1, null, null))
branchTo(i)
}
private fun InsCALLRVAL(i: IRInstruction) {
callStack.push(CallSiteContext(pcChunk, pcIndex+1, i.reg1, i.fpReg1))
branchTo(i)
}
@ -611,7 +605,7 @@ class VirtualMachine(irProgram: IRProgram) {
}
}
private fun InsRETURNREG(i: IRInstruction) {
private fun InsRETURNR(i: IRInstruction) {
if(callStack.isEmpty())
exit(0)
else {
@ -2293,11 +2287,11 @@ class VirtualMachine(irProgram: IRProgram) {
}
fun gfx_getpixel() {
val y = valueStack.popw()
val x = valueStack.popw()
if(window==null)
registers.setUB(0, 0u)
valueStack.push(0u)
else {
val y = valueStack.popw()
val x = valueStack.popw()
val color = Color(window!!.getpixel(x.toInt(), y.toInt()))
valueStack.push(color.green.toUByte()) // gets called from a syscall, return value via stack.
}