mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
more ast-codegen v2
This commit is contained in:
parent
03782a37a2
commit
776c844d02
@ -52,7 +52,7 @@ asmsub MOVMF (uword mflpt @ XY) clobbers(A,Y) = $bbd4 ; store fac1 to memory
|
||||
|
||||
; fac1-> signed word in Y/A (might throw ILLEGAL QUANTITY)
|
||||
; (tip: use c64flt.FTOSWRDAY to get A/Y output; lo/hi switched to normal little endian order)
|
||||
asmsub FTOSWORDYA () clobbers(X) -> ubyte @ Y, ubyte @ A = $b1aa
|
||||
asmsub FTOSWORDYA () clobbers(X) -> ubyte @ Y, ubyte @ A = $b1aa ; note: calls AYINT.
|
||||
|
||||
; fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY) (result also in $14/15)
|
||||
; (tip: use c64flt.GETADRAY to get A/Y output; lo/hi switched to normal little endian order)
|
||||
@ -196,8 +196,8 @@ sub print_f (float value) {
|
||||
; ---- prints the floating point value (without a newline) using basic rom routines.
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZPREGX
|
||||
lda #<print_f_value
|
||||
ldy #>print_f_value
|
||||
lda #<value
|
||||
ldy #>value
|
||||
jsr MOVFM ; load float into fac1
|
||||
jsr FOUT ; fac1 to string in A/Y
|
||||
jsr c64.STROUT ; print string in A/Y
|
||||
@ -310,7 +310,7 @@ stack_uw2float .proc
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
|
||||
stack_float2w .proc
|
||||
stack_float2w .proc ; also used for float2b
|
||||
jsr pop_float_fac1
|
||||
stx c64.SCRATCH_ZPREGX
|
||||
jsr AYINT
|
||||
@ -323,7 +323,7 @@ stack_float2w .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
stack_float2uw .proc
|
||||
stack_float2uw .proc ; also used for float2ub
|
||||
jsr pop_float_fac1
|
||||
stx c64.SCRATCH_ZPREGX
|
||||
jsr GETADR
|
||||
|
@ -1,6 +1,7 @@
|
||||
package prog8.ast.base
|
||||
|
||||
import prog8.ast.Node
|
||||
import prog8.compiler.target.c64.MachineDefinition
|
||||
|
||||
/**************************** AST Data classes ****************************/
|
||||
|
||||
@ -25,10 +26,10 @@ enum class DataType {
|
||||
infix fun isAssignableTo(targetType: DataType) =
|
||||
// what types are assignable to others without loss of precision?
|
||||
when(this) {
|
||||
UBYTE -> targetType in setOf(UBYTE, UWORD, WORD, FLOAT)
|
||||
BYTE -> targetType in setOf(BYTE, UBYTE, UWORD, WORD, FLOAT)
|
||||
UBYTE -> targetType in setOf(UBYTE, WORD, UWORD, FLOAT)
|
||||
BYTE -> targetType in setOf(BYTE, WORD, FLOAT)
|
||||
UWORD -> targetType in setOf(UWORD, FLOAT)
|
||||
WORD -> targetType in setOf(WORD, UWORD, FLOAT)
|
||||
WORD -> targetType in setOf(WORD, FLOAT)
|
||||
FLOAT -> targetType == FLOAT
|
||||
STR -> targetType == STR || targetType==STR_S
|
||||
STR_S -> targetType == STR || targetType==STR_S
|
||||
@ -52,6 +53,16 @@ enum class DataType {
|
||||
in WordDatatypes -> other in WordDatatypes
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun memorySize(): Int {
|
||||
return when(this) {
|
||||
in ByteDatatypes -> 1
|
||||
in WordDatatypes -> 2
|
||||
FLOAT -> MachineDefinition.Mflpt5.MemorySize
|
||||
in PassByReferenceDatatypes -> 2
|
||||
else -> -9999999
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Register {
|
||||
|
@ -133,7 +133,7 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
subroutine.parameters
|
||||
.filter { it.name !in namesInSub }
|
||||
.forEach {
|
||||
val vardecl = VarDecl(VarDeclType.VAR, it.type, ZeropageWish.DONTCARE, null, it.name, null, null,
|
||||
val vardecl = VarDecl(VarDeclType.VAR, it.type, ZeropageWish.NOT_IN_ZEROPAGE, null, it.name, null, null,
|
||||
isArray = false, autogeneratedDontRemove = true, position = subroutine.position)
|
||||
vardecl.linkParents(subroutine)
|
||||
subroutine.statements.add(0, vardecl)
|
||||
|
@ -64,7 +64,7 @@ fun compileProgram(filepath: Path,
|
||||
programAst.removeNopsFlattenAnonScopes()
|
||||
|
||||
// if you want to print the AST, do it before shuffling the statements around below
|
||||
//printAst(programAst)
|
||||
printAst(programAst)
|
||||
|
||||
|
||||
programAst.reorderStatements() // reorder statements and add type casts, to please the compiler later
|
||||
|
@ -459,8 +459,8 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
|
||||
Opcode.CAST_B_TO_F -> " jsr c64flt.stack_b2float"
|
||||
Opcode.CAST_UW_TO_F -> " jsr c64flt.stack_uw2float"
|
||||
Opcode.CAST_W_TO_F -> " jsr c64flt.stack_w2float"
|
||||
Opcode.CAST_F_TO_UB -> " jsr c64flt.stack_float2uw"
|
||||
Opcode.CAST_F_TO_B -> " jsr c64flt.stack_float2w"
|
||||
Opcode.CAST_F_TO_UB -> " jsr c64flt.stack_float2ub"
|
||||
Opcode.CAST_F_TO_B -> " jsr c64flt.stack_float2b"
|
||||
Opcode.CAST_F_TO_UW -> " jsr c64flt.stack_float2uw"
|
||||
Opcode.CAST_F_TO_W -> " jsr c64flt.stack_float2w"
|
||||
Opcode.CAST_UB_TO_UW, Opcode.CAST_UB_TO_W -> " lda #0 | sta $ESTACK_HI_PLUS1_HEX,x" // clear the msb
|
||||
|
@ -1,6 +1,9 @@
|
||||
package prog8.compiler.target.c64.codegen2
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.antlr.escape
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.base.initvarsSubName
|
||||
import prog8.ast.expressions.*
|
||||
@ -8,9 +11,16 @@ import prog8.ast.statements.*
|
||||
import prog8.compiler.*
|
||||
import prog8.compiler.target.c64.AssemblyProgram
|
||||
import prog8.compiler.target.c64.MachineDefinition
|
||||
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
|
||||
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
|
||||
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX
|
||||
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import prog8.compiler.target.c64.codegen.optimizeAssembly
|
||||
import prog8.functions.BuiltinFunctions
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
internal class AssemblyError(msg: String) : RuntimeException(msg)
|
||||
@ -24,6 +34,7 @@ internal class AsmGen2(val program: Program,
|
||||
private val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
|
||||
private val allocatedZeropageVariables = mutableMapOf<String, Pair<Int, DataType>>()
|
||||
private val breakpointLabels = mutableListOf<String>()
|
||||
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, options, zeropage, this)
|
||||
|
||||
internal fun compileToAssembly(optimize: Boolean): AssemblyProgram {
|
||||
assemblyLines.clear()
|
||||
@ -123,8 +134,10 @@ internal class AsmGen2(val program: Program,
|
||||
// the global list of all floating point constants for the whole program
|
||||
out("; global float constants")
|
||||
for (flt in globalFloatConsts) {
|
||||
val floatFill = makeFloatFill(MachineDefinition.Mflpt5.fromNumber(flt.key))
|
||||
out("${flt.value}\t.byte $floatFill ; float ${flt.key}")
|
||||
val mflpt5 = MachineDefinition.Mflpt5.fromNumber(flt.key)
|
||||
val floatFill = makeFloatFill(mflpt5)
|
||||
val floatvalue = flt.key
|
||||
out("${flt.value}\t.byte $floatFill ; float $floatvalue")
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,10 +149,11 @@ internal class AsmGen2(val program: Program,
|
||||
out("* = ${block.address.toHex()}")
|
||||
}
|
||||
|
||||
outputSourceLine(block)
|
||||
zeropagevars2asm(block.statements)
|
||||
memdefs2asm(block.statements)
|
||||
vardecls2asm(block.statements)
|
||||
out("")
|
||||
out("\n; subroutines in this block")
|
||||
|
||||
// first translate regular statements, and then put the subroutines at the end.
|
||||
val (subroutine, stmts) = block.statements.partition { it is Subroutine }
|
||||
@ -149,14 +163,20 @@ internal class AsmGen2(val program: Program,
|
||||
out("\n\t.pend\n") // TODO not if force_output?
|
||||
}
|
||||
|
||||
private fun out(str: String, splitlines: Boolean = true) {
|
||||
private fun outputSourceLine(node: Node) {
|
||||
out(" ;\tsrc line: ${node.position.file}:${node.position.line}")
|
||||
}
|
||||
|
||||
internal fun out(str: String, splitlines: Boolean = true) {
|
||||
val fragment = (if(" | " in str) str.replace("|", "\n") else str).trim('\n')
|
||||
|
||||
if (splitlines) {
|
||||
for (line in str.split('\n')) {
|
||||
for (line in fragment.split('\n')) {
|
||||
val trimmed = if (line.startsWith(' ')) "\t" + line.trim() else line.trim()
|
||||
// trimmed = trimmed.replace(Regex("^\\+\\s+"), "+\t") // sanitize local label indentation
|
||||
assemblyLines.add(trimmed)
|
||||
}
|
||||
} else assemblyLines.add(str)
|
||||
} else assemblyLines.add(fragment)
|
||||
}
|
||||
|
||||
private fun makeFloatFill(flt: MachineDefinition.Mflpt5): String {
|
||||
@ -168,10 +188,25 @@ internal class AsmGen2(val program: Program,
|
||||
return "$b0, $b1, $b2, $b3, $b4"
|
||||
}
|
||||
|
||||
private fun encodeStr(str: String, dt: DataType): List<Short> {
|
||||
return when(dt) {
|
||||
DataType.STR -> {
|
||||
val bytes = Petscii.encodePetscii(str, true)
|
||||
bytes.plus(0)
|
||||
}
|
||||
DataType.STR_S -> {
|
||||
val bytes = Petscii.encodeScreencode(str, true)
|
||||
bytes.plus(0)
|
||||
}
|
||||
else -> throw prog8.compiler.target.c64.codegen.AssemblyError("invalid str type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun zeropagevars2asm(statements: List<Statement>) {
|
||||
out("; vars allocated on zeropage")
|
||||
val variables = statements.filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR }
|
||||
for(variable in variables) {
|
||||
// should NOT allocate subroutine parameters on the zero page
|
||||
val fullName = variable.scopedname
|
||||
val zpVar = allocatedZeropageVariables[fullName]
|
||||
if(zpVar==null) {
|
||||
@ -205,10 +240,14 @@ internal class AsmGen2(val program: Program,
|
||||
DataType.WORD -> out("${decl.name}\t.sint 0")
|
||||
DataType.FLOAT -> out("${decl.name}\t.byte 0,0,0,0,0 ; float")
|
||||
DataType.STRUCT -> {} // is flattened
|
||||
DataType.STR -> TODO()
|
||||
DataType.STR_S -> TODO()
|
||||
DataType.STR, DataType.STR_S -> {
|
||||
val string = (decl.value as ReferenceLiteralValue).str!!
|
||||
val bytes = encodeStr(string, decl.datatype).map { "$" + it.toString(16).padStart(2, '0') }
|
||||
out("${decl.name}\t; ${decl.datatype} \"${escape(string).replace("\u0000", "<NULL>")}\"")
|
||||
for (chunk in bytes.chunked(16))
|
||||
out(" .byte " + chunk.joinToString())
|
||||
}
|
||||
DataType.ARRAY_UB -> {
|
||||
// unsigned integer byte arraysize
|
||||
val data = makeArrayFillDataUnsigned(decl)
|
||||
if (data.size <= 16)
|
||||
out("${decl.name}\t.byte ${data.joinToString()}")
|
||||
@ -218,10 +257,46 @@ internal class AsmGen2(val program: Program,
|
||||
out(" .byte " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_B -> TODO()
|
||||
DataType.ARRAY_UW -> TODO()
|
||||
DataType.ARRAY_W -> TODO()
|
||||
DataType.ARRAY_F -> TODO()
|
||||
DataType.ARRAY_B -> {
|
||||
val data = makeArrayFillDataSigned(decl)
|
||||
if (data.size <= 16)
|
||||
out("${decl.name}\t.char ${data.joinToString()}")
|
||||
else {
|
||||
out(decl.name)
|
||||
for (chunk in data.chunked(16))
|
||||
out(" .char " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
val data = makeArrayFillDataUnsigned(decl)
|
||||
if (data.size <= 16)
|
||||
out("${decl.name}\t.word ${data.joinToString()}")
|
||||
else {
|
||||
out(decl.name)
|
||||
for (chunk in data.chunked(16))
|
||||
out(" .word " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
val data = makeArrayFillDataSigned(decl)
|
||||
if (data.size <= 16)
|
||||
out("${decl.name}\t.sint ${data.joinToString()}")
|
||||
else {
|
||||
out(decl.name)
|
||||
for (chunk in data.chunked(16))
|
||||
out(" .sint " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
val array = (decl.value as ReferenceLiteralValue).array!!
|
||||
val floatFills = array.map {
|
||||
val number = (it as NumericLiteralValue).number
|
||||
makeFloatFill(MachineDefinition.Mflpt5.fromNumber(number))
|
||||
}
|
||||
out(decl.name)
|
||||
for (f in array.zip(floatFills))
|
||||
out(" .byte ${f.second} ; float ${f.first}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +334,45 @@ internal class AsmGen2(val program: Program,
|
||||
|
||||
private fun makeArrayFillDataUnsigned(decl: VarDecl): List<String> {
|
||||
val array = (decl.value as ReferenceLiteralValue).array!!
|
||||
return array.map { (it as NumericLiteralValue).number.toString() }
|
||||
return when {
|
||||
decl.datatype == DataType.ARRAY_UB ->
|
||||
// byte array can never contain pointer-to types, so treat values as all integers
|
||||
array.map {
|
||||
val number = (it as NumericLiteralValue).number.toInt()
|
||||
"$"+number.toString(16).padStart(2, '0')
|
||||
}
|
||||
decl.datatype== DataType.ARRAY_UW -> array.map {
|
||||
val number = (it as NumericLiteralValue).number.toInt()
|
||||
// TODO word array with address-references
|
||||
"$"+number.toString(16).padStart(4, '0')
|
||||
}
|
||||
else -> throw AssemblyError("invalid arraysize type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeArrayFillDataSigned(decl: VarDecl): List<String> {
|
||||
val array = (decl.value as ReferenceLiteralValue).array!!
|
||||
return when {
|
||||
decl.datatype == DataType.ARRAY_UB ->
|
||||
// byte array can never contain pointer-to types, so treat values as all integers
|
||||
array.map {
|
||||
val number = (it as NumericLiteralValue).number.toInt()
|
||||
val hexnum = number.absoluteValue.toString(16).padStart(2, '0')
|
||||
if(number>=0)
|
||||
"$$hexnum"
|
||||
else
|
||||
"-$$hexnum"
|
||||
}
|
||||
decl.datatype== DataType.ARRAY_UW -> array.map {
|
||||
val number = (it as NumericLiteralValue).number.toInt()
|
||||
val hexnum = number.absoluteValue.toString(16).padStart(4, '0')
|
||||
if(number>=0)
|
||||
"$$hexnum"
|
||||
else
|
||||
"-$$hexnum"
|
||||
}
|
||||
else -> throw AssemblyError("invalid arraysize type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFloatConst(number: Double): String {
|
||||
@ -271,6 +384,14 @@ internal class AsmGen2(val program: Program,
|
||||
return newName
|
||||
}
|
||||
|
||||
private fun signExtendAtoMsb(destination: String) =
|
||||
"""
|
||||
ora #$7f
|
||||
bmi +
|
||||
lda #0
|
||||
+ sta $destination
|
||||
"""
|
||||
|
||||
private fun asmIdentifierName(identifier: IdentifierReference): String {
|
||||
val name = if(identifier.memberOfStruct(program.namespace)!=null) {
|
||||
identifier.targetVarDecl(program.namespace)!!.name
|
||||
@ -308,13 +429,28 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun translate(stmt: Statement) {
|
||||
outputSourceLine(stmt)
|
||||
when(stmt) {
|
||||
is VarDecl, is StructDecl, is NopStatement -> {}
|
||||
is Directive -> translate(stmt)
|
||||
is Return -> translate(stmt)
|
||||
is Subroutine -> translate(stmt)
|
||||
is InlineAssembly -> translate(stmt)
|
||||
is FunctionCallStatement -> translate(stmt)
|
||||
is FunctionCallStatement -> {
|
||||
val functionName = stmt.target.nameInSource.last()
|
||||
val builtinFunc = BuiltinFunctions[functionName]
|
||||
if(builtinFunc!=null) {
|
||||
builtinFunctionsAsmGen.translateFunctioncallStatement(stmt, builtinFunc)
|
||||
} else {
|
||||
translateSubroutineCall(stmt)
|
||||
// discard any results from the stack:
|
||||
val returns = stmt.target.targetSubroutine(program.namespace)!!.returntypes
|
||||
for(t in returns) {
|
||||
if (t in IntegerDatatypes || t in PassByReferenceDatatypes) out(" inx")
|
||||
else if (t == DataType.FLOAT) out(" inx | inx | inx")
|
||||
}
|
||||
}
|
||||
}
|
||||
is Assignment -> translate(stmt)
|
||||
is Jump -> translate(stmt)
|
||||
is PostIncrDecr -> translate(stmt)
|
||||
@ -333,6 +469,80 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateSubroutineCall(stmt: IFunctionCall) {
|
||||
val subName = stmt.target.nameInSource.joinToString(".")
|
||||
if(stmt.arglist.isNotEmpty()) {
|
||||
val sub = stmt.target.targetSubroutine(program.namespace)!!
|
||||
for(arg in sub.parameters.withIndex().zip(stmt.arglist)) {
|
||||
if(arg.first.value.type!=arg.second.inferType(program))
|
||||
throw AssemblyError("argument type mismatch")
|
||||
if(sub.asmParameterRegisters.isEmpty()) {
|
||||
// pass arg via a variable
|
||||
val paramVar = arg.first.value
|
||||
val scopedParamVar = (sub.scopedname+"."+paramVar.name).split(".")
|
||||
val target = AssignTarget(null, IdentifierReference(scopedParamVar, sub.position), null, null, sub.position)
|
||||
target.linkParents(stmt as Node)
|
||||
val literal = arg.second as? NumericLiteralValue
|
||||
when {
|
||||
literal!=null -> {
|
||||
// optimize when the argument is a constant literal
|
||||
when(arg.first.value.type) {
|
||||
in ByteDatatypes -> assignByteConstant(target, literal.number.toShort())
|
||||
in WordDatatypes -> assignWordConstant(target, literal.number.toInt())
|
||||
DataType.FLOAT -> assignFloatConstant(target, literal.number.toDouble())
|
||||
in PassByReferenceDatatypes-> TODO( "str/array/struct sub arg")
|
||||
else -> throw AssemblyError("weird arg datatype")
|
||||
}
|
||||
}
|
||||
arg.second is IdentifierReference -> {
|
||||
// optimize when the argument is a variable
|
||||
when (arg.first.value.type) {
|
||||
in ByteDatatypes -> assignByteVariable(target, arg.second as IdentifierReference)
|
||||
in WordDatatypes -> assignWordVariable(target, arg.second as IdentifierReference)
|
||||
DataType.FLOAT -> assignFloatVariable(target, arg.second as IdentifierReference)
|
||||
in PassByReferenceDatatypes -> TODO("str/array/struct sub arg")
|
||||
else -> throw AssemblyError("weird arg datatype")
|
||||
}
|
||||
}
|
||||
else -> TODO("non-constant sub arg $arg")
|
||||
}
|
||||
} else {
|
||||
// pass arg via a register parameter
|
||||
val paramRegister = sub.asmParameterRegisters[arg.first.index]
|
||||
val statusflag = paramRegister.statusflag
|
||||
val register = paramRegister.registerOrPair
|
||||
val stack = paramRegister.stack
|
||||
when {
|
||||
stack==true -> TODO("stack param")
|
||||
statusflag!=null -> {
|
||||
if (statusflag == Statusflag.Pc) TODO("carry flag param")
|
||||
else throw AssemblyError("can only use Carry as status flag parameter")
|
||||
}
|
||||
register!=null -> {
|
||||
val target = AssignTarget(Register.valueOf(register.name), null, null, null, sub.position)
|
||||
target.linkParents(stmt as Node)
|
||||
val literal = arg.second as? NumericLiteralValue
|
||||
if(literal!=null) {
|
||||
// optimize when the argument is a constant literal
|
||||
when(register) {
|
||||
RegisterOrPair.A,
|
||||
RegisterOrPair.X,
|
||||
RegisterOrPair.Y -> assignByteConstant(target, literal.number.toShort())
|
||||
RegisterOrPair.AX -> TODO("register A+X param $literal")
|
||||
RegisterOrPair.AY -> TODO("register A+Y param $literal")
|
||||
RegisterOrPair.XY -> TODO("register X+Y param $literal")
|
||||
}
|
||||
} else {
|
||||
TODO("register param")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out(" jsr $subName")
|
||||
}
|
||||
|
||||
private fun translate(stmt: Label) {
|
||||
out("${stmt.name}")
|
||||
}
|
||||
@ -347,7 +557,7 @@ internal class AsmGen2(val program: Program,
|
||||
val instruction = branchInstruction(stmt.condition, false)
|
||||
out(" $instruction ${getJumpTarget(jump)}")
|
||||
} else {
|
||||
TODO("$stmt")
|
||||
TODO("branch $stmt")
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,26 +586,50 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun translate(stmt: ForLoop) {
|
||||
out("; for $stmt")
|
||||
out("; TODO for $stmt") // TODO
|
||||
}
|
||||
|
||||
private fun translate(stmt: PostIncrDecr) {
|
||||
val incr = stmt.operator=="++"
|
||||
when {
|
||||
stmt.target.register!=null -> {
|
||||
when(stmt.target.register!!) {
|
||||
Register.A -> out("""
|
||||
clc
|
||||
adc #1
|
||||
""")
|
||||
Register.X -> out(" inx")
|
||||
Register.Y -> out(" iny")
|
||||
Register.A -> {
|
||||
if(incr)
|
||||
out(" clc | adc #1 ")
|
||||
else
|
||||
out(" sec | sbc #1 ")
|
||||
}
|
||||
Register.X -> {
|
||||
if(incr) out(" inx") else out(" dex")
|
||||
}
|
||||
Register.Y -> {
|
||||
if(incr) out(" iny") else out(" dey")
|
||||
}
|
||||
}
|
||||
}
|
||||
stmt.target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(stmt.target.identifier!!)
|
||||
out(" inc $targetName")
|
||||
val what = asmIdentifierName(stmt.target.identifier!!)
|
||||
out(if(incr) " inc $what" else " dec $what")
|
||||
}
|
||||
else -> TODO("postincrdecr $stmt")
|
||||
stmt.target.memoryAddress!=null -> {
|
||||
val target = stmt.target.memoryAddress!!.addressExpression
|
||||
when (target) {
|
||||
is NumericLiteralValue -> {
|
||||
val what = target.number.toHex()
|
||||
out(if(incr) " inc $what" else " dec $what")
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
val what = target.nameInSource.joinToString(".")
|
||||
out(if(incr) " inc $what" else " dec $what")
|
||||
}
|
||||
else -> throw AssemblyError("weird target type $target")
|
||||
}
|
||||
}
|
||||
stmt.target.arrayindexed!=null -> {
|
||||
TODO("postincrdecr array element ${stmt.target.arrayindexed}")
|
||||
}
|
||||
else -> throw AssemblyError("weird target type ${stmt.target}")
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,13 +647,14 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun translate(ret: Return) {
|
||||
if(ret.value!=null) {
|
||||
TODO("$ret value")
|
||||
}
|
||||
ret.value?.let { translateExpression(it) }
|
||||
out(" rts")
|
||||
}
|
||||
|
||||
private fun translate(sub: Subroutine) {
|
||||
out("")
|
||||
outputSourceLine(sub)
|
||||
|
||||
if(sub.isAsmSubroutine) {
|
||||
if(sub.asmAddress!=null)
|
||||
return // already done at the memvars section
|
||||
@ -433,7 +668,9 @@ internal class AsmGen2(val program: Program,
|
||||
out("${sub.name}\t.proc")
|
||||
zeropagevars2asm(sub.statements)
|
||||
memdefs2asm(sub.statements)
|
||||
out("; statements")
|
||||
sub.statements.forEach{ translate(it) }
|
||||
out("; variables")
|
||||
vardecls2asm(sub.statements)
|
||||
out(" .pend\n")
|
||||
}
|
||||
@ -444,14 +681,6 @@ internal class AsmGen2(val program: Program,
|
||||
assemblyLines.add(assembly)
|
||||
}
|
||||
|
||||
private fun translate(call: FunctionCallStatement) {
|
||||
if(call.arglist.isEmpty()) {
|
||||
out(" jsr ${call.target.nameInSource.joinToString(".")}")
|
||||
} else {
|
||||
TODO("call $call")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translate(assign: Assignment) {
|
||||
if(assign.aug_op!=null)
|
||||
throw AssemblyError("aug-op assignments should have been transformed to normal ones")
|
||||
@ -460,7 +689,7 @@ internal class AsmGen2(val program: Program,
|
||||
is NumericLiteralValue -> {
|
||||
val numVal = assign.value as NumericLiteralValue
|
||||
when(numVal.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> assignByteConstant(assign.target, numVal.number.toInt())
|
||||
DataType.UBYTE, DataType.BYTE -> assignByteConstant(assign.target, numVal.number.toShort())
|
||||
DataType.UWORD, DataType.WORD -> assignWordConstant(assign.target, numVal.number.toInt())
|
||||
DataType.FLOAT -> assignFloatConstant(assign.target, numVal.number.toDouble())
|
||||
DataType.STR -> TODO()
|
||||
@ -481,7 +710,7 @@ internal class AsmGen2(val program: Program,
|
||||
when(type) {
|
||||
DataType.UBYTE, DataType.BYTE -> assignByteVariable(assign.target, assign.value as IdentifierReference)
|
||||
DataType.UWORD, DataType.WORD -> assignWordVariable(assign.target, assign.value as IdentifierReference)
|
||||
DataType.FLOAT -> TODO()
|
||||
DataType.FLOAT -> assignFloatVariable(assign.target, assign.value as IdentifierReference)
|
||||
DataType.STR -> TODO()
|
||||
DataType.STR_S -> TODO()
|
||||
DataType.ARRAY_UB -> TODO()
|
||||
@ -509,7 +738,7 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
else -> {
|
||||
translateExpression(read.addressExpression)
|
||||
out("; read memory byte from result and put that in ${assign.target}") // TODO
|
||||
out("; TODO read memory byte from result and put that in ${assign.target}") // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -550,19 +779,65 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: ArrayIndexedExpression) {
|
||||
out("; evaluate arrayindexed ${expr}")
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: FunctionCall) {
|
||||
out("; evaluate funccall ${expr}")
|
||||
out("; TODO evaluate arrayindexed ${expr}") // TODO
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: TypecastExpression) {
|
||||
translateExpression(expr.expression)
|
||||
out("; typecast to ${expr.type}")
|
||||
when(expr.expression.inferType(program)!!) {
|
||||
DataType.UBYTE -> {
|
||||
when(expr.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> {}
|
||||
DataType.UWORD, DataType.WORD -> out(" lda #0 | sta $ESTACK_HI_PLUS1_HEX,x")
|
||||
DataType.FLOAT -> out(" jsr c64flt.stack_ub2float")
|
||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
when(expr.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> {}
|
||||
DataType.UWORD, DataType.WORD -> out(" lda $ESTACK_HI_PLUS1_HEX,x | ${signExtendAtoMsb("$ESTACK_HI_PLUS1_HEX,x")}")
|
||||
DataType.FLOAT -> out(" jsr c64flt.stack_b2float")
|
||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
when(expr.type) {
|
||||
DataType.BYTE, DataType.UBYTE -> {}
|
||||
DataType.WORD, DataType.UWORD -> {}
|
||||
DataType.FLOAT -> out(" jsr c64flt.stack_uw2float")
|
||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
DataType.WORD -> {
|
||||
when(expr.type) {
|
||||
DataType.BYTE, DataType.UBYTE -> {}
|
||||
DataType.WORD, DataType.UWORD -> {}
|
||||
DataType.FLOAT -> out(" jsr c64flt.stack_w2float")
|
||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
when(expr.type) {
|
||||
DataType.UBYTE -> out(" jsr c64flt.stack_float2uw")
|
||||
DataType.BYTE -> out(" jsr c64flt.stack_float2w")
|
||||
DataType.UWORD -> out(" jsr c64flt.stack_float2uw")
|
||||
DataType.WORD -> out(" jsr c64flt.stack_float2w")
|
||||
DataType.FLOAT -> {}
|
||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot case a pass-by-reference datatypes into something else")
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateExpression(expression: Expression) {
|
||||
internal fun translateExpression(expression: Expression) {
|
||||
when(expression) {
|
||||
is PrefixExpression -> translateExpression(expression)
|
||||
is BinaryExpression -> translateExpression(expression)
|
||||
@ -573,7 +848,15 @@ internal class AsmGen2(val program: Program,
|
||||
is NumericLiteralValue -> translateExpression(expression)
|
||||
is RegisterExpr -> translateExpression(expression)
|
||||
is IdentifierReference -> translateExpression(expression)
|
||||
is FunctionCall -> translateExpression(expression)
|
||||
is FunctionCall -> {
|
||||
val functionName = expression.target.nameInSource.last()
|
||||
val builtinFunc = BuiltinFunctions[functionName]
|
||||
if(builtinFunc!=null) {
|
||||
builtinFunctionsAsmGen.translateFunctioncallExpression(expression, builtinFunc)
|
||||
} else {
|
||||
translateSubroutineCall(expression)
|
||||
}
|
||||
}
|
||||
is ReferenceLiteralValue -> TODO("string/array/struct assignment?")
|
||||
is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened")
|
||||
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values")
|
||||
@ -581,38 +864,105 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: AddressOf) {
|
||||
out("; take address of ${expr}")
|
||||
out("; TODO take address of ${expr}") // TODO
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: DirectMemoryRead) {
|
||||
out("; memread ${expr}")
|
||||
out("; TODO memread ${expr}") // TODO
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: NumericLiteralValue) {
|
||||
out("; literalvalue ${expr}")
|
||||
when(expr.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> out(" lda #${expr.number.toHex()} | sta $ESTACK_LO_HEX,x | dex")
|
||||
DataType.UWORD, DataType.WORD -> out("""
|
||||
lda #<${expr.number.toHex()}
|
||||
sta $ESTACK_LO_HEX,x
|
||||
lda #>${expr.number.toHex()}
|
||||
sta $ESTACK_HI_HEX,x
|
||||
dex
|
||||
""")
|
||||
DataType.FLOAT -> {
|
||||
val floatConst = getFloatConst(expr.number.toDouble())
|
||||
out(" lda #<$floatConst | ldy #>$floatConst | jsr c64flt.push_float")
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: RegisterExpr) {
|
||||
out("; register value ${expr}")
|
||||
when(expr.register) {
|
||||
Register.A -> out(" sta $ESTACK_LO_HEX,x | dex")
|
||||
Register.X -> throw AssemblyError("cannot push X")
|
||||
Register.Y -> out(" tya | sta $ESTACK_LO_HEX,x | dex")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: IdentifierReference) {
|
||||
out("; identifier value ${expr}")
|
||||
val varname = expr.nameInSource.joinToString(".")
|
||||
when(expr.inferType(program)!!) {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
out(" lda $varname | sta $ESTACK_LO_HEX,x | dex")
|
||||
}
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
out(" lda $varname | sta $ESTACK_LO_HEX,x | lda $varname+1 | sta $ESTACK_HI_HEX,x | dex")
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
out(" lda #<$varname | ldy #>$varname| jsr c64flt.push_float")
|
||||
}
|
||||
else -> throw AssemblyError("stack push weird variable type $expr")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: BinaryExpression) {
|
||||
translateExpression(expr.left)
|
||||
translateExpression(expr.right)
|
||||
out("; evaluate binary ${expr.operator}")
|
||||
out("; TODO evaluate binary ${expr.operator}") // TODO
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: PrefixExpression) {
|
||||
translateExpression(expr.expression)
|
||||
out("; evaluate prefix ${expr.operator}")
|
||||
out("; TODO evaluate prefix ${expr.operator}") // TODO
|
||||
}
|
||||
|
||||
private fun assignEvalResult(target: AssignTarget) {
|
||||
out("; put result in $target")
|
||||
when {
|
||||
target.register!=null -> {
|
||||
out(" inx | ld${target.register.name.toLowerCase()} $ESTACK_LO_HEX,x ")
|
||||
}
|
||||
target.identifier!=null -> {
|
||||
val targetName = target.identifier.nameInSource.joinToString(".")
|
||||
val targetDt = target.identifier.inferType(program)!!
|
||||
when(targetDt) {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
out(" inx | lda $ESTACK_LO_HEX,x | sta $targetName")
|
||||
}
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
out("""
|
||||
inx
|
||||
lda $ESTACK_LO_HEX,x
|
||||
sta $targetName
|
||||
lda $ESTACK_HI_HEX,x
|
||||
sta $targetName+1
|
||||
""")
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
out("""
|
||||
lda #<$targetName
|
||||
ldy #>$targetName
|
||||
jsr c64flt.pop_float
|
||||
""")
|
||||
}
|
||||
else -> throw AssemblyError("weird target variable type $targetDt")
|
||||
}
|
||||
}
|
||||
target.memoryAddress!=null -> {
|
||||
out("; TODO put result in $target") // TODO
|
||||
}
|
||||
target.arrayindexed!=null -> {
|
||||
out("; TODO put result in $target") // TODO
|
||||
}
|
||||
else -> throw AssemblyError("weird assignment target $target")
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignAddressOf(target: AssignTarget, name: IdentifierReference, scopedname: String) {
|
||||
@ -664,6 +1014,28 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignFloatVariable(target: AssignTarget, variable: IdentifierReference) {
|
||||
val sourceName = variable.nameInSource.joinToString(".")
|
||||
when {
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
out("""
|
||||
lda $sourceName
|
||||
sta $targetName
|
||||
lda $sourceName+1
|
||||
sta $targetName+1
|
||||
lda $sourceName+2
|
||||
sta $targetName+2
|
||||
lda $sourceName+3
|
||||
sta $targetName+3
|
||||
lda $sourceName+4
|
||||
sta $targetName+4
|
||||
""")
|
||||
}
|
||||
else -> TODO("assign float to $target")
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignByteVariable(target: AssignTarget, variable: IdentifierReference) {
|
||||
val sourceName = variable.nameInSource.joinToString(".")
|
||||
when {
|
||||
@ -706,38 +1078,43 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> out("; assign register $register to $target")
|
||||
else -> out("; TODO assign register $register to $target") // TODO
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignWordConstant(target: AssignTarget, word: Int) {
|
||||
if(target.identifier!=null) {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
// TODO optimize case where lsb = msb
|
||||
out("""
|
||||
lda #<${word.toHex()}
|
||||
ldy #>${word.toHex()}
|
||||
sta $targetName
|
||||
sty $targetName+1
|
||||
""")
|
||||
if(word ushr 8 == word and 255) {
|
||||
// lsb=msb
|
||||
out("""
|
||||
lda #${(word and 255).toHex()}
|
||||
sta $targetName
|
||||
sta $targetName+1
|
||||
""")
|
||||
} else {
|
||||
out("""
|
||||
lda #<${word.toHex()}
|
||||
ldy #>${word.toHex()}
|
||||
sta $targetName
|
||||
sty $targetName+1
|
||||
""")
|
||||
}
|
||||
} else {
|
||||
out("; assign byte $word to $target")
|
||||
out("; TODO assign byte $word to $target") // TODO
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignByteConstant(target: AssignTarget, byte: Int) {
|
||||
private fun assignByteConstant(target: AssignTarget, byte: Short) {
|
||||
when {
|
||||
target.register!=null -> {
|
||||
out(" ld${target.register.name.toLowerCase()} #${byte.toHex()}")
|
||||
}
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
out("""
|
||||
lda #${byte.toHex()}
|
||||
sta $targetName
|
||||
""")
|
||||
out(" lda #${byte.toHex()} | sta $targetName ")
|
||||
}
|
||||
else -> out("; assign byte $byte to $target")
|
||||
else -> out("; TODO assign byte $byte to $target") // TODO
|
||||
}
|
||||
}
|
||||
|
||||
@ -755,7 +1132,7 @@ internal class AsmGen2(val program: Program,
|
||||
sta $targetName+4
|
||||
""")
|
||||
} else {
|
||||
out("; assign float 0.0 to $target")
|
||||
out("; TODO assign float 0.0 to $target") // TODO
|
||||
}
|
||||
} else {
|
||||
// non-zero value
|
||||
@ -775,7 +1152,7 @@ internal class AsmGen2(val program: Program,
|
||||
sta $targetName+4
|
||||
""")
|
||||
} else {
|
||||
out("; assign float $float ($constFloat) to $target")
|
||||
out("; TODO assign float $float ($constFloat) to $target") // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -793,7 +1170,7 @@ internal class AsmGen2(val program: Program,
|
||||
sta $targetName
|
||||
""")
|
||||
}
|
||||
else -> TODO()
|
||||
else -> TODO("assign memory byte $target")
|
||||
}
|
||||
}
|
||||
else if(identifier!=null) {
|
||||
@ -818,7 +1195,7 @@ internal class AsmGen2(val program: Program,
|
||||
sta $targetName
|
||||
""")
|
||||
}
|
||||
else -> TODO()
|
||||
else -> TODO("assign memory byte $target")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package prog8.compiler.target.c64.codegen2
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.WordDatatypes
|
||||
import prog8.ast.expressions.FunctionCall
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import prog8.ast.statements.FunctionCallStatement
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.compiler.target.c64.MachineDefinition
|
||||
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
|
||||
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
|
||||
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX
|
||||
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.Zeropage
|
||||
import prog8.functions.BuiltinFunctions
|
||||
import prog8.functions.FunctionSignature
|
||||
|
||||
internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
private val options: CompilationOptions,
|
||||
private val zeropage: Zeropage,
|
||||
private val asmgen: AsmGen2) {
|
||||
|
||||
internal fun translateFunctioncallExpression(fcall: FunctionCall, func: FunctionSignature) {
|
||||
translateFunctioncall(fcall, func, false)
|
||||
}
|
||||
|
||||
internal fun translateFunctioncallStatement(fcall: FunctionCallStatement, func: FunctionSignature) {
|
||||
translateFunctioncall(fcall, func, true)
|
||||
}
|
||||
|
||||
private fun translateFunctioncall(fcall: IFunctionCall, func: FunctionSignature, discardResult: Boolean) {
|
||||
val functionName = fcall.target.nameInSource.last()
|
||||
if(discardResult) {
|
||||
if(func.pure)
|
||||
return // can just ignore the whole function call altogether
|
||||
else
|
||||
throw AssemblyError("discarding result of non-pure function $fcall")
|
||||
}
|
||||
|
||||
when(functionName) {
|
||||
"msb" -> {
|
||||
val arg = fcall.arglist.single()
|
||||
if(arg.inferType(program) !in WordDatatypes)
|
||||
throw AssemblyError("msb required word argument")
|
||||
if(arg is NumericLiteralValue)
|
||||
throw AssemblyError("should have been const-folded")
|
||||
if(arg is IdentifierReference) {
|
||||
val sourceName = arg.nameInSource.joinToString(".")
|
||||
asmgen.out(" lda $sourceName+1 | sta $ESTACK_LO_HEX,x | dex")
|
||||
} else {
|
||||
asmgen.translateExpression(arg)
|
||||
asmgen.out(" lda $ESTACK_HI_PLUS1_HEX,x | sta $ESTACK_LO_PLUS1_HEX,x")
|
||||
}
|
||||
}
|
||||
"mkword" -> {
|
||||
asmgen.translateExpression(fcall.arglist[0])
|
||||
asmgen.translateExpression(fcall.arglist[1])
|
||||
asmgen.out(" inx | lda $ESTACK_LO_HEX,x | sta $ESTACK_HI_PLUS1_HEX,x")
|
||||
}
|
||||
else -> TODO("builtin function $functionName")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -379,10 +379,10 @@ internal class StatementOptimizer(private val program: Program, private val opti
|
||||
printWarning("condition is always true", whileLoop.position)
|
||||
if(hasContinueOrBreak(whileLoop.body))
|
||||
return whileLoop
|
||||
val label = Label("__back", whileLoop.condition.position)
|
||||
val label = Label("_prog8_back", whileLoop.condition.position)
|
||||
whileLoop.body.statements.add(0, label)
|
||||
whileLoop.body.statements.add(Jump(null,
|
||||
IdentifierReference(listOf("__back"), whileLoop.condition.position),
|
||||
IdentifierReference(listOf("_prog8_back"), whileLoop.condition.position),
|
||||
null, whileLoop.condition.position))
|
||||
optimizationsDone++
|
||||
return whileLoop.body
|
||||
|
74
examples/romfloats.p8
Normal file
74
examples/romfloats.p8
Normal file
@ -0,0 +1,74 @@
|
||||
%import c64flt
|
||||
%zeropage basicsafe
|
||||
%option enable_floats
|
||||
|
||||
~ main {
|
||||
|
||||
sub start() {
|
||||
|
||||
float f1
|
||||
|
||||
; these are all floating point constants defined in the ROM so no allocation required
|
||||
; TODO actually read these from ROM
|
||||
|
||||
f1 = 3.141592653589793
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = -32768.0
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.0
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.7071067811865476
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.4142135623730951
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = -0.5
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.6931471805599453
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 10.0
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.0e9
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.5
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.4426950408889634
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.5707963267948966
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 6.283185307179586
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.25
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.0
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
%import c64utils
|
||||
%import c64flt
|
||||
%zeropage basicsafe
|
||||
%option enable_floats
|
||||
@ -7,11 +6,69 @@
|
||||
|
||||
sub start() {
|
||||
|
||||
if_z goto start
|
||||
if_pos goto start
|
||||
if_cc goto start
|
||||
if_nz goto start
|
||||
float f1
|
||||
|
||||
; these are all floating point constants defined in the ROM so no allocation required
|
||||
; TODO actually read these from ROM
|
||||
|
||||
f1 = 3.141592653589793
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = -32768.0
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.0
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.7071067811865476
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.4142135623730951
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = -0.5
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.6931471805599453
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 10.0
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.0e9
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.5
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.4426950408889634
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 1.5707963267948966
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 6.283185307179586
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.25
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
f1 = 0.0
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user