mirror of
https://github.com/irmen/prog8.git
synced 2025-02-04 02:30:19 +00:00
asm fixes
This commit is contained in:
parent
fba3cb7301
commit
4effd0b3db
6
compiler/compile.cmd
Normal file
6
compiler/compile.cmd
Normal 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 %*
|
@ -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
|
||||
|
12
compiler/src/build_the_compiler.cmd
Normal file
12
compiler/src/build_the_compiler.cmd
Normal 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
|
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -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 =
|
||||
|
@ -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 =
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user