asm fixes

This commit is contained in:
Irmen de Jong 2018-10-24 17:51:56 +02:00
parent fba3cb7301
commit 4effd0b3db
8 changed files with 182 additions and 101 deletions

6
compiler/compile.cmd Normal file
View File

@ -0,0 +1,6 @@
set PROG8_LIBDIR=../prog8lib
set PROG8CLASSPATH=out/production/compiler/
set KOTLINPATH=%USERPROFILE%/.IdeaIC2018.2/config/plugins/Kotlin
set LIBJARS=%KOTLINPATH%/lib/kotlin-stdlib.jar;%KOTLINPATH%/lib/kotlin-reflect.jar;antlr/lib/antlr-runtime-4.7.1.jar
java -Dprog8.libdir=%PROG8_LIBDIR% -cp %PROG8CLASSPATH%;%LIBJARS% prog8.CompilerMainKt %*

View File

@ -18,13 +18,40 @@ sub start() {
float fl1 = 1.1
float fl2 = 2.2
memory byte mbyte = $c000
memory ubyte mubyte = $c001
memory word mword = $c002
memory uword muword = $c004
memory float mfloat = $c006
uw2 = uw
w2 = w
b2 = b
derp=pixely
fl2 = fl1
fl2++
mbyte = 99
mubyte = 99
mword = 99 ; @todo fix ast error literal value missing wordvalue
muword = 99 ; @todo fix ast error literal value missing wordvalue
mword = 999.w
muword = 999.w
mfloat = 1.23456
mbyte = b
mubyte = derp
mword = w
muword = uw
mfloat = fl2
; @todo fix deze assignments:
b = mbyte
derp = mubyte
w = mword
uw = muword
fl2 = mfloat
return

View File

@ -0,0 +1,12 @@
mkdir compiled_java
java -jar ../antlr/lib/antlr-4.7.1-complete.jar -o ./prog8/parser -no-listener -no-visitor -package prog8.parser ../antlr/prog8.g4
@dir /b /S src *.java > sources.txt
javac -verbose -d compiled_java -cp ../antlr/lib/antlr-runtime-4.7.1.jar @sources.txt
@del sources.txt
jar cf parser.jar -C compiled_java prog8
set KOTLINC=%USERPROFILE%\.IdeaIC2018.2\config\plugins\kotlin\kotlinc\bin\kotlinc.bat
%KOTLINC% -verbose -include-runtime -d prog8_kotlin.jar -cp ../antlr/lib/antlr-runtime-4.7.1.jar;parser.jar prog8

View File

@ -7,9 +7,9 @@ enum class Opcode {
PUSH_WORD, // push word value (or 'address' of string / array / matrix)
PUSH_FLOAT, // push float value
PUSH_MEM_B, // push byte value from memory to stack
PUSH_MEM_UB, // push byte value from memory to stack
PUSH_MEM_UB, // push unsigned byte value from memory to stack
PUSH_MEM_W, // push word value from memory to stack
PUSH_MEM_UW, // push word value from memory to stack
PUSH_MEM_UW, // push unsigned word value from memory to stack
PUSH_MEM_FLOAT, // push float value from memory to stack
PUSH_VAR_BYTE, // push byte variable (ubyte, byte)
PUSH_VAR_WORD, // push word variable (uword, word)

View File

@ -352,6 +352,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
}
private fun getFloatConst(value: Value): String =
globalFloatConsts[value.numericValue().toDouble()]
?: throw AssemblyError("should have a global float const for number $value")
private fun simpleInstr2Asm(ins: Instruction): String? {
// a label 'instruction' is simply translated into a asm label
if(ins is LabelInstr) {
@ -393,17 +397,18 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
"_prog8_breakpoint_$breakpointCounter\tnop"
}
Opcode.PUSH_BYTE -> {
" lda #${ins.arg!!.integerValue().toHex()} | sta ${ESTACK_LO.toHex()},x | dex"
}
Opcode.PUSH_WORD -> {
val value = ins.arg!!.integerValue().toHex()
" lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex"
}
Opcode.PUSH_FLOAT -> {
val floatConst = globalFloatConsts[ins.arg!!.numericValue().toDouble()] ?: throw AssemblyError("should have a global float const for number ${ins.arg}")
" lda #<$floatConst | ldy #>$floatConst | jsr prog8_lib.push_float"
}
// todo weer aanzetten?
// Opcode.PUSH_BYTE -> {
// " lda #${ins.arg!!.integerValue().toHex()} | sta ${ESTACK_LO.toHex()},x | dex"
// }
// Opcode.PUSH_WORD -> {
// val value = ins.arg!!.integerValue().toHex()
// " lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex"
// }
// Opcode.PUSH_FLOAT -> {
// val floatConst = getFloatConst(ins.arg)
// " lda #<$floatConst | ldy #>$floatConst | jsr prog8_lib.push_float"
// }
Opcode.PUSH_VAR_BYTE -> {
when(ins.callLabel) {
"X" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself")
@ -721,72 +726,15 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
val opcodes = segment.map { it.opcode }
val result = mutableListOf<AsmFragment>()
// check for regular 'assignments' (a push immediately followed by a pop)
if(opcodes[0] in pushOpcodes && opcodes[1] in popOpcodes) {
when(opcodes[0]) {
Opcode.PUSH_BYTE -> when(opcodes[1]) {
Opcode.POP_VAR_BYTE -> {
result.add(AsmFragment(
" lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}",
10, 2))
}
else -> TODO("pop byte ${segment[1]}")
}
Opcode.PUSH_WORD -> when(opcodes[1]) {
Opcode.POP_VAR_WORD -> {
result.add(AsmFragment(
"""
lda #<${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}
lda #>${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}+1
""",
10, 2))
}
else -> TODO("pop word ${segment[1]}")
}
Opcode.PUSH_FLOAT -> {
val floatConst = globalFloatConsts[segment[0].arg!!.numericValue().toDouble()] ?: throw AssemblyError("should have a global float const for number ${segment[0].arg}")
result.add(AsmFragment(
"""
lda #<$floatConst
ldy #>$floatConst
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<${segment[1].callLabel}
ldy #>${segment[1].callLabel}
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
""", 10,2))
}
Opcode.PUSH_MEM_B -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_MEM_UB -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_MEM_W -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_MEM_UW -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_MEM_FLOAT -> TODO("assignment ${segment[0]} --> ${segment[1]}")
Opcode.PUSH_VAR_BYTE -> {
if(opcodes[1] == Opcode.POP_VAR_BYTE)
throw AssemblyError("push+pop var byte should have been changed into COPY_VAR_BYTE opcode")
else TODO("assignment ${segment[0]} --> ${segment[1]}")
}
Opcode.PUSH_VAR_WORD -> {
if(opcodes[1] == Opcode.POP_VAR_WORD)
throw AssemblyError("push+pop var word should have been changed into COPY_VAR_WORD opcode")
else TODO("assignment ${segment[0]} --> ${segment[1]}")
}
Opcode.PUSH_VAR_FLOAT -> {
if(opcodes[1] == Opcode.POP_VAR_FLOAT)
throw AssemblyError("push+pop var float should have been changed into COPY_VAR_FLOAT opcode")
else TODO("assignment ${segment[0]} --> ${segment[1]}")
}
else -> throw AssemblyError("strange push opcode ${segment[0]}")
}
// check for direct var assignments that should have been converted into COPY_VAR_XXX opcodes
if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[1]==Opcode.POP_VAR_BYTE) ||
(opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[1]==Opcode.POP_VAR_WORD) ||
(opcodes[0]==Opcode.PUSH_VAR_FLOAT && opcodes[1]==Opcode.POP_VAR_FLOAT)) {
throw AssemblyError("push+pop var should have been changed into COPY_VAR_XXX opcode")
}
// check for operations that modify a single value, by putting it on the stack (and popping it afterwards)
else if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[2]==Opcode.POP_VAR_BYTE) ||
if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[2]==Opcode.POP_VAR_BYTE) ||
(opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[2]==Opcode.POP_VAR_WORD)) {
if (segment[0].callLabel == segment[2].callLabel) {
val fragment = sameVarOperation(segment[0].callLabel!!, segment[1])
@ -1032,26 +980,115 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
class AsmPattern(val sequence: List<Opcode>, val prio: Int, val asm: (List<Instruction>)->String?)
private val patterns = listOf(
// assignment: var = byte
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_VAR_BYTE), 10) { segment ->
when (segment[1].callLabel) {
"A", "X", "Y" -> " ld${segment[1].callLabel!!.toLowerCase()} #${segment[0].arg!!.integerValue().toHex()}"
else -> null
"A", "X", "Y" ->
" ld${segment[1].callLabel!!.toLowerCase()} #${segment[0].arg!!.integerValue().toHex()}"
else ->
" lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}"
}
},
// assignment: mem = byte/ubyte
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_B), 10) { segment ->
" lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}"
},
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_UB), 9) { segment ->
" lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}"
},
// assignment: var = word
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_VAR_WORD), 10) { segment ->
val number = segment[0].arg!!.integerValue().toHex()
when (segment[1].callLabel) {
"AX" -> " lda #<$number | ldx #>$number"
"AY" -> " lda #<$number | ldy #>$number"
"XY" -> " ldx #<$number | ldy #>$number"
else -> null
else ->
"""
lda #<${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}
lda #>${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].callLabel}+1
"""
}
},
// assignment: mem = word/uword
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_W), 10) { segment ->
"""
lda #<${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].arg!!.integerValue().toHex()}
lda #>${segment[0].arg!!.integerValue().toHex()}
sta ${(segment[1].arg!!.integerValue()+1).toHex()}
"""
},
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_UW), 9) { segment ->
"""
lda #<${segment[0].arg!!.integerValue().toHex()}
sta ${segment[1].arg!!.integerValue().toHex()}
lda #>${segment[0].arg!!.integerValue().toHex()}
sta ${(segment[1].arg!!.integerValue()+1).toHex()}
"""
},
// assignment: var = float
AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.POP_VAR_FLOAT), 10) { segment ->
val floatConst = getFloatConst(segment[0].arg!!)
"""
lda #<$floatConst
ldy #>$floatConst
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<${segment[1].callLabel}
ldy #>${segment[1].callLabel}
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
"""
},
// assignment: mem = float
AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.POP_MEM_FLOAT), 10) { segment ->
val floatConst = getFloatConst(segment[0].arg!!)
"""
lda #<$floatConst
ldy #>$floatConst
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<${segment[1].arg!!.integerValue().toHex()}
ldy #>${segment[1].arg!!.integerValue().toHex()}
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
"""
},
// assignment: mem = floatvar
AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.POP_MEM_FLOAT), 10) { segment ->
"""
lda #<${segment[0].callLabel}
ldy #>${segment[0].callLabel}
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
lda #<${segment[1].arg!!.integerValue().toHex()}
ldy #>${segment[1].arg!!.integerValue().toHex()}
sta ${C64Zeropage.SCRATCH_W2}
sty ${C64Zeropage.SCRATCH_W2+1}
jsr prog8_lib.copy_float
"""
},
// assignment: var = bytearray[index]
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE), 10) { segment ->
val index = segment[0].arg!!.integerValue()
when (segment[2].callLabel) {
"A", "X", "Y" -> " ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index"
else -> null
"A", "X", "Y" ->
" ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index"
else ->
TODO("assign byte to array indexed")
}
}
)

View File

@ -1,16 +1,17 @@
// Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7
// Generated from ../antlr/prog8.g4 by ANTLR 4.7.1
package prog8.parser;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNDeserializer;
import org.antlr.v4.runtime.atn.LexerATNSimulator;
import org.antlr.v4.runtime.atn.PredictionContextCache;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class prog8Lexer extends Lexer {
static { RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); }
static { RuntimeMetaData.checkVersion("4.7.1", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =

View File

@ -1,19 +1,17 @@
// Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7
// Generated from ../antlr/prog8.g4 by ANTLR 4.7.1
package prog8.parser;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNDeserializer;
import org.antlr.v4.runtime.atn.ParserATNSimulator;
import org.antlr.v4.runtime.atn.PredictionContextCache;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.runtime.tree.*;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class prog8Parser extends Parser {
static { RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); }
static { RuntimeMetaData.checkVersion("4.7.1", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =

View File

@ -27,9 +27,9 @@ class Memory {
fun setSByte(address: Int, value: Short) {
if(value !in -128..127) throw VmExecutionException("byte value out of range")
if(value>=0)
setUByte(address, value)
mem[address] = value
else
setUByte(address, ((abs(value.toInt()) xor 255)+1).toShort()) // 2's complement
mem[address] = ((abs(value.toInt()) xor 255)+1).toShort() // 2's complement
}
fun getUWord(address: Int): Int {