mirror of
https://github.com/irmen/prog8.git
synced 2024-06-26 07:29:32 +00:00
Merge branch 'remove_evalstack'
This commit is contained in:
commit
9167ba499d
|
@ -26,8 +26,6 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||||
PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
|
PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
|
||||||
PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
|
PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
|
||||||
PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
|
PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
|
||||||
PtMemMapped("P8ESTACK_LO", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_LO, 128u, Position.DUMMY),
|
|
||||||
PtMemMapped("P8ESTACK_HI", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_HI, 128u, Position.DUMMY)
|
|
||||||
).forEach {
|
).forEach {
|
||||||
it.parent = program
|
it.parent = program
|
||||||
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))
|
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))
|
||||||
|
|
|
@ -126,7 +126,6 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||||
else
|
else
|
||||||
"->"
|
"->"
|
||||||
}
|
}
|
||||||
else -> throw InternalCompilerException("unrecognised ast node $node")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,9 +124,7 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
|
||||||
"push" to FSignature(false, listOf(FParam("value", ByteDatatypes)), null),
|
"push" to FSignature(false, listOf(FParam("value", ByteDatatypes)), null),
|
||||||
"pushw" to FSignature(false, listOf(FParam("value", WordDatatypes)), null),
|
"pushw" to FSignature(false, listOf(FParam("value", WordDatatypes)), null),
|
||||||
"rsave" to FSignature(false, emptyList(), null),
|
"rsave" to FSignature(false, emptyList(), null),
|
||||||
"rsavex" to FSignature(false, emptyList(), null),
|
|
||||||
"rrestore" to FSignature(false, emptyList(), null),
|
"rrestore" to FSignature(false, emptyList(), null),
|
||||||
"rrestorex" to FSignature(false, emptyList(), null),
|
|
||||||
"memory" to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
|
"memory" to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
|
||||||
"callfar" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD),
|
"callfar" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD),
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,15 +13,12 @@ class CompilationOptions(val output: OutputType,
|
||||||
val compTarget: ICompilationTarget,
|
val compTarget: ICompilationTarget,
|
||||||
// these are set later, based on command line arguments or options in the source code:
|
// these are set later, based on command line arguments or options in the source code:
|
||||||
var loadAddress: UInt,
|
var loadAddress: UInt,
|
||||||
var slowCodegenWarnings: Boolean = false,
|
|
||||||
var optimize: Boolean = false,
|
var optimize: Boolean = false,
|
||||||
var optimizeFloatExpressions: Boolean = false,
|
|
||||||
var asmQuiet: Boolean = false,
|
var asmQuiet: Boolean = false,
|
||||||
var asmListfile: Boolean = false,
|
var asmListfile: Boolean = false,
|
||||||
var experimentalCodegen: Boolean = false,
|
var experimentalCodegen: Boolean = false,
|
||||||
var varsHighBank: Int? = null,
|
var varsHighBank: Int? = null,
|
||||||
var splitWordArrays: Boolean = false,
|
var splitWordArrays: Boolean = false,
|
||||||
var evalStackBaseAddress: UInt? = null,
|
|
||||||
var outputDir: Path = Path(""),
|
var outputDir: Path = Path(""),
|
||||||
var symbolDefs: Map<String, String> = emptyMap()
|
var symbolDefs: Map<String, String> = emptyMap()
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -13,8 +13,6 @@ interface IMachineDefinition {
|
||||||
val FLOAT_MAX_NEGATIVE: Double
|
val FLOAT_MAX_NEGATIVE: Double
|
||||||
val FLOAT_MAX_POSITIVE: Double
|
val FLOAT_MAX_POSITIVE: Double
|
||||||
val FLOAT_MEM_SIZE: Int
|
val FLOAT_MEM_SIZE: Int
|
||||||
var ESTACK_LO: UInt
|
|
||||||
var ESTACK_HI: UInt
|
|
||||||
val PROGRAM_LOAD_ADDRESS : UInt
|
val PROGRAM_LOAD_ADDRESS : UInt
|
||||||
val BSSHIGHRAM_START: UInt
|
val BSSHIGHRAM_START: UInt
|
||||||
val BSSHIGHRAM_END: UInt
|
val BSSHIGHRAM_END: UInt
|
||||||
|
@ -29,11 +27,4 @@ interface IMachineDefinition {
|
||||||
fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String>
|
fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String>
|
||||||
fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
|
fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
|
||||||
fun isIOAddress(address: UInt): Boolean
|
fun isIOAddress(address: UInt): Boolean
|
||||||
fun overrideEvalStack(evalStackBaseAddress: UInt) {
|
|
||||||
require(evalStackBaseAddress and 255u == 0u)
|
|
||||||
ESTACK_LO = evalStackBaseAddress
|
|
||||||
ESTACK_HI = evalStackBaseAddress + 256u
|
|
||||||
require(ESTACK_LO !in golden.region && ESTACK_HI !in golden.region) { "user-set ESTACK can't be in GOLDEN ram" }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,6 @@ class AtariMachineDefinition: IMachineDefinition {
|
||||||
override val FLOAT_MEM_SIZE = 6
|
override val FLOAT_MEM_SIZE = 6
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0x2000u
|
override val PROGRAM_LOAD_ADDRESS = 0x2000u
|
||||||
|
|
||||||
// the 2*128 byte evaluation stack (1 page, on which bytes, words, and even floats are stored during calculations)
|
|
||||||
override var ESTACK_LO = 0x1b00u // $1b00-$1b7f inclusive // TODO
|
|
||||||
override var ESTACK_HI = 0x1b80u // $1b80-$1bff inclusive // TODO
|
|
||||||
|
|
||||||
override val BSSHIGHRAM_START = 0u // TODO
|
override val BSSHIGHRAM_START = 0u // TODO
|
||||||
override val BSSHIGHRAM_END = 0u // TODO
|
override val BSSHIGHRAM_END = 0u // TODO
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,6 @@ class C128MachineDefinition: IMachineDefinition {
|
||||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0x1c01u
|
override val PROGRAM_LOAD_ADDRESS = 0x1c01u
|
||||||
|
|
||||||
// the 2*128 byte evaluation stack (1 page, on which bytes, words, and even floats are stored during calculations)
|
|
||||||
override var ESTACK_LO = 0x1b00u // $1b00-$1b7f inclusive
|
|
||||||
override var ESTACK_HI = 0x1b80u // $1b80-$1bff inclusive
|
|
||||||
|
|
||||||
override val BSSHIGHRAM_START = 0u // TODO
|
override val BSSHIGHRAM_START = 0u // TODO
|
||||||
override val BSSHIGHRAM_END = 0u // TODO
|
override val BSSHIGHRAM_END = 0u // TODO
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,8 @@ class C64MachineDefinition: IMachineDefinition {
|
||||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
||||||
|
|
||||||
// the 2*128 byte evaluation stack (1 page, on which bytes, words, and even floats are stored during calculations)
|
|
||||||
override var ESTACK_LO = 0xcf00u // $cf00-$cf7f inclusive
|
|
||||||
override var ESTACK_HI = 0xcf80u // $cf80-$cfff inclusive
|
|
||||||
|
|
||||||
override val BSSHIGHRAM_START = 0xc000u
|
override val BSSHIGHRAM_START = 0xc000u
|
||||||
override val BSSHIGHRAM_END = ESTACK_LO
|
override val BSSHIGHRAM_END = 0xd000u
|
||||||
|
|
||||||
override lateinit var zeropage: Zeropage
|
override lateinit var zeropage: Zeropage
|
||||||
override lateinit var golden: GoldenRam
|
override lateinit var golden: GoldenRam
|
||||||
|
@ -62,7 +58,7 @@ class C64MachineDefinition: IMachineDefinition {
|
||||||
|
|
||||||
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
zeropage = C64Zeropage(compilerOptions)
|
zeropage = C64Zeropage(compilerOptions)
|
||||||
golden = GoldenRam(compilerOptions, 0xc000u until ESTACK_LO)
|
golden = GoldenRam(compilerOptions, 0xc000u until 0xd000u)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,6 @@ class CX16MachineDefinition: IMachineDefinition {
|
||||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
||||||
|
|
||||||
// the 2*128 byte evaluation stack (1 page, on which bytes, words, and even floats are stored during calculations)
|
|
||||||
override var ESTACK_LO = 0x0700u // $0700-$077f inclusive
|
|
||||||
override var ESTACK_HI = 0x0780u // $0780-$07ff inclusive
|
|
||||||
|
|
||||||
override val BSSHIGHRAM_START = 0xa000u // hiram bank 1, 8Kb, assumed to be active
|
override val BSSHIGHRAM_START = 0xa000u // hiram bank 1, 8Kb, assumed to be active
|
||||||
override val BSSHIGHRAM_END = 0xc000u // rom starts here.
|
override val BSSHIGHRAM_END = 0xc000u // rom starts here.
|
||||||
|
|
||||||
|
@ -64,7 +60,7 @@ class CX16MachineDefinition: IMachineDefinition {
|
||||||
|
|
||||||
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||||
zeropage = CX16Zeropage(compilerOptions)
|
zeropage = CX16Zeropage(compilerOptions)
|
||||||
golden = GoldenRam(compilerOptions, 0x0400u until ESTACK_LO)
|
golden = GoldenRam(compilerOptions, 0x0400u until 0x0800u)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||||
ZeropageType.DONTUSE -> {
|
ZeropageType.DONTUSE -> {
|
||||||
free.clear() // don't use zeropage at all
|
free.clear() // don't use zeropage at all
|
||||||
}
|
}
|
||||||
else -> throw InternalCompilerException("for this machine target, zero page type 'floatsafe' is not available. ${options.zeropage}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val distinctFree = free.distinct()
|
val distinctFree = free.distinct()
|
||||||
|
|
|
@ -15,8 +15,6 @@ class VirtualMachineDefinition: IMachineDefinition {
|
||||||
override val FLOAT_MEM_SIZE = 4 // 32-bits floating point
|
override val FLOAT_MEM_SIZE = 4 // 32-bits floating point
|
||||||
override val PROGRAM_LOAD_ADDRESS = 0u // not actually used
|
override val PROGRAM_LOAD_ADDRESS = 0u // not actually used
|
||||||
|
|
||||||
override var ESTACK_LO = 0u // not actually used
|
|
||||||
override var ESTACK_HI = 0u // not actually used
|
|
||||||
override val BSSHIGHRAM_START = 0u // not actually used
|
override val BSSHIGHRAM_START = 0u // not actually used
|
||||||
override val BSSHIGHRAM_END = 0u // not actually used
|
override val BSSHIGHRAM_END = 0u // not actually used
|
||||||
override lateinit var zeropage: Zeropage // not actually used
|
override lateinit var zeropage: Zeropage // not actually used
|
||||||
|
|
|
@ -207,8 +207,8 @@ class AsmGen6502Internal (
|
||||||
private val postincrdecrAsmGen = PostIncrDecrAsmGen(program, this)
|
private val postincrdecrAsmGen = PostIncrDecrAsmGen(program, this)
|
||||||
private val functioncallAsmGen = FunctionCallAsmGen(program, this)
|
private val functioncallAsmGen = FunctionCallAsmGen(program, this)
|
||||||
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
|
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
|
||||||
private val assignmentAsmGen = AssignmentAsmGen(program, symbolTable, this, allocator)
|
private val anyExprGen = AnyExprAsmGen(this)
|
||||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator)
|
private val assignmentAsmGen = AssignmentAsmGen(program, this, anyExprGen, allocator)
|
||||||
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
|
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
|
||||||
|
|
||||||
fun compileToAssembly(): IAssemblyProgram? {
|
fun compileToAssembly(): IAssemblyProgram? {
|
||||||
|
@ -394,32 +394,6 @@ class AsmGen6502Internal (
|
||||||
return name2.replace("prog8_lib.P8ZP_SCRATCH_", "P8ZP_SCRATCH_") // take care of the 'hooks' to the temp vars -> reference zp symbols directly
|
return name2.replace("prog8_lib.P8ZP_SCRATCH_", "P8ZP_SCRATCH_") // take care of the 'hooks' to the temp vars -> reference zp symbols directly
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun saveRegisterLocal(register: CpuRegister, scope: IPtSubroutine) {
|
|
||||||
if (isTargetCpu(CpuType.CPU65c02)) {
|
|
||||||
// just use the cpu's stack for all registers, shorter code
|
|
||||||
when (register) {
|
|
||||||
CpuRegister.A -> out(" pha")
|
|
||||||
CpuRegister.X -> out(" phx")
|
|
||||||
CpuRegister.Y -> out(" phy")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
when (register) {
|
|
||||||
CpuRegister.A -> {
|
|
||||||
// just use the stack, only for A
|
|
||||||
out(" pha")
|
|
||||||
}
|
|
||||||
CpuRegister.X -> {
|
|
||||||
out(" stx prog8_regsaveX")
|
|
||||||
subroutineExtra(scope).usedRegsaveX = true
|
|
||||||
}
|
|
||||||
CpuRegister.Y -> {
|
|
||||||
out(" sty prog8_regsaveY")
|
|
||||||
subroutineExtra(scope).usedRegsaveY = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun saveRegisterStack(register: CpuRegister, keepA: Boolean) {
|
internal fun saveRegisterStack(register: CpuRegister, keepA: Boolean) {
|
||||||
when (register) {
|
when (register) {
|
||||||
CpuRegister.A -> out(" pha")
|
CpuRegister.A -> out(" pha")
|
||||||
|
@ -444,24 +418,6 @@ class AsmGen6502Internal (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun restoreRegisterLocal(register: CpuRegister) {
|
|
||||||
if (isTargetCpu(CpuType.CPU65c02)) {
|
|
||||||
when (register) {
|
|
||||||
// this just used the stack, for all registers. Shorter code.
|
|
||||||
CpuRegister.A -> out(" pla")
|
|
||||||
CpuRegister.X -> out(" plx")
|
|
||||||
CpuRegister.Y -> out(" ply")
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
when (register) {
|
|
||||||
CpuRegister.A -> out(" pla") // this just used the stack but only for A
|
|
||||||
CpuRegister.X -> out(" ldx prog8_regsaveX")
|
|
||||||
CpuRegister.Y -> out(" ldy prog8_regsaveY")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun restoreRegisterStack(register: CpuRegister, keepA: Boolean) {
|
internal fun restoreRegisterStack(register: CpuRegister, keepA: Boolean) {
|
||||||
when (register) {
|
when (register) {
|
||||||
CpuRegister.A -> {
|
CpuRegister.A -> {
|
||||||
|
@ -581,22 +537,12 @@ class AsmGen6502Internal (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("avoid calling this as it generates slow evalstack based code")
|
internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): DataType? =
|
||||||
internal fun translateExpression(expression: PtExpression) =
|
builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultRegister)
|
||||||
expressionsAsmGen.translateExpression(expression)
|
|
||||||
|
|
||||||
internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? =
|
|
||||||
builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultToStack, resultRegister)
|
|
||||||
|
|
||||||
internal fun translateFunctionCall(functionCallExpr: PtFunctionCall) =
|
internal fun translateFunctionCall(functionCallExpr: PtFunctionCall) =
|
||||||
functioncallAsmGen.translateFunctionCall(functionCallExpr)
|
functioncallAsmGen.translateFunctionCall(functionCallExpr)
|
||||||
|
|
||||||
internal fun saveXbeforeCall(functionCall: PtFunctionCall) =
|
|
||||||
functioncallAsmGen.saveXbeforeCall(functionCall)
|
|
||||||
|
|
||||||
internal fun restoreXafterCall(functionCall: PtFunctionCall) =
|
|
||||||
functioncallAsmGen.restoreXafterCall(functionCall)
|
|
||||||
|
|
||||||
internal fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) =
|
internal fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) =
|
||||||
assignmentAsmGen.translateNormalAssignment(assign, scope)
|
assignmentAsmGen.translateNormalAssignment(assign, scope)
|
||||||
|
|
||||||
|
@ -625,7 +571,6 @@ class AsmGen6502Internal (
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun assignExpressionTo(value: PtExpression, target: AsmAssignTarget) {
|
internal fun assignExpressionTo(value: PtExpression, target: AsmAssignTarget) {
|
||||||
// don't use translateExpression() to avoid evalstack
|
|
||||||
when (target.datatype) {
|
when (target.datatype) {
|
||||||
in ByteDatatypes -> {
|
in ByteDatatypes -> {
|
||||||
assignExpressionToRegister(value, RegisterOrPair.A)
|
assignExpressionToRegister(value, RegisterOrPair.A)
|
||||||
|
@ -1086,20 +1031,6 @@ $repeatLabel""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun signExtendStackLsb(valueDt: DataType) {
|
|
||||||
// sign extend signed byte on stack to signed word on stack
|
|
||||||
when(valueDt) {
|
|
||||||
DataType.UBYTE -> {
|
|
||||||
if(isTargetCpu(CpuType.CPU65c02))
|
|
||||||
out(" stz P8ESTACK_HI+1,x")
|
|
||||||
else
|
|
||||||
out(" lda #0 | sta P8ESTACK_HI+1,x")
|
|
||||||
}
|
|
||||||
DataType.BYTE -> out(" jsr prog8_lib.sign_extend_stack_byte")
|
|
||||||
else -> throw AssemblyError("need byte type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun signExtendVariableLsb(asmvar: String, valueDt: DataType) {
|
internal fun signExtendVariableLsb(asmvar: String, valueDt: DataType) {
|
||||||
// sign extend signed byte in a var to a full word in that variable
|
// sign extend signed byte in a var to a full word in that variable
|
||||||
when(valueDt) {
|
when(valueDt) {
|
||||||
|
@ -1728,7 +1659,7 @@ $repeatLabel""")
|
||||||
}
|
}
|
||||||
else if (left is PtMemoryByte) {
|
else if (left is PtMemoryByte) {
|
||||||
return if(rightConstVal.number.toInt()!=0) {
|
return if(rightConstVal.number.toInt()!=0) {
|
||||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
translateDirectMemReadExpressionToRegA(left)
|
||||||
code("#${rightConstVal.number.toInt()}")
|
code("#${rightConstVal.number.toInt()}")
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1875,7 +1806,7 @@ $repeatLabel""")
|
||||||
out(" beq $jumpIfFalseLabel")
|
out(" beq $jumpIfFalseLabel")
|
||||||
}
|
}
|
||||||
else if (left is PtMemoryByte) {
|
else if (left is PtMemoryByte) {
|
||||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
translateDirectMemReadExpressionToRegA(left)
|
||||||
return if(rightConstVal.number.toInt()!=0)
|
return if(rightConstVal.number.toInt()!=0)
|
||||||
code("#${rightConstVal.number.toInt()}")
|
code("#${rightConstVal.number.toInt()}")
|
||||||
else
|
else
|
||||||
|
@ -2036,7 +1967,7 @@ $repeatLabel""")
|
||||||
out(" bne $jumpIfFalseLabel")
|
out(" bne $jumpIfFalseLabel")
|
||||||
}
|
}
|
||||||
else if (left is PtMemoryByte) {
|
else if (left is PtMemoryByte) {
|
||||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
translateDirectMemReadExpressionToRegA(left)
|
||||||
return if(rightConstVal.number.toInt()!=0)
|
return if(rightConstVal.number.toInt()!=0)
|
||||||
code("#${rightConstVal.number.toInt()}")
|
code("#${rightConstVal.number.toInt()}")
|
||||||
else
|
else
|
||||||
|
@ -2200,7 +2131,7 @@ $repeatLabel""")
|
||||||
}
|
}
|
||||||
else if (left is PtMemoryByte) {
|
else if (left is PtMemoryByte) {
|
||||||
if(rightConstVal.number.toInt()!=0) {
|
if(rightConstVal.number.toInt()!=0) {
|
||||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
translateDirectMemReadExpressionToRegA(left)
|
||||||
code("#${rightConstVal.number.toInt()}")
|
code("#${rightConstVal.number.toInt()}")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -2363,7 +2294,7 @@ $repeatLabel""")
|
||||||
out(" bne $jumpIfFalseLabel")
|
out(" bne $jumpIfFalseLabel")
|
||||||
}
|
}
|
||||||
else if (left is PtMemoryByte) {
|
else if (left is PtMemoryByte) {
|
||||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
translateDirectMemReadExpressionToRegA(left)
|
||||||
return if(rightConstVal.number.toInt()!=0)
|
return if(rightConstVal.number.toInt()!=0)
|
||||||
code("#${rightConstVal.number.toInt()}")
|
code("#${rightConstVal.number.toInt()}")
|
||||||
else
|
else
|
||||||
|
@ -2409,7 +2340,7 @@ $repeatLabel""")
|
||||||
out(" beq $jumpIfFalseLabel")
|
out(" beq $jumpIfFalseLabel")
|
||||||
}
|
}
|
||||||
else if (left is PtMemoryByte) {
|
else if (left is PtMemoryByte) {
|
||||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
translateDirectMemReadExpressionToRegA(left)
|
||||||
return if(rightConstVal.number.toInt()!=0)
|
return if(rightConstVal.number.toInt()!=0)
|
||||||
code("#${rightConstVal.number.toInt()}")
|
code("#${rightConstVal.number.toInt()}")
|
||||||
else
|
else
|
||||||
|
@ -2865,22 +2796,14 @@ $repeatLabel""")
|
||||||
+""")
|
+""")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun translateDirectMemReadExpressionToRegAorStack(expr: PtMemoryByte, pushResultOnEstack: Boolean) {
|
internal fun translateDirectMemReadExpressionToRegA(expr: PtMemoryByte) {
|
||||||
|
|
||||||
fun assignViaExprEval() {
|
fun assignViaExprEval() {
|
||||||
assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||||
if (isTargetCpu(CpuType.CPU65c02)) {
|
if (isTargetCpu(CpuType.CPU65c02)) {
|
||||||
if (pushResultOnEstack) {
|
out(" lda (P8ZP_SCRATCH_W2)")
|
||||||
out(" lda (P8ZP_SCRATCH_W2) | dex | sta P8ESTACK_LO+1,x")
|
|
||||||
} else {
|
|
||||||
out(" lda (P8ZP_SCRATCH_W2)")
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (pushResultOnEstack) {
|
out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
|
||||||
out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y | dex | sta P8ESTACK_LO+1,x")
|
|
||||||
} else {
|
|
||||||
out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2888,21 +2811,14 @@ $repeatLabel""")
|
||||||
is PtNumber -> {
|
is PtNumber -> {
|
||||||
val address = (expr.address as PtNumber).number.toInt()
|
val address = (expr.address as PtNumber).number.toInt()
|
||||||
out(" lda ${address.toHex()}")
|
out(" lda ${address.toHex()}")
|
||||||
if(pushResultOnEstack)
|
|
||||||
out(" sta P8ESTACK_LO,x | dex")
|
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
// the identifier is a pointer variable, so read the value from the address in it
|
// the identifier is a pointer variable, so read the value from the address in it
|
||||||
loadByteFromPointerIntoA(expr.address as PtIdentifier)
|
loadByteFromPointerIntoA(expr.address as PtIdentifier)
|
||||||
if(pushResultOnEstack)
|
|
||||||
out(" sta P8ESTACK_LO,x | dex")
|
|
||||||
}
|
}
|
||||||
is PtBinaryExpression -> {
|
is PtBinaryExpression -> {
|
||||||
val addrExpr = expr.address as PtBinaryExpression
|
val addrExpr = expr.address as PtBinaryExpression
|
||||||
if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
|
if(!tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
|
||||||
if(pushResultOnEstack)
|
|
||||||
out(" sta P8ESTACK_LO,x | dex")
|
|
||||||
} else {
|
|
||||||
assignViaExprEval()
|
assignViaExprEval()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3098,6 +3014,14 @@ $repeatLabel""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun pushFAC1() {
|
||||||
|
out(" jsr floats.pushFAC1")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun popFAC1() {
|
||||||
|
out(" jsr floats.popFAC1")
|
||||||
|
}
|
||||||
|
|
||||||
internal fun needAsaveForExpr(arg: PtExpression): Boolean =
|
internal fun needAsaveForExpr(arg: PtExpression): Boolean =
|
||||||
arg !is PtNumber && arg !is PtIdentifier && (arg !is PtMemoryByte || !arg.isSimple())
|
arg !is PtNumber && arg !is PtIdentifier && (arg !is PtMemoryByte || !arg.isSimple())
|
||||||
|
|
||||||
|
@ -3130,9 +3054,6 @@ $repeatLabel""")
|
||||||
* it's more consistent to only define these attributes on a Subroutine node.
|
* it's more consistent to only define these attributes on a Subroutine node.
|
||||||
*/
|
*/
|
||||||
internal class SubroutineExtraAsmInfo {
|
internal class SubroutineExtraAsmInfo {
|
||||||
var usedRegsaveA = false
|
|
||||||
var usedRegsaveX = false
|
|
||||||
var usedRegsaveY = false
|
|
||||||
var usedFloatEvalResultVar1 = false
|
var usedFloatEvalResultVar1 = false
|
||||||
var usedFloatEvalResultVar2 = false
|
var usedFloatEvalResultVar2 = false
|
||||||
|
|
||||||
|
|
|
@ -15,21 +15,7 @@ internal fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefin
|
||||||
|
|
||||||
var linesByFour = getLinesBy(lines, 4)
|
var linesByFour = getLinesBy(lines, 4)
|
||||||
|
|
||||||
var mods = optimizeUselessStackByteWrites(linesByFour)
|
var mods = optimizeIncDec(linesByFour)
|
||||||
if(mods.isNotEmpty()) {
|
|
||||||
apply(mods, lines)
|
|
||||||
linesByFour = getLinesBy(lines, 4)
|
|
||||||
numberOfOptimizations++
|
|
||||||
}
|
|
||||||
|
|
||||||
mods = optimizeIncDec(linesByFour)
|
|
||||||
if(mods.isNotEmpty()) {
|
|
||||||
apply(mods, lines)
|
|
||||||
linesByFour = getLinesBy(lines, 4)
|
|
||||||
numberOfOptimizations++
|
|
||||||
}
|
|
||||||
|
|
||||||
mods = optimizeCmpSequence(linesByFour)
|
|
||||||
if(mods.isNotEmpty()) {
|
if(mods.isNotEmpty()) {
|
||||||
apply(mods, lines)
|
apply(mods, lines)
|
||||||
linesByFour = getLinesBy(lines, 4)
|
linesByFour = getLinesBy(lines, 4)
|
||||||
|
@ -97,44 +83,6 @@ private fun getLinesBy(lines: MutableList<String>, windowSize: Int) =
|
||||||
// all lines (that aren't empty or comments) in sliding windows of certain size
|
// all lines (that aren't empty or comments) in sliding windows of certain size
|
||||||
lines.withIndex().filter { it.value.isNotBlank() && !it.value.trimStart().startsWith(';') }.windowed(windowSize, partialWindows = false)
|
lines.withIndex().filter { it.value.isNotBlank() && !it.value.trimStart().startsWith(';') }.windowed(windowSize, partialWindows = false)
|
||||||
|
|
||||||
private fun optimizeCmpSequence(linesByFour: List<List<IndexedValue<String>>>): List<Modification> {
|
|
||||||
// when statement (on bytes) generates a sequence of:
|
|
||||||
// lda $ce01,x
|
|
||||||
// cmp #$20
|
|
||||||
// beq check_prog8_s72choice_32
|
|
||||||
// lda $ce01,x
|
|
||||||
// cmp #$21
|
|
||||||
// beq check_prog8_s73choice_33
|
|
||||||
// the repeated lda can be removed
|
|
||||||
val mods = mutableListOf<Modification>()
|
|
||||||
for(lines in linesByFour) {
|
|
||||||
if(lines[0].value.trim()=="lda P8ESTACK_LO+1,x" &&
|
|
||||||
lines[1].value.trim().startsWith("cmp ") &&
|
|
||||||
lines[2].value.trim().startsWith("beq ") &&
|
|
||||||
lines[3].value.trim()=="lda P8ESTACK_LO+1,x") {
|
|
||||||
mods.add(Modification(lines[3].index, true, null)) // remove the second lda
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mods
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun optimizeUselessStackByteWrites(linesByFour: List<List<IndexedValue<String>>>): List<Modification> {
|
|
||||||
// sta on stack, dex, inx, lda from stack -> eliminate this useless stack byte write
|
|
||||||
// this is a lot harder for word values because the instruction sequence varies.
|
|
||||||
val mods = mutableListOf<Modification>()
|
|
||||||
for(lines in linesByFour) {
|
|
||||||
if(lines[0].value.trim()=="sta P8ESTACK_LO,x" &&
|
|
||||||
lines[1].value.trim()=="dex" &&
|
|
||||||
lines[2].value.trim()=="inx" &&
|
|
||||||
lines[3].value.trim()=="lda P8ESTACK_LO,x") {
|
|
||||||
mods.add(Modification(lines[1].index, true, null))
|
|
||||||
mods.add(Modification(lines[2].index, true, null))
|
|
||||||
mods.add(Modification(lines[3].index, true, null))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mods
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun optimizeSameAssignments(
|
private fun optimizeSameAssignments(
|
||||||
linesByFourteen: List<List<IndexedValue<String>>>,
|
linesByFourteen: List<List<IndexedValue<String>>>,
|
||||||
machine: IMachineDefinition,
|
machine: IMachineDefinition,
|
||||||
|
|
|
@ -10,34 +10,31 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
private val asmgen: AsmGen6502Internal,
|
private val asmgen: AsmGen6502Internal,
|
||||||
private val assignAsmGen: AssignmentAsmGen) {
|
private val assignAsmGen: AssignmentAsmGen) {
|
||||||
|
|
||||||
internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? {
|
internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): DataType? {
|
||||||
return translateFunctioncall(fcall, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister)
|
return translateFunctioncall(fcall, discardResult = false, resultRegister = resultRegister)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun translateFunctioncallStatement(fcall: PtBuiltinFunctionCall) {
|
internal fun translateFunctioncallStatement(fcall: PtBuiltinFunctionCall) {
|
||||||
translateFunctioncall(fcall, discardResult = true, resultToStack = false, resultRegister = null)
|
translateFunctioncall(fcall, discardResult = true, resultRegister = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? {
|
private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultRegister: RegisterOrPair?): DataType? {
|
||||||
if (discardResult && fcall.hasNoSideEffects)
|
if (discardResult && fcall.hasNoSideEffects)
|
||||||
return null // can just ignore the whole function call altogether
|
return null // can just ignore the whole function call altogether
|
||||||
|
|
||||||
if(discardResult && resultToStack)
|
|
||||||
throw AssemblyError("cannot both discard the result AND put it onto stack")
|
|
||||||
|
|
||||||
val sscope = fcall.definingISub()
|
val sscope = fcall.definingISub()
|
||||||
|
|
||||||
when (fcall.name) {
|
when (fcall.name) {
|
||||||
"msb" -> funcMsb(fcall, resultToStack, resultRegister)
|
"msb" -> funcMsb(fcall, resultRegister)
|
||||||
"lsb" -> funcLsb(fcall, resultToStack, resultRegister)
|
"lsb" -> funcLsb(fcall, resultRegister)
|
||||||
"mkword" -> funcMkword(fcall, resultToStack, resultRegister)
|
"mkword" -> funcMkword(fcall, resultRegister)
|
||||||
"clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword" -> funcClamp(fcall, resultToStack, resultRegister)
|
"clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword" -> funcClamp(fcall, resultRegister)
|
||||||
"min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(fcall, resultToStack, resultRegister)
|
"min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(fcall, resultRegister)
|
||||||
"max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(fcall, resultToStack, resultRegister)
|
"max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(fcall, resultRegister)
|
||||||
"abs__byte", "abs__word", "abs__float" -> funcAbs(fcall, resultToStack, resultRegister, sscope)
|
"abs__byte", "abs__word", "abs__float" -> funcAbs(fcall, resultRegister, sscope)
|
||||||
"any", "all" -> funcAnyAll(fcall, resultToStack, resultRegister, sscope)
|
"any", "all" -> funcAnyAll(fcall, resultRegister, sscope)
|
||||||
"sgn" -> funcSgn(fcall, resultToStack, resultRegister, sscope)
|
"sgn" -> funcSgn(fcall, resultRegister, sscope)
|
||||||
"sqrt__ubyte", "sqrt__uword", "sqrt__float" -> funcSqrt(fcall, resultToStack, resultRegister, sscope)
|
"sqrt__ubyte", "sqrt__uword", "sqrt__float" -> funcSqrt(fcall, resultRegister, sscope)
|
||||||
"divmod__ubyte" -> funcDivmod(fcall)
|
"divmod__ubyte" -> funcDivmod(fcall)
|
||||||
"divmod__uword" -> funcDivmodW(fcall)
|
"divmod__uword" -> funcDivmodW(fcall)
|
||||||
"rol" -> funcRol(fcall)
|
"rol" -> funcRol(fcall)
|
||||||
|
@ -46,8 +43,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
"ror2" -> funcRor2(fcall)
|
"ror2" -> funcRor2(fcall)
|
||||||
"sort" -> funcSort(fcall)
|
"sort" -> funcSort(fcall)
|
||||||
"reverse" -> funcReverse(fcall)
|
"reverse" -> funcReverse(fcall)
|
||||||
"memory" -> funcMemory(fcall, discardResult, resultToStack, resultRegister)
|
"memory" -> funcMemory(fcall, discardResult, resultRegister)
|
||||||
"peekw" -> funcPeekW(fcall, resultToStack, resultRegister)
|
"peekw" -> funcPeekW(fcall, resultRegister)
|
||||||
"peek" -> throw AssemblyError("peek() should have been replaced by @()")
|
"peek" -> throw AssemblyError("peek() should have been replaced by @()")
|
||||||
"pokew" -> funcPokeW(fcall)
|
"pokew" -> funcPokeW(fcall)
|
||||||
"pokemon" -> { /* meme function */ }
|
"pokemon" -> { /* meme function */ }
|
||||||
|
@ -71,12 +68,10 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
asmgen.popCpuStack(DataType.UWORD, target, fcall.definingISub())
|
asmgen.popCpuStack(DataType.UWORD, target, fcall.definingISub())
|
||||||
}
|
}
|
||||||
"rsave" -> funcRsave()
|
"rsave" -> funcRsave()
|
||||||
"rsavex" -> funcRsaveX()
|
|
||||||
"rrestore" -> funcRrestore()
|
"rrestore" -> funcRrestore()
|
||||||
"rrestorex" -> funcRrestoreX()
|
|
||||||
"cmp" -> funcCmp(fcall)
|
"cmp" -> funcCmp(fcall)
|
||||||
"callfar" -> funcCallFar(fcall)
|
"callfar" -> funcCallFar(fcall)
|
||||||
"prog8_lib_stringcompare" -> funcStringCompare(fcall, resultToStack)
|
"prog8_lib_stringcompare" -> funcStringCompare(fcall)
|
||||||
else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}")
|
else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,11 +110,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
sty $remainderVar+1""")
|
sty $remainderVar+1""")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcStringCompare(fcall: PtBuiltinFunctionCall, resultToStack: Boolean) {
|
private fun funcStringCompare(fcall: PtBuiltinFunctionCall) {
|
||||||
asmgen.assignWordOperandsToAYAndVar(fcall.args[0], fcall.args[1], "P8ZP_SCRATCH_W2")
|
asmgen.assignWordOperandsToAYAndVar(fcall.args[0], fcall.args[1], "P8ZP_SCRATCH_W2")
|
||||||
asmgen.out(" jsr prog8_lib.strcmp_mem")
|
asmgen.out(" jsr prog8_lib.strcmp_mem")
|
||||||
if(resultToStack)
|
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcRsave() {
|
private fun funcRsave() {
|
||||||
|
@ -142,13 +135,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
lda P8ZP_SCRATCH_REG""")
|
lda P8ZP_SCRATCH_REG""")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcRsaveX() {
|
|
||||||
if (asmgen.isTargetCpu(CpuType.CPU65c02))
|
|
||||||
asmgen.out(" phx")
|
|
||||||
else
|
|
||||||
asmgen.out(" txa | pha")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun funcRrestore() {
|
private fun funcRrestore() {
|
||||||
if (asmgen.isTargetCpu(CpuType.CPU65c02))
|
if (asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
@ -166,13 +152,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
plp""")
|
plp""")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcRrestoreX() {
|
|
||||||
if (asmgen.isTargetCpu(CpuType.CPU65c02))
|
|
||||||
asmgen.out(" plx")
|
|
||||||
else
|
|
||||||
asmgen.out(" sta P8ZP_SCRATCH_B1 | pla | tax | lda P8ZP_SCRATCH_B1")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun funcCallFar(fcall: PtBuiltinFunctionCall) {
|
private fun funcCallFar(fcall: PtBuiltinFunctionCall) {
|
||||||
if(asmgen.options.compTarget.name != "cx16")
|
if(asmgen.options.compTarget.name != "cx16")
|
||||||
throw AssemblyError("callfar only works on cx16 target at this time")
|
throw AssemblyError("callfar only works on cx16 target at this time")
|
||||||
|
@ -253,7 +232,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcMemory(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcMemory(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultRegister: RegisterOrPair?) {
|
||||||
if(discardResult)
|
if(discardResult)
|
||||||
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
||||||
val name = (fcall.args[0] as PtString).value
|
val name = (fcall.args[0] as PtString).value
|
||||||
|
@ -263,41 +242,25 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
addressOf.add(slabname)
|
addressOf.add(slabname)
|
||||||
addressOf.parent = fcall
|
addressOf.parent = fcall
|
||||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = addressOf)
|
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = addressOf)
|
||||||
val target =
|
val target = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen)
|
||||||
if(resultToStack)
|
|
||||||
AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, null, fcall.position)
|
|
||||||
else
|
|
||||||
AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen)
|
|
||||||
val assign = AsmAssignment(src, target, program.memsizer, fcall.position)
|
val assign = AsmAssignment(src, target, program.memsizer, fcall.position)
|
||||||
asmgen.translateNormalAssignment(assign, fcall.definingISub())
|
asmgen.translateNormalAssignment(assign, fcall.definingISub())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcSqrt(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
private fun funcSqrt(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||||
translateArguments(fcall, scope)
|
translateArguments(fcall, scope)
|
||||||
when(fcall.args[0].type) {
|
when(fcall.args[0].type) {
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
if(resultToStack)
|
asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_into_A")
|
||||||
asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_stack")
|
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false)
|
||||||
else {
|
|
||||||
asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_into_A")
|
|
||||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
if(resultToStack)
|
asmgen.out(" jsr prog8_lib.func_sqrt16_into_A")
|
||||||
asmgen.out(" jsr prog8_lib.func_sqrt16_stack")
|
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false)
|
||||||
else {
|
|
||||||
asmgen.out(" jsr prog8_lib.func_sqrt16_into_A")
|
|
||||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
asmgen.out(" jsr floats.func_sqrt_into_FAC1")
|
asmgen.out(" jsr floats.func_sqrt_into_FAC1")
|
||||||
if(resultToStack)
|
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
|
||||||
assignAsmGen.assignFAC1float(AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.FLOAT, scope, fcall.position))
|
|
||||||
else {
|
|
||||||
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird dt")
|
else -> throw AssemblyError("weird dt")
|
||||||
}
|
}
|
||||||
|
@ -466,16 +429,13 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
} else {
|
} else {
|
||||||
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address)
|
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address)
|
||||||
if(ptrAndIndex!=null) {
|
if(ptrAndIndex!=null) {
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!)
|
asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.A)
|
||||||
asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X)
|
asmgen.saveRegisterStack(CpuRegister.A, true)
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!)
|
|
||||||
asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY)
|
asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY)
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
asmgen.out(" sta (+) + 1 | sty (+) + 2")
|
||||||
|
asmgen.restoreRegisterStack(CpuRegister.X, false)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sta (+) + 1
|
|
||||||
sty (+) + 2
|
|
||||||
+ ror ${'$'}ffff,x ; modified""")
|
+ ror ${'$'}ffff,x ; modified""")
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
} else {
|
} else {
|
||||||
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
|
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
@ -571,16 +531,13 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
} else {
|
} else {
|
||||||
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address)
|
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address)
|
||||||
if(ptrAndIndex!=null) {
|
if(ptrAndIndex!=null) {
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!)
|
asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.A)
|
||||||
asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X)
|
asmgen.saveRegisterStack(CpuRegister.A, true)
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!)
|
|
||||||
asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY)
|
asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY)
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
asmgen.out(" sta (+) + 1 | sty (+) + 2")
|
||||||
|
asmgen.restoreRegisterStack(CpuRegister.X, false)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sta (+) + 1
|
|
||||||
sty (+) + 2
|
|
||||||
+ rol ${'$'}ffff,x ; modified""")
|
+ rol ${'$'}ffff,x ; modified""")
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
} else {
|
} else {
|
||||||
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
|
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
@ -633,88 +590,56 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE)
|
asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcSgn(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||||
translateArguments(fcall, scope)
|
translateArguments(fcall, scope)
|
||||||
val dt = fcall.args.single().type
|
val dt = fcall.args.single().type
|
||||||
if(resultToStack) {
|
when (dt) {
|
||||||
when (dt) {
|
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A")
|
||||||
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_stack")
|
DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
|
||||||
DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_stack")
|
DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
|
||||||
DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_stack")
|
DataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A")
|
||||||
DataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_stack")
|
DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A")
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_stack")
|
else -> throw AssemblyError("weird type $dt")
|
||||||
else -> throw AssemblyError("weird type $dt")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
when (dt) {
|
|
||||||
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A")
|
|
||||||
DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
|
|
||||||
DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
|
|
||||||
DataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A")
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A")
|
|
||||||
else -> throw AssemblyError("weird type $dt")
|
|
||||||
}
|
|
||||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, true)
|
|
||||||
}
|
}
|
||||||
|
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcAnyAll(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
private fun funcAnyAll(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||||
outputAddressAndLenghtOfArray(fcall.args[0])
|
outputAddressAndLenghtOfArray(fcall.args[0])
|
||||||
val dt = fcall.args.single().type
|
val dt = fcall.args.single().type
|
||||||
if(resultToStack) {
|
when (dt) {
|
||||||
when (dt) {
|
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_b_into_A | ldy #0")
|
||||||
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_b_stack")
|
DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_w_into_A | ldy #0")
|
||||||
DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_w_stack")
|
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${fcall.name}_f_into_A | ldy #0")
|
||||||
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${fcall.name}_f_stack")
|
in SplitWordArrayTypes -> TODO("split word any/all")
|
||||||
in SplitWordArrayTypes -> TODO("split word any/all")
|
else -> throw AssemblyError("weird type $dt")
|
||||||
else -> throw AssemblyError("weird type $dt")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
when (dt) {
|
|
||||||
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_b_into_A | ldy #0")
|
|
||||||
DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_w_into_A | ldy #0")
|
|
||||||
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${fcall.name}_f_into_A | ldy #0")
|
|
||||||
in SplitWordArrayTypes -> TODO("split word any/all")
|
|
||||||
else -> throw AssemblyError("weird type $dt")
|
|
||||||
}
|
|
||||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, dt in SignedDatatypes)
|
|
||||||
}
|
}
|
||||||
|
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, dt in SignedDatatypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcAbs(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
private fun funcAbs(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||||
translateArguments(fcall, scope)
|
translateArguments(fcall, scope)
|
||||||
val dt = fcall.args.single().type
|
val dt = fcall.args.single().type
|
||||||
if(resultToStack) {
|
when (dt) {
|
||||||
when (dt) {
|
DataType.BYTE -> {
|
||||||
DataType.BYTE -> asmgen.out(" jsr prog8_lib.abs_b_stack")
|
asmgen.out(" jsr prog8_lib.abs_b_into_A")
|
||||||
DataType.WORD -> asmgen.out(" jsr prog8_lib.abs_w_stack")
|
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A,false)
|
||||||
else -> {
|
|
||||||
asmgen.out(" jsr floats.func_abs_f_into_FAC1")
|
|
||||||
assignAsmGen.assignFAC1float(AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.FLOAT, scope, fcall.position))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
DataType.WORD -> {
|
||||||
when (dt) {
|
asmgen.out(" jsr prog8_lib.abs_w_into_AY")
|
||||||
DataType.BYTE -> {
|
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY)
|
||||||
asmgen.out(" jsr prog8_lib.abs_b_into_A")
|
|
||||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A,false)
|
|
||||||
}
|
|
||||||
DataType.WORD -> {
|
|
||||||
asmgen.out(" jsr prog8_lib.abs_w_into_AY")
|
|
||||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY)
|
|
||||||
}
|
|
||||||
DataType.FLOAT -> {
|
|
||||||
asmgen.out(" jsr floats.func_abs_f_into_FAC1")
|
|
||||||
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
|
|
||||||
}
|
|
||||||
DataType.UBYTE -> {
|
|
||||||
asmgen.assignRegister(RegisterOrPair.A, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.A, false, fcall.position, scope, asmgen))
|
|
||||||
}
|
|
||||||
DataType.UWORD -> {
|
|
||||||
asmgen.assignRegister(RegisterOrPair.AY, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.AY, false, fcall.position, scope, asmgen))
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
}
|
||||||
|
DataType.FLOAT -> {
|
||||||
|
asmgen.out(" jsr floats.func_abs_f_into_FAC1")
|
||||||
|
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
|
||||||
|
}
|
||||||
|
DataType.UBYTE -> {
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.A, false, fcall.position, scope, asmgen))
|
||||||
|
}
|
||||||
|
DataType.UWORD -> {
|
||||||
|
asmgen.assignRegister(RegisterOrPair.AY, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.AY, false, fcall.position, scope, asmgen))
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("weird type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,7 +655,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
val varname = asmgen.asmVariableName(addrExpr)
|
val varname = asmgen.asmVariableName(addrExpr)
|
||||||
if(asmgen.isZpVar(addrExpr)) {
|
if(asmgen.isZpVar(addrExpr)) {
|
||||||
// pointervar is already in the zero page, no need to copy
|
// pointervar is already in the zero page, no need to copy
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!)
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX)
|
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX)
|
||||||
if (asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
if (asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
@ -746,7 +670,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
iny
|
iny
|
||||||
sta ($varname),y""")
|
sta ($varname),y""")
|
||||||
}
|
}
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -756,18 +679,15 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
|
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
|
||||||
// can do ZP,Y indexing
|
// can do ZP,Y indexing
|
||||||
val varname = asmgen.asmVariableName(pointer)
|
val varname = asmgen.asmVariableName(pointer)
|
||||||
val scope = fcall.definingISub()!!
|
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
|
||||||
asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y)
|
asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y)
|
||||||
asmgen.saveRegisterLocal(CpuRegister.Y, scope)
|
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
||||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX)
|
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX)
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.Y)
|
asmgen.restoreRegisterStack(CpuRegister.Y, true)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sta ($varname),y
|
sta ($varname),y
|
||||||
txa
|
txa
|
||||||
iny
|
iny
|
||||||
sta ($varname),y""")
|
sta ($varname),y""")
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -779,7 +699,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
asmgen.out(" jsr prog8_lib.func_pokew")
|
asmgen.out(" jsr prog8_lib.func_pokew")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcPeekW(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcPeekW(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||||
fun fallback() {
|
fun fallback() {
|
||||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||||
asmgen.out(" jsr prog8_lib.func_peekw")
|
asmgen.out(" jsr prog8_lib.func_peekw")
|
||||||
|
@ -830,23 +750,19 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
else -> fallback()
|
else -> fallback()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(resultToStack){
|
when(resultRegister ?: RegisterOrPair.AY) {
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
RegisterOrPair.AY -> {}
|
||||||
} else {
|
RegisterOrPair.AX -> asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG")
|
||||||
when(resultRegister ?: RegisterOrPair.AY) {
|
RegisterOrPair.XY -> asmgen.out(" tax")
|
||||||
RegisterOrPair.AY -> {}
|
in Cx16VirtualRegisters -> asmgen.out(
|
||||||
RegisterOrPair.AX -> asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG")
|
" sta cx16.${
|
||||||
RegisterOrPair.XY -> asmgen.out(" tax")
|
resultRegister.toString().lowercase()
|
||||||
in Cx16VirtualRegisters -> asmgen.out(
|
} | sty cx16.${resultRegister.toString().lowercase()}+1")
|
||||||
" sta cx16.${
|
else -> throw AssemblyError("invalid reg")
|
||||||
resultRegister.toString().lowercase()
|
|
||||||
} | sty cx16.${resultRegister.toString().lowercase()}+1")
|
|
||||||
else -> throw AssemblyError("invalid reg")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcClamp(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcClamp(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||||
val signed = fcall.type in SignedDatatypes
|
val signed = fcall.type in SignedDatatypes
|
||||||
when(fcall.type) {
|
when(fcall.type) {
|
||||||
in ByteDatatypes -> {
|
in ByteDatatypes -> {
|
||||||
|
@ -854,30 +770,22 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W1+1", fcall.args[2].type) // maximum
|
assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W1+1", fcall.args[2].type) // maximum
|
||||||
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A, signed) // value
|
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A, signed) // value
|
||||||
asmgen.out(" jsr prog8_lib.func_clamp_${fcall.type.toString().lowercase()}")
|
asmgen.out(" jsr prog8_lib.func_clamp_${fcall.type.toString().lowercase()}")
|
||||||
if(resultToStack) {
|
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
assignAsmGen.assignRegisterByte(targetReg, CpuRegister.A, signed)
|
||||||
} else {
|
|
||||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
|
||||||
assignAsmGen.assignRegisterByte(targetReg, CpuRegister.A, signed)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
in WordDatatypes -> {
|
in WordDatatypes -> {
|
||||||
assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum
|
assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum
|
||||||
assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W2", fcall.args[2].type) // maximum
|
assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W2", fcall.args[2].type) // maximum
|
||||||
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY, signed) // value
|
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY, signed) // value
|
||||||
asmgen.out(" jsr prog8_lib.func_clamp_${fcall.type.toString().lowercase()}")
|
asmgen.out(" jsr prog8_lib.func_clamp_${fcall.type.toString().lowercase()}")
|
||||||
if(resultToStack) {
|
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex")
|
assignAsmGen.assignRegisterpairWord(targetReg, RegisterOrPair.AY)
|
||||||
} else {
|
|
||||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen)
|
|
||||||
assignAsmGen.assignRegisterpairWord(targetReg, RegisterOrPair.AY)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid dt")
|
else -> throw AssemblyError("invalid dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcMin(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcMin(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||||
val signed = fcall.type in SignedDatatypes
|
val signed = fcall.type in SignedDatatypes
|
||||||
if(fcall.type in ByteDatatypes) {
|
if(fcall.type in ByteDatatypes) {
|
||||||
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_B1", fcall.type) // right
|
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_B1", fcall.type) // right
|
||||||
|
@ -887,12 +795,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda P8ZP_SCRATCH_B1
|
lda P8ZP_SCRATCH_B1
|
||||||
+""")
|
+""")
|
||||||
if(resultToStack) {
|
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
asmgen.assignRegister(RegisterOrPair.A, targetReg)
|
||||||
} else {
|
|
||||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
|
||||||
asmgen.assignRegister(RegisterOrPair.A, targetReg)
|
|
||||||
}
|
|
||||||
} else if(fcall.type in WordDatatypes) {
|
} else if(fcall.type in WordDatatypes) {
|
||||||
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left
|
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left
|
||||||
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right
|
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right
|
||||||
|
@ -928,18 +832,14 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
ldy P8ZP_SCRATCH_W1+1
|
ldy P8ZP_SCRATCH_W1+1
|
||||||
+""")
|
+""")
|
||||||
}
|
}
|
||||||
if(resultToStack) {
|
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex")
|
asmgen.assignRegister(RegisterOrPair.AY, targetReg)
|
||||||
} else {
|
|
||||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen)
|
|
||||||
asmgen.assignRegister(RegisterOrPair.AY, targetReg)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw AssemblyError("min float not supported")
|
throw AssemblyError("min float not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcMax(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcMax(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||||
val signed = fcall.type in SignedDatatypes
|
val signed = fcall.type in SignedDatatypes
|
||||||
if(fcall.type in ByteDatatypes) {
|
if(fcall.type in ByteDatatypes) {
|
||||||
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_B1", fcall.type) // left
|
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_B1", fcall.type) // left
|
||||||
|
@ -949,12 +849,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda P8ZP_SCRATCH_B1
|
lda P8ZP_SCRATCH_B1
|
||||||
+""")
|
+""")
|
||||||
if(resultToStack) {
|
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
asmgen.assignRegister(RegisterOrPair.A, targetReg)
|
||||||
} else {
|
|
||||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
|
||||||
asmgen.assignRegister(RegisterOrPair.A, targetReg)
|
|
||||||
}
|
|
||||||
} else if(fcall.type in WordDatatypes) {
|
} else if(fcall.type in WordDatatypes) {
|
||||||
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left
|
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left
|
||||||
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right
|
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right
|
||||||
|
@ -990,72 +886,61 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
ldy P8ZP_SCRATCH_W2+1
|
ldy P8ZP_SCRATCH_W2+1
|
||||||
+""")
|
+""")
|
||||||
}
|
}
|
||||||
if(resultToStack) {
|
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex")
|
asmgen.assignRegister(RegisterOrPair.AY, targetReg)
|
||||||
} else {
|
|
||||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen)
|
|
||||||
asmgen.assignRegister(RegisterOrPair.AY, targetReg)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw AssemblyError("max float not supported")
|
throw AssemblyError("max float not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcMkword(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcMkword(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||||
if(resultToStack) {
|
val reg = resultRegister ?: RegisterOrPair.AY
|
||||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // msb
|
var needAsave = asmgen.needAsaveForExpr(fcall.args[0])
|
||||||
asmgen.out(" pha")
|
if(!needAsave) {
|
||||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
val mr0 = fcall.args[0] as? PtMemoryByte
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | pla | sta P8ESTACK_HI,x | dex")
|
val mr1 = fcall.args[1] as? PtMemoryByte
|
||||||
} else {
|
if (mr0 != null)
|
||||||
val reg = resultRegister ?: RegisterOrPair.AY
|
needAsave = mr0.address !is PtNumber
|
||||||
var needAsave = asmgen.needAsaveForExpr(fcall.args[0])
|
if (mr1 != null)
|
||||||
if(!needAsave) {
|
needAsave = needAsave or (mr1.address !is PtNumber)
|
||||||
val mr0 = fcall.args[0] as? PtMemoryByte
|
}
|
||||||
val mr1 = fcall.args[1] as? PtMemoryByte
|
when(reg) {
|
||||||
if (mr0 != null)
|
RegisterOrPair.AX -> {
|
||||||
needAsave = mr0.address !is PtNumber
|
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
||||||
if (mr1 != null)
|
if(needAsave)
|
||||||
needAsave = needAsave or (mr1.address !is PtNumber)
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.X) // msb
|
||||||
|
if(needAsave)
|
||||||
|
asmgen.out(" pla")
|
||||||
}
|
}
|
||||||
when(reg) {
|
RegisterOrPair.AY -> {
|
||||||
RegisterOrPair.AX -> {
|
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
||||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
if(needAsave)
|
||||||
if(needAsave)
|
asmgen.out(" pha")
|
||||||
asmgen.out(" pha")
|
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb
|
||||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.X) // msb
|
if(needAsave)
|
||||||
if(needAsave)
|
asmgen.out(" pla")
|
||||||
asmgen.out(" pla")
|
|
||||||
}
|
|
||||||
RegisterOrPair.AY -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
|
||||||
if(needAsave)
|
|
||||||
asmgen.out(" pha")
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb
|
|
||||||
if(needAsave)
|
|
||||||
asmgen.out(" pla")
|
|
||||||
}
|
|
||||||
RegisterOrPair.XY -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
|
||||||
if(needAsave)
|
|
||||||
asmgen.out(" pha")
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb
|
|
||||||
if(needAsave)
|
|
||||||
asmgen.out(" pla")
|
|
||||||
asmgen.out(" tax")
|
|
||||||
}
|
|
||||||
in Cx16VirtualRegisters -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
|
||||||
asmgen.out(" sta cx16.${reg.toString().lowercase()}")
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // msb
|
|
||||||
asmgen.out(" sta cx16.${reg.toString().lowercase()}+1")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("invalid mkword target reg")
|
|
||||||
}
|
}
|
||||||
|
RegisterOrPair.XY -> {
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
||||||
|
if(needAsave)
|
||||||
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb
|
||||||
|
if(needAsave)
|
||||||
|
asmgen.out(" pla")
|
||||||
|
asmgen.out(" tax")
|
||||||
|
}
|
||||||
|
in Cx16VirtualRegisters -> {
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
||||||
|
asmgen.out(" sta cx16.${reg.toString().lowercase()}")
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // msb
|
||||||
|
asmgen.out(" sta cx16.${reg.toString().lowercase()}+1")
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("invalid mkword target reg")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcMsb(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcMsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||||
val arg = fcall.args.single()
|
val arg = fcall.args.single()
|
||||||
if (arg.type !in WordDatatypes)
|
if (arg.type !in WordDatatypes)
|
||||||
throw AssemblyError("msb required word argument")
|
throw AssemblyError("msb required word argument")
|
||||||
|
@ -1063,53 +948,44 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
throw AssemblyError("msb(const) should have been const-folded away")
|
throw AssemblyError("msb(const) should have been const-folded away")
|
||||||
if (arg is PtIdentifier) {
|
if (arg is PtIdentifier) {
|
||||||
val sourceName = asmgen.asmVariableName(arg)
|
val sourceName = asmgen.asmVariableName(arg)
|
||||||
if(resultToStack) {
|
when(resultRegister) {
|
||||||
asmgen.out(" lda $sourceName+1 | sta P8ESTACK_LO,x | dex")
|
null, RegisterOrPair.A -> asmgen.out(" lda $sourceName+1")
|
||||||
} else {
|
RegisterOrPair.X -> asmgen.out(" ldx $sourceName+1")
|
||||||
when(resultRegister) {
|
RegisterOrPair.Y -> asmgen.out(" ldy $sourceName+1")
|
||||||
null, RegisterOrPair.A -> asmgen.out(" lda $sourceName+1")
|
RegisterOrPair.AX -> asmgen.out(" lda $sourceName+1 | ldx #0")
|
||||||
RegisterOrPair.X -> asmgen.out(" ldx $sourceName+1")
|
RegisterOrPair.AY -> asmgen.out(" lda $sourceName+1 | ldy #0")
|
||||||
RegisterOrPair.Y -> asmgen.out(" ldy $sourceName+1")
|
RegisterOrPair.XY -> asmgen.out(" ldx $sourceName+1 | ldy #0")
|
||||||
RegisterOrPair.AX -> asmgen.out(" lda $sourceName+1 | ldx #0")
|
in Cx16VirtualRegisters -> {
|
||||||
RegisterOrPair.AY -> asmgen.out(" lda $sourceName+1 | ldy #0")
|
val regname = resultRegister.name.lowercase()
|
||||||
RegisterOrPair.XY -> asmgen.out(" ldx $sourceName+1 | ldy #0")
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||||
in Cx16VirtualRegisters -> {
|
asmgen.out(" lda $sourceName+1 | sta cx16.$regname | stz cx16.$regname+1")
|
||||||
val regname = resultRegister.name.lowercase()
|
else
|
||||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
asmgen.out(" lda $sourceName+1 | sta cx16.$regname | lda #0 | sta cx16.$regname+1")
|
||||||
asmgen.out(" lda $sourceName+1 | sta cx16.$regname | stz cx16.$regname+1")
|
|
||||||
else
|
|
||||||
asmgen.out(" lda $sourceName+1 | sta cx16.$regname | lda #0 | sta cx16.$regname+1")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("invalid reg")
|
|
||||||
}
|
}
|
||||||
|
else -> throw AssemblyError("invalid reg")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(resultToStack) {
|
when(resultRegister) {
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
null, RegisterOrPair.A -> {
|
||||||
asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
||||||
} else {
|
asmgen.out(" tya")
|
||||||
when(resultRegister) {
|
|
||||||
null, RegisterOrPair.A -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
|
||||||
asmgen.out(" tya")
|
|
||||||
}
|
|
||||||
RegisterOrPair.X -> {
|
|
||||||
asmgen.out(" pha")
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AX)
|
|
||||||
asmgen.out(" pla")
|
|
||||||
}
|
|
||||||
RegisterOrPair.Y -> {
|
|
||||||
asmgen.out(" pha")
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
|
||||||
asmgen.out(" pla")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("invalid reg")
|
|
||||||
}
|
}
|
||||||
|
RegisterOrPair.X -> {
|
||||||
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AX)
|
||||||
|
asmgen.out(" pla")
|
||||||
|
}
|
||||||
|
RegisterOrPair.Y -> {
|
||||||
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
||||||
|
asmgen.out(" pla")
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("invalid reg")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcLsb(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcLsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||||
val arg = fcall.args.single()
|
val arg = fcall.args.single()
|
||||||
if (arg.type !in WordDatatypes)
|
if (arg.type !in WordDatatypes)
|
||||||
throw AssemblyError("lsb required word argument")
|
throw AssemblyError("lsb required word argument")
|
||||||
|
@ -1118,72 +994,60 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||||
|
|
||||||
if (arg is PtIdentifier) {
|
if (arg is PtIdentifier) {
|
||||||
val sourceName = asmgen.asmVariableName(arg)
|
val sourceName = asmgen.asmVariableName(arg)
|
||||||
if(resultToStack) {
|
when(resultRegister) {
|
||||||
asmgen.out(" lda $sourceName | sta P8ESTACK_LO,x | dex")
|
null, RegisterOrPair.A -> asmgen.out(" lda $sourceName")
|
||||||
} else {
|
RegisterOrPair.X -> asmgen.out(" ldx $sourceName")
|
||||||
when(resultRegister) {
|
RegisterOrPair.Y -> asmgen.out(" ldy $sourceName")
|
||||||
null, RegisterOrPair.A -> asmgen.out(" lda $sourceName")
|
RegisterOrPair.AX -> asmgen.out(" lda $sourceName | ldx #0")
|
||||||
RegisterOrPair.X -> asmgen.out(" ldx $sourceName")
|
RegisterOrPair.AY -> asmgen.out(" lda $sourceName | ldy #0")
|
||||||
RegisterOrPair.Y -> asmgen.out(" ldy $sourceName")
|
RegisterOrPair.XY -> asmgen.out(" ldx $sourceName | ldy #0")
|
||||||
RegisterOrPair.AX -> asmgen.out(" lda $sourceName | ldx #0")
|
in Cx16VirtualRegisters -> {
|
||||||
RegisterOrPair.AY -> asmgen.out(" lda $sourceName | ldy #0")
|
val regname = resultRegister.name.lowercase()
|
||||||
RegisterOrPair.XY -> asmgen.out(" ldx $sourceName | ldy #0")
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||||
in Cx16VirtualRegisters -> {
|
asmgen.out(" lda $sourceName | sta cx16.$regname | stz cx16.$regname+1")
|
||||||
val regname = resultRegister.name.lowercase()
|
else
|
||||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
asmgen.out(" lda $sourceName | sta cx16.$regname | lda #0 | sta cx16.$regname+1")
|
||||||
asmgen.out(" lda $sourceName | sta cx16.$regname | stz cx16.$regname+1")
|
|
||||||
else
|
|
||||||
asmgen.out(" lda $sourceName | sta cx16.$regname | lda #0 | sta cx16.$regname+1")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("invalid reg")
|
|
||||||
}
|
}
|
||||||
|
else -> throw AssemblyError("invalid reg")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(resultToStack) {
|
when(resultRegister) {
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
null, RegisterOrPair.A -> {
|
||||||
// NOTE: we rely on the fact that the above assignment to AY, assigns the Lsb to A as the last instruction.
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
||||||
// this is required because the compiler assumes the status bits are set according to what A is (lsb)
|
// NOTE: we rely on the fact that the above assignment to AY, assigns the Lsb to A as the last instruction.
|
||||||
// and will not generate another cmp when lsb() is directly used inside a comparison expression.
|
// this is required because the compiler assumes the status bits are set according to what A is (lsb)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
// and will not generate another cmp when lsb() is directly used inside a comparison expression.
|
||||||
} else {
|
|
||||||
when(resultRegister) {
|
|
||||||
null, RegisterOrPair.A -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
|
||||||
// NOTE: we rely on the fact that the above assignment to AY, assigns the Lsb to A as the last instruction.
|
|
||||||
// this is required because the compiler assumes the status bits are set according to what A is (lsb)
|
|
||||||
// and will not generate another cmp when lsb() is directly used inside a comparison expression.
|
|
||||||
}
|
|
||||||
RegisterOrPair.X -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.XY)
|
|
||||||
// NOTE: we rely on the fact that the above assignment to XY, assigns the Lsb to X as the last instruction.
|
|
||||||
// this is required because the compiler assumes the status bits are set according to what X is (lsb)
|
|
||||||
// and will not generate another cmp when lsb() is directly used inside a comparison expression.
|
|
||||||
}
|
|
||||||
RegisterOrPair.Y -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
|
||||||
asmgen.out(" tay | cpy #0")
|
|
||||||
}
|
|
||||||
RegisterOrPair.AY -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
|
||||||
asmgen.out(" ldy #0 | cmp #0")
|
|
||||||
}
|
|
||||||
RegisterOrPair.AX -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AX)
|
|
||||||
asmgen.out(" ldx #0 | cmp #0")
|
|
||||||
}
|
|
||||||
RegisterOrPair.XY -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.XY)
|
|
||||||
asmgen.out(" ldy #0 | cpx #0")
|
|
||||||
}
|
|
||||||
in Cx16VirtualRegisters -> {
|
|
||||||
asmgen.assignExpressionToRegister(fcall.args.single(), resultRegister)
|
|
||||||
val zero = PtNumber(DataType.UBYTE, 0.0, Position.DUMMY)
|
|
||||||
zero.parent=fcall
|
|
||||||
assignAsmGen.assignExpressionToVariable(zero, "cx16.${resultRegister.toString().lowercase()}H", DataType.UBYTE)
|
|
||||||
asmgen.out(" lda cx16.r0L")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("invalid reg")
|
|
||||||
}
|
}
|
||||||
|
RegisterOrPair.X -> {
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.XY)
|
||||||
|
// NOTE: we rely on the fact that the above assignment to XY, assigns the Lsb to X as the last instruction.
|
||||||
|
// this is required because the compiler assumes the status bits are set according to what X is (lsb)
|
||||||
|
// and will not generate another cmp when lsb() is directly used inside a comparison expression.
|
||||||
|
}
|
||||||
|
RegisterOrPair.Y -> {
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
||||||
|
asmgen.out(" tay | cpy #0")
|
||||||
|
}
|
||||||
|
RegisterOrPair.AY -> {
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
||||||
|
asmgen.out(" ldy #0 | cmp #0")
|
||||||
|
}
|
||||||
|
RegisterOrPair.AX -> {
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AX)
|
||||||
|
asmgen.out(" ldx #0 | cmp #0")
|
||||||
|
}
|
||||||
|
RegisterOrPair.XY -> {
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.XY)
|
||||||
|
asmgen.out(" ldy #0 | cpx #0")
|
||||||
|
}
|
||||||
|
in Cx16VirtualRegisters -> {
|
||||||
|
asmgen.assignExpressionToRegister(fcall.args.single(), resultRegister)
|
||||||
|
val zero = PtNumber(DataType.UBYTE, 0.0, Position.DUMMY)
|
||||||
|
zero.parent=fcall
|
||||||
|
assignAsmGen.assignExpressionToVariable(zero, "cx16.${resultRegister.toString().lowercase()}H", DataType.UBYTE)
|
||||||
|
asmgen.out(" lda cx16.r0L")
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("invalid reg")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,933 +0,0 @@
|
||||||
package prog8.codegen.cpu6502
|
|
||||||
|
|
||||||
import prog8.code.ast.*
|
|
||||||
import prog8.code.core.*
|
|
||||||
import kotlin.math.absoluteValue
|
|
||||||
|
|
||||||
internal class ExpressionsAsmGen(private val program: PtProgram,
|
|
||||||
private val asmgen: AsmGen6502Internal,
|
|
||||||
private val allocator: VariableAllocator) {
|
|
||||||
|
|
||||||
@Deprecated("avoid calling this as it generates slow evalstack based code")
|
|
||||||
internal fun translateExpression(expression: PtExpression) {
|
|
||||||
if (this.asmgen.options.slowCodegenWarnings) {
|
|
||||||
asmgen.errors.warn("slow stack evaluation used for expression", expression.position)
|
|
||||||
}
|
|
||||||
translateExpressionInternal(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// the rest of the methods are all PRIVATE
|
|
||||||
|
|
||||||
|
|
||||||
private fun translateExpressionInternal(expression: PtExpression) {
|
|
||||||
|
|
||||||
when(expression) {
|
|
||||||
is PtPrefix -> translateExpression(expression)
|
|
||||||
is PtBinaryExpression -> translateExpression(expression)
|
|
||||||
is PtArrayIndexer -> translateExpression(expression)
|
|
||||||
is PtTypeCast -> translateExpression(expression)
|
|
||||||
is PtAddressOf -> translateExpression(expression)
|
|
||||||
is PtMemoryByte -> asmgen.translateDirectMemReadExpressionToRegAorStack(expression, true)
|
|
||||||
is PtNumber -> translateExpression(expression)
|
|
||||||
is PtIdentifier -> translateExpression(expression)
|
|
||||||
is PtFunctionCall -> translateFunctionCallResultOntoStack(expression)
|
|
||||||
is PtBuiltinFunctionCall -> asmgen.translateBuiltinFunctionCallExpression(expression, true, null)
|
|
||||||
is PtContainmentCheck -> translateContainmentCheck(expression)
|
|
||||||
is PtArray, is PtString -> throw AssemblyError("string/array literal value assignment should have been replaced by a variable")
|
|
||||||
is PtRange -> throw AssemblyError("range expression should have been changed into array values")
|
|
||||||
is PtMachineRegister -> throw AssemblyError("machine register ast node should not occur in 6502 codegen it is for IR code")
|
|
||||||
else -> TODO("missing expression asmgen for $expression")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateContainmentCheck(check: PtContainmentCheck) {
|
|
||||||
asmgen.assignExpressionToRegister(check, RegisterOrPair.A)
|
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateFunctionCallResultOntoStack(call: PtFunctionCall) {
|
|
||||||
// only for use in nested expression evaluation
|
|
||||||
|
|
||||||
val symbol = asmgen.symbolTable.lookup(call.name)
|
|
||||||
val sub = symbol!!.astNode as IPtSubroutine
|
|
||||||
asmgen.saveXbeforeCall(call)
|
|
||||||
asmgen.translateFunctionCall(call)
|
|
||||||
if(sub.regXasResult()) {
|
|
||||||
// store the return value in X somewhere that we can access again below
|
|
||||||
asmgen.out(" stx P8ZP_SCRATCH_REG")
|
|
||||||
}
|
|
||||||
asmgen.restoreXafterCall(call)
|
|
||||||
|
|
||||||
val returns: List<Pair<RegisterOrStatusflag, DataType>> = sub.returnsWhatWhere()
|
|
||||||
for ((reg, _) in returns) {
|
|
||||||
// result value is in cpu or status registers, put it on the stack instead (as we're evaluating an expression tree)
|
|
||||||
if (reg.registerOrPair != null) {
|
|
||||||
when (reg.registerOrPair!!) {
|
|
||||||
RegisterOrPair.A -> asmgen.out(" sta P8ESTACK_LO,x | dex")
|
|
||||||
RegisterOrPair.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
|
||||||
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
|
||||||
RegisterOrPair.X -> asmgen.out(" lda P8ZP_SCRATCH_REG | sta P8ESTACK_LO,x | dex")
|
|
||||||
RegisterOrPair.AX -> asmgen.out(" sta P8ESTACK_LO,x | lda P8ZP_SCRATCH_REG | sta P8ESTACK_HI,x | dex")
|
|
||||||
RegisterOrPair.XY -> asmgen.out(" tya | sta P8ESTACK_HI,x | lda P8ZP_SCRATCH_REG | sta P8ESTACK_LO,x | dex")
|
|
||||||
RegisterOrPair.FAC1 -> asmgen.out(" jsr floats.push_fac1")
|
|
||||||
RegisterOrPair.FAC2 -> asmgen.out(" jsr floats.push_fac2")
|
|
||||||
RegisterOrPair.R0,
|
|
||||||
RegisterOrPair.R1,
|
|
||||||
RegisterOrPair.R2,
|
|
||||||
RegisterOrPair.R3,
|
|
||||||
RegisterOrPair.R4,
|
|
||||||
RegisterOrPair.R5,
|
|
||||||
RegisterOrPair.R6,
|
|
||||||
RegisterOrPair.R7,
|
|
||||||
RegisterOrPair.R8,
|
|
||||||
RegisterOrPair.R9,
|
|
||||||
RegisterOrPair.R10,
|
|
||||||
RegisterOrPair.R11,
|
|
||||||
RegisterOrPair.R12,
|
|
||||||
RegisterOrPair.R13,
|
|
||||||
RegisterOrPair.R14,
|
|
||||||
RegisterOrPair.R15 -> {
|
|
||||||
asmgen.out(
|
|
||||||
"""
|
|
||||||
lda cx16.${reg.registerOrPair.toString().lowercase()}
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
lda cx16.${reg.registerOrPair.toString().lowercase()}+1
|
|
||||||
sta P8ESTACK_HI,x
|
|
||||||
dex
|
|
||||||
""")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else when(reg.statusflag) {
|
|
||||||
Statusflag.Pc -> {
|
|
||||||
asmgen.out("""
|
|
||||||
lda #0
|
|
||||||
rol a
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
}
|
|
||||||
Statusflag.Pz -> {
|
|
||||||
asmgen.out("""
|
|
||||||
beq +
|
|
||||||
lda #0
|
|
||||||
beq ++
|
|
||||||
+ lda #1
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
}
|
|
||||||
Statusflag.Pv -> {
|
|
||||||
asmgen.out("""
|
|
||||||
bvs +
|
|
||||||
lda #0
|
|
||||||
beq ++
|
|
||||||
+ lda #1
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
}
|
|
||||||
Statusflag.Pn -> {
|
|
||||||
asmgen.out("""
|
|
||||||
bmi +
|
|
||||||
lda #0
|
|
||||||
beq ++
|
|
||||||
+ lda #1
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
}
|
|
||||||
null -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateExpression(typecast: PtTypeCast) {
|
|
||||||
translateExpressionInternal(typecast.value)
|
|
||||||
when(typecast.value.type) {
|
|
||||||
DataType.UBYTE, DataType.BOOL -> {
|
|
||||||
when(typecast.type) {
|
|
||||||
DataType.UBYTE, DataType.BYTE -> {}
|
|
||||||
DataType.UWORD, DataType.WORD -> {
|
|
||||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
|
||||||
asmgen.out(" stz P8ESTACK_HI+1,x")
|
|
||||||
else
|
|
||||||
asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x")
|
|
||||||
}
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.stack_ub2float")
|
|
||||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.BYTE -> {
|
|
||||||
when(typecast.type) {
|
|
||||||
DataType.UBYTE, DataType.BYTE -> {}
|
|
||||||
DataType.UWORD, DataType.WORD -> asmgen.signExtendStackLsb(DataType.BYTE)
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.stack_b2float")
|
|
||||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.UWORD -> {
|
|
||||||
when(typecast.type) {
|
|
||||||
DataType.BYTE, DataType.UBYTE -> {}
|
|
||||||
DataType.WORD, DataType.UWORD -> {}
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.stack_uw2float")
|
|
||||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.WORD -> {
|
|
||||||
when(typecast.type) {
|
|
||||||
DataType.BYTE, DataType.UBYTE -> {}
|
|
||||||
DataType.WORD, DataType.UWORD -> {}
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.stack_w2float")
|
|
||||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.FLOAT -> {
|
|
||||||
when(typecast.type) {
|
|
||||||
DataType.UBYTE -> asmgen.out(" jsr floats.stack_float2uw")
|
|
||||||
DataType.BYTE -> asmgen.out(" jsr floats.stack_float2w")
|
|
||||||
DataType.UWORD -> asmgen.out(" jsr floats.stack_float2uw")
|
|
||||||
DataType.WORD -> asmgen.out(" jsr floats.stack_float2w")
|
|
||||||
DataType.FLOAT -> {}
|
|
||||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.STR -> {
|
|
||||||
if (typecast.type != DataType.UWORD && typecast.type == DataType.STR)
|
|
||||||
throw AssemblyError("cannot typecast a string into another incompatitble type")
|
|
||||||
}
|
|
||||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast pass-by-reference value into another type")
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateExpression(expr: PtAddressOf) {
|
|
||||||
val name = asmgen.asmVariableName(expr.identifier)
|
|
||||||
asmgen.out(" lda #<$name | sta P8ESTACK_LO,x | lda #>$name | sta P8ESTACK_HI,x | dex")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateExpression(expr: PtNumber) {
|
|
||||||
when(expr.type) {
|
|
||||||
DataType.UBYTE, DataType.BYTE -> asmgen.out(" lda #${expr.number.toHex()} | sta P8ESTACK_LO,x | dex")
|
|
||||||
DataType.UWORD, DataType.WORD -> asmgen.out("""
|
|
||||||
lda #<${expr.number.toHex()}
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
lda #>${expr.number.toHex()}
|
|
||||||
sta P8ESTACK_HI,x
|
|
||||||
dex
|
|
||||||
""")
|
|
||||||
DataType.FLOAT -> {
|
|
||||||
val floatConst = allocator.getFloatAsmConst(expr.number)
|
|
||||||
asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateExpression(expr: PtIdentifier) {
|
|
||||||
val varname = asmgen.asmVariableName(expr)
|
|
||||||
when(expr.type) {
|
|
||||||
DataType.UBYTE, DataType.BYTE -> {
|
|
||||||
asmgen.out(" lda $varname | sta P8ESTACK_LO,x | dex")
|
|
||||||
}
|
|
||||||
DataType.UWORD, DataType.WORD -> {
|
|
||||||
asmgen.out(" lda $varname | sta P8ESTACK_LO,x | lda $varname+1 | sta P8ESTACK_HI,x | dex")
|
|
||||||
}
|
|
||||||
DataType.FLOAT -> {
|
|
||||||
asmgen.out(" lda #<$varname | ldy #>$varname| jsr floats.push_float")
|
|
||||||
}
|
|
||||||
in SplitWordArrayTypes -> {
|
|
||||||
throw AssemblyError("can't push address of split-word array ${expr.position}")
|
|
||||||
}
|
|
||||||
in IterableDatatypes -> {
|
|
||||||
asmgen.out(" lda #<$varname | sta P8ESTACK_LO,x | lda #>$varname | sta P8ESTACK_HI,x | dex")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("stack push weird variable type $expr")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateExpression(expr: PtBinaryExpression) {
|
|
||||||
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
|
|
||||||
if(translateSomewhatOptimized(expr.left, expr.operator, expr.right))
|
|
||||||
return
|
|
||||||
|
|
||||||
val leftDt = expr.left.type
|
|
||||||
val rightDt = expr.right.type
|
|
||||||
|
|
||||||
// compare with zero
|
|
||||||
if(expr.operator in ComparisonOperators) {
|
|
||||||
if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) {
|
|
||||||
val rightVal = expr.right.asConstInteger()
|
|
||||||
if(rightVal==0)
|
|
||||||
return translateComparisonWithZero(expr.left, leftDt, expr.operator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(leftDt==DataType.STR && rightDt==DataType.STR && expr.operator in ComparisonOperators)
|
|
||||||
return translateCompareStrings(expr.left, expr.operator, expr.right)
|
|
||||||
|
|
||||||
if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes)
|
|
||||||
|| (leftDt in WordDatatypes && rightDt !in WordDatatypes))
|
|
||||||
throw AssemblyError("binary operator ${expr.operator} left/right dt not identical")
|
|
||||||
|
|
||||||
// the general, non-optimized cases
|
|
||||||
// TODO optimize more cases.... (or one day just don't use the evalstack at all anymore)
|
|
||||||
translateExpressionInternal(expr.left)
|
|
||||||
translateExpressionInternal(expr.right)
|
|
||||||
when (leftDt) {
|
|
||||||
in ByteDatatypes -> translateBinaryOperatorBytes(expr.operator, leftDt)
|
|
||||||
in WordDatatypes -> translateBinaryOperatorWords(expr.operator, leftDt)
|
|
||||||
DataType.FLOAT -> translateBinaryOperatorFloats(expr.operator)
|
|
||||||
else -> throw AssemblyError("non-numerical datatype")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateSomewhatOptimized(left: PtExpression, operator: String, right: PtExpression): Boolean {
|
|
||||||
val leftDt = left.type
|
|
||||||
val rightDt = right.type
|
|
||||||
when(operator) {
|
|
||||||
"+" -> {
|
|
||||||
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
|
||||||
val leftVal = left.asConstInteger()
|
|
||||||
val rightVal = right.asConstInteger()
|
|
||||||
if (leftVal!=null && leftVal in -4..4) {
|
|
||||||
translateExpressionInternal(right)
|
|
||||||
if(rightDt in ByteDatatypes) {
|
|
||||||
val incdec = if(leftVal<0) "dec" else "inc"
|
|
||||||
repeat(leftVal.absoluteValue) {
|
|
||||||
asmgen.out(" $incdec P8ESTACK_LO+1,x")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// word
|
|
||||||
if(leftVal<0) {
|
|
||||||
repeat(leftVal.absoluteValue) {
|
|
||||||
asmgen.out("""
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
bne +
|
|
||||||
dec P8ESTACK_HI+1,x
|
|
||||||
+ dec P8ESTACK_LO+1,x""")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
repeat(leftVal) {
|
|
||||||
asmgen.out("""
|
|
||||||
inc P8ESTACK_LO+1,x
|
|
||||||
bne +
|
|
||||||
inc P8ESTACK_HI+1,x
|
|
||||||
+""")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
else if (rightVal!=null && rightVal in -4..4)
|
|
||||||
{
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
if(leftDt in ByteDatatypes) {
|
|
||||||
val incdec = if(rightVal<0) "dec" else "inc"
|
|
||||||
repeat(rightVal.absoluteValue) {
|
|
||||||
asmgen.out(" $incdec P8ESTACK_LO+1,x")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// word
|
|
||||||
if(rightVal<0) {
|
|
||||||
repeat(rightVal.absoluteValue) {
|
|
||||||
asmgen.out("""
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
bne +
|
|
||||||
dec P8ESTACK_HI+1,x
|
|
||||||
+ dec P8ESTACK_LO+1,x""")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
repeat(rightVal) {
|
|
||||||
asmgen.out("""
|
|
||||||
inc P8ESTACK_LO+1,x
|
|
||||||
bne +
|
|
||||||
inc P8ESTACK_HI+1,x
|
|
||||||
+""")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"-" -> {
|
|
||||||
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
|
||||||
val rightVal = right.asConstInteger()
|
|
||||||
if (rightVal!=null && rightVal in -4..4)
|
|
||||||
{
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
if(leftDt in ByteDatatypes) {
|
|
||||||
val incdec = if(rightVal<0) "inc" else "dec"
|
|
||||||
repeat(rightVal.absoluteValue) {
|
|
||||||
asmgen.out(" $incdec P8ESTACK_LO+1,x")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// word
|
|
||||||
if(rightVal>0) {
|
|
||||||
repeat(rightVal.absoluteValue) {
|
|
||||||
asmgen.out("""
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
bne +
|
|
||||||
dec P8ESTACK_HI+1,x
|
|
||||||
+ dec P8ESTACK_LO+1,x""")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
repeat(rightVal) {
|
|
||||||
asmgen.out("""
|
|
||||||
inc P8ESTACK_LO+1,x
|
|
||||||
bne +
|
|
||||||
inc P8ESTACK_HI+1,x
|
|
||||||
+""")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
">>" -> {
|
|
||||||
val amount = right.asConstInteger()
|
|
||||||
if(amount!=null) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
when (leftDt) {
|
|
||||||
DataType.UBYTE -> {
|
|
||||||
if (amount <= 2)
|
|
||||||
repeat(amount) { asmgen.out(" lsr P8ESTACK_LO+1,x") }
|
|
||||||
else {
|
|
||||||
asmgen.out(" lda P8ESTACK_LO+1,x")
|
|
||||||
repeat(amount) { asmgen.out(" lsr a") }
|
|
||||||
asmgen.out(" sta P8ESTACK_LO+1,x")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.BYTE -> {
|
|
||||||
if (amount <= 2)
|
|
||||||
repeat(amount) { asmgen.out(" lda P8ESTACK_LO+1,x | asl a | ror P8ESTACK_LO+1,x") }
|
|
||||||
else {
|
|
||||||
asmgen.out(" lda P8ESTACK_LO+1,x | sta P8ZP_SCRATCH_B1")
|
|
||||||
repeat(amount) { asmgen.out(" asl a | ror P8ZP_SCRATCH_B1 | lda P8ZP_SCRATCH_B1") }
|
|
||||||
asmgen.out(" sta P8ESTACK_LO+1,x")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.UWORD -> {
|
|
||||||
if(amount>=16) {
|
|
||||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
|
||||||
asmgen.out(" stz P8ESTACK_LO+1,x | stz P8ESTACK_HI+1,x")
|
|
||||||
else
|
|
||||||
asmgen.out(" lda #0 | sta P8ESTACK_LO+1,x | sta P8ESTACK_HI+1,x")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
var amountLeft = amount
|
|
||||||
while (amountLeft >= 7) {
|
|
||||||
asmgen.out(" jsr math.shift_right_uw_7")
|
|
||||||
amountLeft -= 7
|
|
||||||
}
|
|
||||||
if (amountLeft in 0..2)
|
|
||||||
repeat(amountLeft) { asmgen.out(" lsr P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
|
||||||
else
|
|
||||||
asmgen.out(" jsr math.shift_right_uw_$amountLeft")
|
|
||||||
}
|
|
||||||
DataType.WORD -> {
|
|
||||||
if(amount>=16) {
|
|
||||||
asmgen.out("""
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
bmi +
|
|
||||||
lda #0
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
beq ++
|
|
||||||
+ lda #255
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
+""")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
var amountLeft = amount
|
|
||||||
while (amountLeft >= 7) {
|
|
||||||
asmgen.out(" jsr math.shift_right_w_7")
|
|
||||||
amountLeft -= 7
|
|
||||||
}
|
|
||||||
if (amountLeft in 0..2)
|
|
||||||
repeat(amountLeft) { asmgen.out(" lda P8ESTACK_HI+1,x | asl a | ror P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
|
||||||
else
|
|
||||||
asmgen.out(" jsr math.shift_right_w_$amountLeft")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"<<" -> {
|
|
||||||
val amount = right.asConstInteger()
|
|
||||||
if(amount!=null) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
if (leftDt in ByteDatatypes) {
|
|
||||||
if (amount <= 2)
|
|
||||||
repeat(amount) { asmgen.out(" asl P8ESTACK_LO+1,x") }
|
|
||||||
else {
|
|
||||||
asmgen.out(" lda P8ESTACK_LO+1,x")
|
|
||||||
repeat(amount) { asmgen.out(" asl a") }
|
|
||||||
asmgen.out(" sta P8ESTACK_LO+1,x")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var amountLeft = amount
|
|
||||||
while (amountLeft >= 7) {
|
|
||||||
asmgen.out(" jsr math.shift_left_w_7")
|
|
||||||
amountLeft -= 7
|
|
||||||
}
|
|
||||||
if (amountLeft in 0..2)
|
|
||||||
repeat(amountLeft) { asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") }
|
|
||||||
else
|
|
||||||
asmgen.out(" jsr math.shift_left_w_$amountLeft")
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"*" -> {
|
|
||||||
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
|
||||||
val leftVar = left as? PtIdentifier
|
|
||||||
val rightVar = right as? PtIdentifier
|
|
||||||
if(leftVar!=null && rightVar!=null && leftVar==rightVar) {
|
|
||||||
translateSquared(leftVar, leftDt)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val value = right as? PtNumber
|
|
||||||
if(value!=null) {
|
|
||||||
if(rightDt in IntegerDatatypes) {
|
|
||||||
val amount = value.number.toInt()
|
|
||||||
if(amount==2) {
|
|
||||||
// optimize x*2 common case
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
if(leftDt in ByteDatatypes) {
|
|
||||||
asmgen.out(" asl P8ESTACK_LO+1,x")
|
|
||||||
} else {
|
|
||||||
asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x")
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
when(rightDt) {
|
|
||||||
DataType.UBYTE -> {
|
|
||||||
if(amount in asmgen.optimizedByteMultiplications) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
asmgen.out(" jsr math.stack_mul_byte_$amount")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.BYTE -> {
|
|
||||||
if(amount in asmgen.optimizedByteMultiplications) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
asmgen.out(" jsr math.stack_mul_byte_$amount")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if(amount.absoluteValue in asmgen.optimizedByteMultiplications) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
asmgen.out(" jsr prog8_lib.neg_b | jsr math.stack_mul_byte_${amount.absoluteValue}")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.UWORD -> {
|
|
||||||
if(amount in asmgen.optimizedWordMultiplications) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
asmgen.out(" jsr math.stack_mul_word_$amount")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataType.WORD -> {
|
|
||||||
if(amount in asmgen.optimizedWordMultiplications) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
asmgen.out(" jsr math.stack_mul_word_$amount")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if(amount.absoluteValue in asmgen.optimizedWordMultiplications) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
asmgen.out(" jsr prog8_lib.neg_w | jsr math.stack_mul_word_${amount.absoluteValue}")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"/" -> {
|
|
||||||
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
|
||||||
val rightVal = right.asConstInteger()
|
|
||||||
if(rightVal!=null && rightVal==2) {
|
|
||||||
translateExpressionInternal(left)
|
|
||||||
when (leftDt) {
|
|
||||||
DataType.UBYTE -> {
|
|
||||||
asmgen.out(" lsr P8ESTACK_LO+1,x")
|
|
||||||
}
|
|
||||||
DataType.UWORD -> {
|
|
||||||
asmgen.out(" lsr P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x")
|
|
||||||
}
|
|
||||||
DataType.BYTE -> {
|
|
||||||
// signed divide using shift needs adjusting of negative value to get correct rounding towards zero
|
|
||||||
asmgen.out("""
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
bpl +
|
|
||||||
inc P8ESTACK_LO+1,x
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
+ asl a
|
|
||||||
ror P8ESTACK_LO+1,x""")
|
|
||||||
}
|
|
||||||
DataType.WORD -> {
|
|
||||||
// signed divide using shift needs adjusting of negative value to get correct rounding towards zero
|
|
||||||
asmgen.out("""
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
bpl ++
|
|
||||||
inc P8ESTACK_LO+1,x
|
|
||||||
bne +
|
|
||||||
inc P8ESTACK_HI+1,x
|
|
||||||
+ lda P8ESTACK_HI+1,x
|
|
||||||
+ asl a
|
|
||||||
ror P8ESTACK_HI+1,x
|
|
||||||
ror P8ESTACK_LO+1,x""")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird dt")
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateComparisonWithZero(expr: PtExpression, dt: DataType, operator: String) {
|
|
||||||
if(expr.isSimple()) {
|
|
||||||
if(operator=="!=") {
|
|
||||||
when (dt) {
|
|
||||||
in ByteDatatypes -> {
|
|
||||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.A, dt == DataType.BYTE)
|
|
||||||
asmgen.out("""
|
|
||||||
beq +
|
|
||||||
lda #1
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
in WordDatatypes -> {
|
|
||||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, dt == DataType.WORD)
|
|
||||||
asmgen.out("""
|
|
||||||
sty P8ZP_SCRATCH_B1
|
|
||||||
ora P8ZP_SCRATCH_B1
|
|
||||||
beq +
|
|
||||||
lda #1
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
DataType.FLOAT -> {
|
|
||||||
asmgen.assignExpressionToRegister(expr, RegisterOrPair.FAC1, true)
|
|
||||||
asmgen.out("""
|
|
||||||
jsr floats.SIGN
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* operator == is not worth it to special case, the code is mostly larger */
|
|
||||||
}
|
|
||||||
translateExpressionInternal(expr)
|
|
||||||
when(operator) {
|
|
||||||
"==" -> {
|
|
||||||
when(dt) {
|
|
||||||
DataType.UBYTE, DataType.BYTE -> asmgen.out(" jsr prog8_lib.equalzero_b")
|
|
||||||
DataType.UWORD, DataType.WORD -> asmgen.out(" jsr prog8_lib.equalzero_w")
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.equal_zero")
|
|
||||||
else -> throw AssemblyError("wrong dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"!=" -> {
|
|
||||||
when(dt) {
|
|
||||||
DataType.UBYTE, DataType.BYTE -> asmgen.out(" jsr prog8_lib.notequalzero_b")
|
|
||||||
DataType.UWORD, DataType.WORD -> asmgen.out(" jsr prog8_lib.notequalzero_w")
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.notequal_zero")
|
|
||||||
else -> throw AssemblyError("wrong dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"<" -> {
|
|
||||||
if(dt==DataType.UBYTE || dt==DataType.UWORD)
|
|
||||||
return translateExpressionInternal(PtNumber.fromBoolean(false, expr.position))
|
|
||||||
when(dt) {
|
|
||||||
DataType.BYTE -> asmgen.out(" jsr prog8_lib.lesszero_b")
|
|
||||||
DataType.WORD -> asmgen.out(" jsr prog8_lib.lesszero_w")
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.less_zero")
|
|
||||||
else -> throw AssemblyError("wrong dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
">" -> {
|
|
||||||
when(dt) {
|
|
||||||
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.greaterzero_ub")
|
|
||||||
DataType.BYTE -> asmgen.out(" jsr prog8_lib.greaterzero_sb")
|
|
||||||
DataType.UWORD -> asmgen.out(" jsr prog8_lib.greaterzero_uw")
|
|
||||||
DataType.WORD -> asmgen.out(" jsr prog8_lib.greaterzero_sw")
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.greater_zero")
|
|
||||||
else -> throw AssemblyError("wrong dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"<=" -> {
|
|
||||||
when(dt) {
|
|
||||||
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.equalzero_b")
|
|
||||||
DataType.BYTE -> asmgen.out(" jsr prog8_lib.lessequalzero_sb")
|
|
||||||
DataType.UWORD -> asmgen.out(" jsr prog8_lib.equalzero_w")
|
|
||||||
DataType.WORD -> asmgen.out(" jsr prog8_lib.lessequalzero_sw")
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.lessequal_zero")
|
|
||||||
else -> throw AssemblyError("wrong dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
">=" -> {
|
|
||||||
if(dt==DataType.UBYTE || dt==DataType.UWORD)
|
|
||||||
return translateExpressionInternal(PtNumber.fromBoolean(true, expr.position))
|
|
||||||
when(dt) {
|
|
||||||
DataType.BYTE -> asmgen.out(" jsr prog8_lib.greaterequalzero_sb")
|
|
||||||
DataType.WORD -> asmgen.out(" jsr prog8_lib.greaterequalzero_sw")
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.greaterequal_zero")
|
|
||||||
else -> throw AssemblyError("wrong dt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("invalid comparison operator")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateSquared(variable: PtIdentifier, dt: DataType) {
|
|
||||||
val asmVar = asmgen.asmVariableName(variable)
|
|
||||||
when(dt) {
|
|
||||||
DataType.BYTE, DataType.UBYTE -> {
|
|
||||||
asmgen.out(" lda $asmVar")
|
|
||||||
asmgen.signExtendAYlsb(dt)
|
|
||||||
asmgen.out(" jsr math.square")
|
|
||||||
}
|
|
||||||
DataType.UWORD, DataType.WORD -> {
|
|
||||||
asmgen.out(" lda $asmVar | ldy $asmVar+1 | jsr math.square")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("require integer dt for square")
|
|
||||||
}
|
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateExpression(expr: PtPrefix) {
|
|
||||||
translateExpressionInternal(expr.value)
|
|
||||||
when(expr.operator) {
|
|
||||||
"+" -> {}
|
|
||||||
"-" -> {
|
|
||||||
when(expr.type) {
|
|
||||||
in ByteDatatypes -> asmgen.out(" jsr prog8_lib.neg_b")
|
|
||||||
in WordDatatypes -> asmgen.out(" jsr prog8_lib.neg_w")
|
|
||||||
DataType.FLOAT -> asmgen.out(" jsr floats.neg_f")
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"~" -> {
|
|
||||||
when(expr.type) {
|
|
||||||
in ByteDatatypes ->
|
|
||||||
asmgen.out("""
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
eor #255
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
""")
|
|
||||||
in WordDatatypes -> asmgen.out(" jsr prog8_lib.inv_word")
|
|
||||||
else -> throw AssemblyError("weird type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("invalid prefix operator ${expr.operator}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateExpression(arrayExpr: PtArrayIndexer) {
|
|
||||||
val elementDt = arrayExpr.type
|
|
||||||
val arrayVarName = asmgen.asmVariableName(arrayExpr.variable)
|
|
||||||
|
|
||||||
if(arrayExpr.variable.type==DataType.UWORD) {
|
|
||||||
// indexing a pointer var instead of a real array or string
|
|
||||||
if(elementDt !in ByteDatatypes)
|
|
||||||
throw AssemblyError("non-array var indexing requires bytes dt")
|
|
||||||
if(arrayExpr.index.type != DataType.UBYTE)
|
|
||||||
throw AssemblyError("non-array var indexing requires bytes index")
|
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.Y)
|
|
||||||
if(asmgen.isZpVar(arrayExpr.variable)) {
|
|
||||||
asmgen.out(" lda ($arrayVarName),y")
|
|
||||||
} else {
|
|
||||||
asmgen.out(" lda $arrayVarName | sta P8ZP_SCRATCH_W1 | lda $arrayVarName+1 | sta P8ZP_SCRATCH_W1+1")
|
|
||||||
asmgen.out(" lda (P8ZP_SCRATCH_W1),y")
|
|
||||||
}
|
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if(arrayExpr.splitWords)
|
|
||||||
TODO("split words expression ${arrayExpr.position}")
|
|
||||||
|
|
||||||
val constIndexNum = arrayExpr.index.asConstInteger()
|
|
||||||
if(constIndexNum!=null) {
|
|
||||||
val indexValue = constIndexNum * program.memsizer.memorySize(elementDt)
|
|
||||||
when(elementDt) {
|
|
||||||
in ByteDatatypes -> {
|
|
||||||
asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | dex")
|
|
||||||
}
|
|
||||||
in WordDatatypes -> {
|
|
||||||
asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | lda $arrayVarName+$indexValue+1 | sta P8ESTACK_HI,x | dex")
|
|
||||||
}
|
|
||||||
DataType.FLOAT -> {
|
|
||||||
asmgen.out(" lda #<($arrayVarName+$indexValue) | ldy #>($arrayVarName+$indexValue) | jsr floats.push_float")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird element type")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
when(elementDt) {
|
|
||||||
in ByteDatatypes -> {
|
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.Y)
|
|
||||||
asmgen.out(" lda $arrayVarName,y | sta P8ESTACK_LO,x | dex")
|
|
||||||
}
|
|
||||||
in WordDatatypes -> {
|
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.Y)
|
|
||||||
asmgen.out(" lda $arrayVarName,y | sta P8ESTACK_LO,x | lda $arrayVarName+1,y | sta P8ESTACK_HI,x | dex")
|
|
||||||
}
|
|
||||||
DataType.FLOAT -> {
|
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.A)
|
|
||||||
asmgen.out("""
|
|
||||||
ldy #>$arrayVarName
|
|
||||||
clc
|
|
||||||
adc #<$arrayVarName
|
|
||||||
bcc +
|
|
||||||
iny
|
|
||||||
+ jsr floats.push_float""")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird dt")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateBinaryOperatorBytes(operator: String, types: DataType) {
|
|
||||||
when(operator) {
|
|
||||||
"*" -> asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
|
||||||
"/" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
|
||||||
"%" -> {
|
|
||||||
if(types==DataType.BYTE)
|
|
||||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
|
||||||
asmgen.out(" jsr prog8_lib.remainder_ub")
|
|
||||||
}
|
|
||||||
"+" -> asmgen.out("""
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
inx
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
""")
|
|
||||||
"-" -> asmgen.out("""
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
inx
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
""")
|
|
||||||
"<<" -> asmgen.out(" jsr prog8_lib.shiftleft_b")
|
|
||||||
">>" -> asmgen.out(" jsr prog8_lib.shiftright_b")
|
|
||||||
"<" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.less_ub" else " jsr prog8_lib.less_b")
|
|
||||||
">" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.greater_ub" else " jsr prog8_lib.greater_b")
|
|
||||||
"<=" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.lesseq_ub" else " jsr prog8_lib.lesseq_b")
|
|
||||||
">=" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.greatereq_ub" else " jsr prog8_lib.greatereq_b")
|
|
||||||
"==" -> asmgen.out(" jsr prog8_lib.equal_b")
|
|
||||||
"!=" -> asmgen.out(" jsr prog8_lib.notequal_b")
|
|
||||||
"&" -> asmgen.out(" jsr prog8_lib.bitand_b")
|
|
||||||
"^" -> asmgen.out(" jsr prog8_lib.bitxor_b")
|
|
||||||
"|" -> asmgen.out(" jsr prog8_lib.bitor_b")
|
|
||||||
else -> throw AssemblyError("invalid operator $operator")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateBinaryOperatorWords(operator: String, dt: DataType) {
|
|
||||||
when(operator) {
|
|
||||||
"*" -> asmgen.out(" jsr prog8_lib.mul_word")
|
|
||||||
"/" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.idiv_uw" else " jsr prog8_lib.idiv_w")
|
|
||||||
"%" -> {
|
|
||||||
if(dt==DataType.WORD)
|
|
||||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
|
||||||
asmgen.out(" jsr prog8_lib.remainder_uw")
|
|
||||||
}
|
|
||||||
"+" -> asmgen.out(" jsr prog8_lib.add_w")
|
|
||||||
"-" -> asmgen.out(" jsr prog8_lib.sub_w")
|
|
||||||
"<<" -> asmgen.out(" jsr math.shift_left_w")
|
|
||||||
">>" -> {
|
|
||||||
if(dt==DataType.UWORD)
|
|
||||||
asmgen.out(" jsr math.shift_right_uw")
|
|
||||||
else
|
|
||||||
asmgen.out(" jsr math.shift_right_w")
|
|
||||||
}
|
|
||||||
"<" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.less_uw" else " jsr prog8_lib.less_w")
|
|
||||||
">" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.greater_uw" else " jsr prog8_lib.greater_w")
|
|
||||||
"<=" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.lesseq_uw" else " jsr prog8_lib.lesseq_w")
|
|
||||||
">=" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.greatereq_uw" else " jsr prog8_lib.greatereq_w")
|
|
||||||
"==" -> asmgen.out(" jsr prog8_lib.equal_w")
|
|
||||||
"!=" -> asmgen.out(" jsr prog8_lib.notequal_w")
|
|
||||||
"&" -> asmgen.out(" jsr prog8_lib.bitand_w")
|
|
||||||
"^" -> asmgen.out(" jsr prog8_lib.bitxor_w")
|
|
||||||
"|" -> asmgen.out(" jsr prog8_lib.bitor_w")
|
|
||||||
else -> throw AssemblyError("invalid operator $operator")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateBinaryOperatorFloats(operator: String) {
|
|
||||||
when(operator) {
|
|
||||||
"*" -> asmgen.out(" jsr floats.mul_f")
|
|
||||||
"/" -> asmgen.out(" jsr floats.div_f")
|
|
||||||
"+" -> asmgen.out(" jsr floats.add_f")
|
|
||||||
"-" -> asmgen.out(" jsr floats.sub_f")
|
|
||||||
"<" -> asmgen.out(" jsr floats.less_f")
|
|
||||||
">" -> asmgen.out(" jsr floats.greater_f")
|
|
||||||
"<=" -> asmgen.out(" jsr floats.lesseq_f")
|
|
||||||
">=" -> asmgen.out(" jsr floats.greatereq_f")
|
|
||||||
"==" -> asmgen.out(" jsr floats.equal_f")
|
|
||||||
"!=" -> asmgen.out(" jsr floats.notequal_f")
|
|
||||||
"%", "<<", ">>", "&", "^", "|" -> throw AssemblyError("requires integer datatype")
|
|
||||||
else -> throw AssemblyError("invalid operator $operator")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateCompareStrings(s1: PtExpression, operator: String, s2: PtExpression) {
|
|
||||||
asmgen.assignExpressionToVariable(s1, "prog8_lib.strcmp_expression._arg_s1", DataType.UWORD)
|
|
||||||
asmgen.assignExpressionToVariable(s2, "prog8_lib.strcmp_expression._arg_s2", DataType.UWORD)
|
|
||||||
asmgen.out(" jsr prog8_lib.strcmp_expression") // result of compare is in A
|
|
||||||
compareStringsProcessResultInA(operator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun compareStringsProcessResultInA(operator: String) {
|
|
||||||
when(operator) {
|
|
||||||
"==" -> asmgen.out(" and #1 | eor #1 | sta P8ESTACK_LO,x")
|
|
||||||
"!=" -> asmgen.out(" and #1 | sta P8ESTACK_LO,x")
|
|
||||||
"<=" -> asmgen.out("""
|
|
||||||
bpl +
|
|
||||||
lda #1
|
|
||||||
bne ++
|
|
||||||
+ lda #0
|
|
||||||
+ sta P8ESTACK_LO,x""")
|
|
||||||
">=" -> asmgen.out("""
|
|
||||||
bmi +
|
|
||||||
lda #1
|
|
||||||
bne ++
|
|
||||||
+ lda #0
|
|
||||||
+ sta P8ESTACK_LO,x""")
|
|
||||||
"<" -> asmgen.out("""
|
|
||||||
bmi +
|
|
||||||
lda #0
|
|
||||||
beq ++
|
|
||||||
+ lda #1
|
|
||||||
+ sta P8ESTACK_LO,x""")
|
|
||||||
">" -> asmgen.out("""
|
|
||||||
bpl +
|
|
||||||
lda #0
|
|
||||||
beq ++
|
|
||||||
+ lda #1
|
|
||||||
+ sta P8ESTACK_LO,x""")
|
|
||||||
}
|
|
||||||
asmgen.out(" dex")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,15 +6,6 @@ import prog8.code.ast.PtSub
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
|
||||||
|
|
||||||
internal fun IPtSubroutine.regXasResult(): Boolean =
|
|
||||||
(this is PtAsmSub) && this.returns.any { it.first.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
|
|
||||||
|
|
||||||
internal fun IPtSubroutine.shouldSaveX(): Boolean =
|
|
||||||
this.regXasResult() || (this is PtAsmSub && (CpuRegister.X in this.clobbers || regXasParam()))
|
|
||||||
|
|
||||||
internal fun PtAsmSub.regXasParam(): Boolean =
|
|
||||||
parameters.any { it.first.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
|
|
||||||
|
|
||||||
internal class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean)
|
internal class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean)
|
||||||
|
|
||||||
internal fun PtAsmSub.shouldKeepA(): KeepAresult {
|
internal fun PtAsmSub.shouldKeepA(): KeepAresult {
|
||||||
|
|
|
@ -11,42 +11,10 @@ import prog8.codegen.cpu6502.assignment.TargetStorageKind
|
||||||
internal class FunctionCallAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal) {
|
internal class FunctionCallAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal) {
|
||||||
|
|
||||||
internal fun translateFunctionCallStatement(stmt: PtFunctionCall) {
|
internal fun translateFunctionCallStatement(stmt: PtFunctionCall) {
|
||||||
saveXbeforeCall(stmt)
|
|
||||||
translateFunctionCall(stmt)
|
translateFunctionCall(stmt)
|
||||||
restoreXafterCall(stmt)
|
|
||||||
// just ignore any result values from the function call.
|
// just ignore any result values from the function call.
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun saveXbeforeCall(stmt: PtFunctionCall) {
|
|
||||||
val symbol = asmgen.symbolTable.lookup(stmt.name)
|
|
||||||
val sub = symbol!!.astNode as IPtSubroutine
|
|
||||||
if(sub.shouldSaveX()) {
|
|
||||||
if(sub is PtAsmSub) {
|
|
||||||
val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
|
||||||
if (regSaveOnStack)
|
|
||||||
asmgen.saveRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnEntry)
|
|
||||||
else
|
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingISub()!!)
|
|
||||||
} else
|
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingISub()!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun restoreXafterCall(stmt: PtFunctionCall) {
|
|
||||||
val symbol = asmgen.symbolTable.lookup(stmt.name)
|
|
||||||
val sub = symbol!!.astNode as IPtSubroutine
|
|
||||||
if(sub.shouldSaveX()) {
|
|
||||||
if(sub is PtAsmSub) {
|
|
||||||
val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
|
||||||
if (regSaveOnStack)
|
|
||||||
asmgen.restoreRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnReturn)
|
|
||||||
else
|
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
} else
|
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun optimizeIntArgsViaRegisters(sub: PtSub) =
|
internal fun optimizeIntArgsViaRegisters(sub: PtSub) =
|
||||||
(sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes)
|
(sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes)
|
||||||
|| (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes)
|
|| (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes)
|
||||||
|
|
|
@ -13,7 +13,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as
|
||||||
val targetIdent = stmt.target.identifier
|
val targetIdent = stmt.target.identifier
|
||||||
val targetMemory = stmt.target.memory
|
val targetMemory = stmt.target.memory
|
||||||
val targetArrayIdx = stmt.target.array
|
val targetArrayIdx = stmt.target.array
|
||||||
val scope = stmt.definingISub()
|
|
||||||
when {
|
when {
|
||||||
targetIdent!=null -> {
|
targetIdent!=null -> {
|
||||||
val what = asmgen.asmVariableName(targetIdent)
|
val what = asmgen.asmVariableName(targetIdent)
|
||||||
|
@ -76,7 +75,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as
|
||||||
dec ${asmArrayvarname}_msb+$constIndex
|
dec ${asmArrayvarname}_msb+$constIndex
|
||||||
+ dec ${asmArrayvarname}_lsb+$constIndex""")
|
+ dec ${asmArrayvarname}_lsb+$constIndex""")
|
||||||
} else {
|
} else {
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, scope!!)
|
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.X)
|
asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.X)
|
||||||
if(incr)
|
if(incr)
|
||||||
asmgen.out(" inc ${asmArrayvarname}_lsb,x | bne + | inc ${asmArrayvarname}_msb,x |+")
|
asmgen.out(" inc ${asmArrayvarname}_lsb,x | bne + | inc ${asmArrayvarname}_msb,x |+")
|
||||||
|
@ -86,7 +84,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as
|
||||||
bne +
|
bne +
|
||||||
dec ${asmArrayvarname}_msb,x
|
dec ${asmArrayvarname}_msb,x
|
||||||
+ dec ${asmArrayvarname}_lsb,x""")
|
+ dec ${asmArrayvarname}_lsb,x""")
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -113,7 +110,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, scope!!)
|
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.X)
|
asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.X)
|
||||||
when(elementDt) {
|
when(elementDt) {
|
||||||
in ByteDatatypes -> {
|
in ByteDatatypes -> {
|
||||||
|
@ -141,7 +137,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird array elt dt")
|
else -> throw AssemblyError("weird array elt dt")
|
||||||
}
|
}
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,6 @@ internal class ProgramAndVarsGen(
|
||||||
asmgen.out("P8ZP_SCRATCH_W1 = ${zp.SCRATCH_W1} ; word")
|
asmgen.out("P8ZP_SCRATCH_W1 = ${zp.SCRATCH_W1} ; word")
|
||||||
asmgen.out("P8ZP_SCRATCH_W2 = ${zp.SCRATCH_W2} ; word")
|
asmgen.out("P8ZP_SCRATCH_W2 = ${zp.SCRATCH_W2} ; word")
|
||||||
asmgen.out(".weak") // hack to allow user to override the following two with command line redefinition (however, just use '-esa' command line option instead!)
|
asmgen.out(".weak") // hack to allow user to override the following two with command line redefinition (however, just use '-esa' command line option instead!)
|
||||||
asmgen.out("P8ESTACK_LO = ${compTarget.machine.ESTACK_LO.toHex()}")
|
|
||||||
asmgen.out("P8ESTACK_HI = ${compTarget.machine.ESTACK_HI.toHex()}")
|
|
||||||
asmgen.out(".endweak")
|
asmgen.out(".endweak")
|
||||||
|
|
||||||
if(options.symbolDefs.isNotEmpty()) {
|
if(options.symbolDefs.isNotEmpty()) {
|
||||||
|
@ -371,12 +369,6 @@ internal class ProgramAndVarsGen(
|
||||||
else -> throw AssemblyError("weird dt for extravar $dt")
|
else -> throw AssemblyError("weird dt for extravar $dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(asmGenInfo.usedRegsaveA) // will probably never occur
|
|
||||||
asmgen.out("prog8_regsaveA .byte ?")
|
|
||||||
if(asmGenInfo.usedRegsaveX)
|
|
||||||
asmgen.out("prog8_regsaveX .byte ?")
|
|
||||||
if(asmGenInfo.usedRegsaveY)
|
|
||||||
asmgen.out("prog8_regsaveY .byte ?")
|
|
||||||
if(asmGenInfo.usedFloatEvalResultVar1)
|
if(asmGenInfo.usedFloatEvalResultVar1)
|
||||||
asmgen.out("$subroutineFloatEvalResultVar1 .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}")
|
asmgen.out("$subroutineFloatEvalResultVar1 .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}")
|
||||||
if(asmGenInfo.usedFloatEvalResultVar2)
|
if(asmGenInfo.usedFloatEvalResultVar2)
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
package prog8.codegen.cpu6502.assignment
|
||||||
|
|
||||||
|
import prog8.code.ast.PtBinaryExpression
|
||||||
|
import prog8.code.core.*
|
||||||
|
import prog8.codegen.cpu6502.AsmGen6502Internal
|
||||||
|
|
||||||
|
//
|
||||||
|
// This contains codegen for stack-based evaluation of binary expressions.
|
||||||
|
// It uses the CPU stack so depth is limited.
|
||||||
|
// It is called "as a last resort" if the optimized codegen path is unable
|
||||||
|
// to come up with a special case of the expression.
|
||||||
|
//
|
||||||
|
internal class AnyExprAsmGen(
|
||||||
|
private val asmgen: AsmGen6502Internal
|
||||||
|
) {
|
||||||
|
fun assignAnyExpressionUsingStack(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||||
|
when(expr.type) {
|
||||||
|
in ByteDatatypes -> {
|
||||||
|
if(expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes)
|
||||||
|
return assignByteBinExpr(expr, assign)
|
||||||
|
if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) {
|
||||||
|
require(expr.operator in ComparisonOperators)
|
||||||
|
TODO("words operands comparison -> byte")
|
||||||
|
}
|
||||||
|
if (expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) {
|
||||||
|
require(expr.operator in ComparisonOperators)
|
||||||
|
return assignFloatBinExpr(expr, assign)
|
||||||
|
}
|
||||||
|
TODO("weird expr operand types")
|
||||||
|
}
|
||||||
|
in WordDatatypes -> {
|
||||||
|
require(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) {
|
||||||
|
"both operands must be words"
|
||||||
|
}
|
||||||
|
return assignWordBinExpr(expr)
|
||||||
|
}
|
||||||
|
DataType.FLOAT -> {
|
||||||
|
require(expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) {
|
||||||
|
"both operands must be floats"
|
||||||
|
}
|
||||||
|
return assignFloatBinExpr(expr, assign)
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("weird expression type in assignment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assignWordBinExpr(expr: PtBinaryExpression): Boolean {
|
||||||
|
when(expr.operator) {
|
||||||
|
"+" -> {
|
||||||
|
TODO("word + at ${expr.position}")
|
||||||
|
}
|
||||||
|
"-" -> {
|
||||||
|
TODO("word - at ${expr.position}")
|
||||||
|
}
|
||||||
|
"*" -> {
|
||||||
|
TODO("word * at ${expr.position}")
|
||||||
|
}
|
||||||
|
"/" -> {
|
||||||
|
TODO("word / at ${expr.position}")
|
||||||
|
}
|
||||||
|
"<<" -> {
|
||||||
|
TODO("word << at ${expr.position}")
|
||||||
|
}
|
||||||
|
">>" -> {
|
||||||
|
TODO("word >> at ${expr.position}")
|
||||||
|
}
|
||||||
|
"%" -> {
|
||||||
|
TODO("word % at ${expr.position}")
|
||||||
|
}
|
||||||
|
"&", "and" -> {
|
||||||
|
TODO("word and at ${expr.position}")
|
||||||
|
}
|
||||||
|
"|", "or" -> {
|
||||||
|
TODO("word or at ${expr.position}")
|
||||||
|
}
|
||||||
|
"^", "xor" -> {
|
||||||
|
TODO("word xor at ${expr.position}")
|
||||||
|
}
|
||||||
|
"==" -> {
|
||||||
|
TODO("word == at ${expr.position}")
|
||||||
|
}
|
||||||
|
"!=" -> {
|
||||||
|
TODO("word != at ${expr.position}")
|
||||||
|
}
|
||||||
|
"<" -> {
|
||||||
|
TODO("word < at ${expr.position}")
|
||||||
|
}
|
||||||
|
"<=" -> {
|
||||||
|
TODO("word <= at ${expr.position}")
|
||||||
|
}
|
||||||
|
">" -> {
|
||||||
|
TODO("word > at ${expr.position}")
|
||||||
|
}
|
||||||
|
">=" -> {
|
||||||
|
TODO("word >= at ${expr.position}")
|
||||||
|
}
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assignByteBinExpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||||
|
when(expr.operator) {
|
||||||
|
"+" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||||
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||||
|
asmgen.out(" pla | clc | adc P8ZP_SCRATCH_B1")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"-" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||||
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||||
|
asmgen.out(" pla | sec | sbc P8ZP_SCRATCH_B1")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"*" -> {
|
||||||
|
TODO("byte * at ${expr.position}")
|
||||||
|
}
|
||||||
|
"/" -> {
|
||||||
|
TODO("byte / at ${expr.position}")
|
||||||
|
}
|
||||||
|
"<<" -> {
|
||||||
|
TODO("byte << at ${expr.position}")
|
||||||
|
}
|
||||||
|
">>" -> {
|
||||||
|
TODO("byte >> at ${expr.position}")
|
||||||
|
}
|
||||||
|
"%" -> {
|
||||||
|
TODO("byte % at ${expr.position}")
|
||||||
|
}
|
||||||
|
"&", "and" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||||
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||||
|
asmgen.out(" pla | and P8ZP_SCRATCH_B1")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"|", "or" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||||
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||||
|
asmgen.out(" pla | ora P8ZP_SCRATCH_B1")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"^", "xor" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||||
|
asmgen.out(" pha")
|
||||||
|
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||||
|
asmgen.out(" pla | eor P8ZP_SCRATCH_B1")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"==" -> {
|
||||||
|
TODO("byte == at ${expr.position}")
|
||||||
|
}
|
||||||
|
"!=" -> {
|
||||||
|
TODO("byte != at ${expr.position}")
|
||||||
|
}
|
||||||
|
"<" -> {
|
||||||
|
TODO("byte < at ${expr.position}")
|
||||||
|
}
|
||||||
|
"<=" -> {
|
||||||
|
TODO("byte <= at ${expr.position}")
|
||||||
|
}
|
||||||
|
">" -> {
|
||||||
|
TODO("byte > at ${expr.position}")
|
||||||
|
}
|
||||||
|
">=" -> {
|
||||||
|
TODO("byte >= at ${expr.position}")
|
||||||
|
}
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assignFloatBinExpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||||
|
when(expr.operator) {
|
||||||
|
"+" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true)
|
||||||
|
if(!expr.right.isSimple()) asmgen.pushFAC1()
|
||||||
|
asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC2, true)
|
||||||
|
if(!expr.right.isSimple()) asmgen.popFAC1()
|
||||||
|
asmgen.out(" jsr floats.FADDT")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.FAC1, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"-" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC1, true)
|
||||||
|
if(!expr.left.isSimple()) asmgen.pushFAC1()
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC2, true)
|
||||||
|
if(!expr.left.isSimple()) asmgen.popFAC1()
|
||||||
|
asmgen.out(" jsr floats.FSUBT")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.FAC1, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"*" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true)
|
||||||
|
if(!expr.right.isSimple()) asmgen.pushFAC1()
|
||||||
|
asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC2, true)
|
||||||
|
if(!expr.right.isSimple()) asmgen.popFAC1()
|
||||||
|
asmgen.out(" jsr floats.FMULTT")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.FAC1, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"/" -> {
|
||||||
|
asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC1, true)
|
||||||
|
if(!expr.left.isSimple()) asmgen.pushFAC1()
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC2, true)
|
||||||
|
if(!expr.left.isSimple()) asmgen.popFAC1()
|
||||||
|
asmgen.out(" jsr floats.FDIVT")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.FAC1, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"==" -> {
|
||||||
|
setupFloatComparisonFAC1vsVarAY(expr)
|
||||||
|
asmgen.out(" jsr floats.var_fac1_equal_f")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"!=" -> {
|
||||||
|
setupFloatComparisonFAC1vsVarAY(expr)
|
||||||
|
asmgen.out(" jsr floats.var_fac1_notequal_f")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"<" -> {
|
||||||
|
setupFloatComparisonFAC1vsVarAY(expr)
|
||||||
|
asmgen.out(" jsr floats.var_fac1_less_f")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
">" -> {
|
||||||
|
setupFloatComparisonFAC1vsVarAY(expr)
|
||||||
|
asmgen.out(" jsr floats.var_fac1_greater_f")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
"<=" -> {
|
||||||
|
setupFloatComparisonFAC1vsVarAY(expr)
|
||||||
|
asmgen.out(" jsr floats.var_fac1_lesseq_f")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
">=" -> {
|
||||||
|
setupFloatComparisonFAC1vsVarAY(expr)
|
||||||
|
asmgen.out(" jsr floats.var_fac1_greatereq_f")
|
||||||
|
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> TODO("float expression operator ${expr.operator}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupFloatComparisonFAC1vsVarAY(expr: PtBinaryExpression) {
|
||||||
|
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true)
|
||||||
|
if(!expr.right.isSimple()) asmgen.pushFAC1()
|
||||||
|
asmgen.assignExpressionToVariable(expr.right, "floats.floats_temp_var", DataType.FLOAT)
|
||||||
|
if(!expr.right.isSimple()) asmgen.popFAC1()
|
||||||
|
asmgen.out(" lda #<floats.floats_temp_var | ldy #>floats.floats_temp_var")
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,8 +10,7 @@ internal enum class TargetStorageKind {
|
||||||
VARIABLE,
|
VARIABLE,
|
||||||
ARRAY,
|
ARRAY,
|
||||||
MEMORY,
|
MEMORY,
|
||||||
REGISTER,
|
REGISTER
|
||||||
STACK
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum class SourceStorageKind {
|
internal enum class SourceStorageKind {
|
||||||
|
@ -20,7 +19,6 @@ internal enum class SourceStorageKind {
|
||||||
ARRAY,
|
ARRAY,
|
||||||
MEMORY,
|
MEMORY,
|
||||||
REGISTER,
|
REGISTER,
|
||||||
STACK, // value is already present on stack
|
|
||||||
EXPRESSION, // expression in ast-form, still to be evaluated
|
EXPRESSION, // expression in ast-form, still to be evaluated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +118,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||||
TargetStorageKind.MEMORY -> {
|
TargetStorageKind.MEMORY -> {
|
||||||
left isSameAs memory!!
|
left isSameAs memory!!
|
||||||
}
|
}
|
||||||
TargetStorageKind.REGISTER, TargetStorageKind.STACK -> {
|
TargetStorageKind.REGISTER -> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -81,7 +81,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value.expression!!)
|
inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in WordDatatypes -> {
|
in WordDatatypes -> {
|
||||||
|
@ -100,25 +99,47 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value.expression!!)
|
inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
when(value.kind) {
|
when(value.kind) {
|
||||||
SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, value.number!!.number, target.scope!!)
|
SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(
|
||||||
SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, value.asmVarname, target.scope!!)
|
target.asmVarname,
|
||||||
SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, regName(value), target.scope!!)
|
operator,
|
||||||
|
value.number!!.number
|
||||||
|
)
|
||||||
|
SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(
|
||||||
|
target.asmVarname,
|
||||||
|
operator,
|
||||||
|
value.asmVarname
|
||||||
|
)
|
||||||
|
SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(
|
||||||
|
target.asmVarname,
|
||||||
|
operator,
|
||||||
|
regName(value)
|
||||||
|
)
|
||||||
SourceStorageKind.MEMORY -> TODO("memread into float")
|
SourceStorageKind.MEMORY -> TODO("memread into float")
|
||||||
SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value.array!!, target.scope!!)
|
SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(
|
||||||
|
target.asmVarname,
|
||||||
|
operator,
|
||||||
|
value.array!!
|
||||||
|
)
|
||||||
SourceStorageKind.EXPRESSION -> {
|
SourceStorageKind.EXPRESSION -> {
|
||||||
if(value.expression is PtTypeCast) {
|
if(value.expression is PtTypeCast) {
|
||||||
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
|
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
|
||||||
inplaceModification_float_value_to_variable(target.asmVarname, operator, value.expression, target.scope!!)
|
inplaceModification_float_value_to_variable(
|
||||||
|
target.asmVarname,
|
||||||
|
operator,
|
||||||
|
value.expression
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
inplaceModification_float_value_to_variable(target.asmVarname, operator, value.expression!!, target.scope!!)
|
inplaceModification_float_value_to_variable(
|
||||||
|
target.asmVarname,
|
||||||
|
operator,
|
||||||
|
value.expression!!
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
|
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
|
||||||
|
@ -143,7 +164,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value.expression!!)
|
inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
|
@ -162,13 +182,13 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_byte_value_to_pointer(pointer, operator, value.expression!!)
|
inplaceModification_byte_value_to_pointer(pointer, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// TODO use some other evaluation here; don't use the estack to transfer the address to read/write from
|
asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.UWORD, memory.definingISub(), target.position, register = RegisterOrPair.AY))
|
||||||
asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingISub(), target.position))
|
asmgen.saveRegisterStack(CpuRegister.A, true)
|
||||||
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1")
|
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
||||||
|
asmgen.out(" jsr prog8_lib.read_byte_from_address_in_AY | sta P8ZP_SCRATCH_B1")
|
||||||
when(value.kind) {
|
when(value.kind) {
|
||||||
SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.number!!.number.toInt())
|
SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.number!!.number.toInt())
|
||||||
SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.asmVarname)
|
SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.asmVarname)
|
||||||
|
@ -182,9 +202,10 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.expression!!)
|
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
asmgen.out(" lda P8ZP_SCRATCH_B1 | jsr prog8_lib.write_byte_to_address_on_stack | inx")
|
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||||
|
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||||
|
asmgen.out(" ldx P8ZP_SCRATCH_B1 | jsr prog8_lib.write_byte_X_to_address_in_AY")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +234,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value.expression!!)
|
inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in WordDatatypes -> {
|
in WordDatatypes -> {
|
||||||
|
@ -231,25 +251,47 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value.expression!!)
|
inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
when(value.kind) {
|
when(value.kind) {
|
||||||
SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(targetVarName, operator, value.number!!.number, target.scope!!)
|
SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(
|
||||||
SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(targetVarName, operator, value.asmVarname, target.scope!!)
|
targetVarName,
|
||||||
SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(targetVarName, operator, regName(value), target.scope!!)
|
operator,
|
||||||
|
value.number!!.number
|
||||||
|
)
|
||||||
|
SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(
|
||||||
|
targetVarName,
|
||||||
|
operator,
|
||||||
|
value.asmVarname
|
||||||
|
)
|
||||||
|
SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(
|
||||||
|
targetVarName,
|
||||||
|
operator,
|
||||||
|
regName(value)
|
||||||
|
)
|
||||||
SourceStorageKind.MEMORY -> TODO("memread into float array")
|
SourceStorageKind.MEMORY -> TODO("memread into float array")
|
||||||
SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(targetVarName, operator, value.array!!, target.scope!!)
|
SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(
|
||||||
|
targetVarName,
|
||||||
|
operator,
|
||||||
|
value.array!!
|
||||||
|
)
|
||||||
SourceStorageKind.EXPRESSION -> {
|
SourceStorageKind.EXPRESSION -> {
|
||||||
if(value.expression is PtTypeCast) {
|
if(value.expression is PtTypeCast) {
|
||||||
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
|
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
|
||||||
inplaceModification_float_value_to_variable(targetVarName, operator, value.expression, target.scope!!)
|
inplaceModification_float_value_to_variable(
|
||||||
|
targetVarName,
|
||||||
|
operator,
|
||||||
|
value.expression
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
inplaceModification_float_value_to_variable(targetVarName, operator, value.expression!!, target.scope!!)
|
inplaceModification_float_value_to_variable(
|
||||||
|
targetVarName,
|
||||||
|
operator,
|
||||||
|
value.expression!!
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
|
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
|
||||||
|
@ -264,7 +306,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
return
|
return
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.UBYTE, CpuRegister.Y)
|
asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.UBYTE, CpuRegister.Y)
|
||||||
asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_B1")
|
asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_B1")
|
||||||
asmgen.saveRegisterLocal(CpuRegister.Y, target.scope!!)
|
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
||||||
when(value.kind) {
|
when(value.kind) {
|
||||||
SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.number!!.number.toInt())
|
SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.number!!.number.toInt())
|
||||||
SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.asmVarname)
|
SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.asmVarname)
|
||||||
|
@ -278,9 +320,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.expression!!)
|
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.Y)
|
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||||
asmgen.out(" lda P8ZP_SCRATCH_B1 | sta ${target.array.variable.name},y")
|
asmgen.out(" lda P8ZP_SCRATCH_B1 | sta ${target.array.variable.name},y")
|
||||||
}
|
}
|
||||||
in WordDatatypes -> {
|
in WordDatatypes -> {
|
||||||
|
@ -310,7 +351,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
inplaceModification_word_value_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression!!)
|
inplaceModification_word_value_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||||
if(target.array.splitWords) {
|
if(target.array.splitWords) {
|
||||||
|
@ -336,21 +376,44 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
ldy #>$tempvar
|
ldy #>$tempvar
|
||||||
jsr floats.copy_float""") // copy from array into float temp var, clobbers A,Y
|
jsr floats.copy_float""") // copy from array into float temp var, clobbers A,Y
|
||||||
when(value.kind) {
|
when(value.kind) {
|
||||||
SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(tempvar, operator, value.number!!.number, target.scope!!)
|
SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(
|
||||||
SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(tempvar, operator, value.asmVarname, target.scope!!)
|
tempvar,
|
||||||
SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(tempvar, operator, regName(value), target.scope!!)
|
operator,
|
||||||
|
value.number!!.number
|
||||||
|
)
|
||||||
|
SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(
|
||||||
|
tempvar,
|
||||||
|
operator,
|
||||||
|
value.asmVarname
|
||||||
|
)
|
||||||
|
SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(
|
||||||
|
tempvar,
|
||||||
|
operator,
|
||||||
|
regName(value)
|
||||||
|
)
|
||||||
SourceStorageKind.MEMORY -> TODO("memread into float")
|
SourceStorageKind.MEMORY -> TODO("memread into float")
|
||||||
SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(tempvar, operator, value.array!!, target.scope!!)
|
SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(
|
||||||
|
tempvar,
|
||||||
|
operator,
|
||||||
|
value.array!!
|
||||||
|
)
|
||||||
SourceStorageKind.EXPRESSION -> {
|
SourceStorageKind.EXPRESSION -> {
|
||||||
if(value.expression is PtTypeCast) {
|
if(value.expression is PtTypeCast) {
|
||||||
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
|
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
|
||||||
return
|
return
|
||||||
inplaceModification_float_value_to_variable(tempvar, operator, value.expression, target.scope!!)
|
inplaceModification_float_value_to_variable(
|
||||||
|
tempvar,
|
||||||
|
operator,
|
||||||
|
value.expression
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
inplaceModification_float_value_to_variable(tempvar, operator, value.expression!!, target.scope!!)
|
inplaceModification_float_value_to_variable(
|
||||||
|
tempvar,
|
||||||
|
operator,
|
||||||
|
value.expression!!
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird source type ${value.kind}")
|
|
||||||
}
|
}
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda P8ZP_SCRATCH_W1
|
lda P8ZP_SCRATCH_W1
|
||||||
|
@ -372,7 +435,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TargetStorageKind.REGISTER -> throw AssemblyError("no asm gen for reg in-place modification")
|
TargetStorageKind.REGISTER -> throw AssemblyError("no asm gen for reg in-place modification")
|
||||||
TargetStorageKind.STACK -> throw AssemblyError("no asm gen for stack in-place modification")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,8 +654,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inplaceModification_byte_value_to_variable(name: String, dt: DataType, operator: String, value: PtExpression) {
|
private fun inplaceModification_byte_value_to_variable(name: String, dt: DataType, operator: String, value: PtExpression) {
|
||||||
// this should be the last resort for code generation for this,
|
|
||||||
// because the value is evaluated onto the eval stack (=slow).
|
|
||||||
when (operator) {
|
when (operator) {
|
||||||
"+" -> {
|
"+" -> {
|
||||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
|
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||||
|
@ -1071,14 +1131,14 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
private fun inplaceModification_byte_memread_to_variable(name: String, dt: DataType, operator: String, memread: PtMemoryByte) {
|
private fun inplaceModification_byte_memread_to_variable(name: String, dt: DataType, operator: String, memread: PtMemoryByte) {
|
||||||
when (operator) {
|
when (operator) {
|
||||||
"+" -> {
|
"+" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
clc
|
clc
|
||||||
adc $name
|
adc $name
|
||||||
sta $name""")
|
sta $name""")
|
||||||
}
|
}
|
||||||
"-" -> {
|
"-" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
val tmpByte = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG"
|
val tmpByte = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG"
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sta $tmpByte
|
sta $tmpByte
|
||||||
|
@ -1088,15 +1148,15 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
sta $name""")
|
sta $name""")
|
||||||
}
|
}
|
||||||
"|" -> {
|
"|" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
asmgen.out(" ora $name | sta $name")
|
asmgen.out(" ora $name | sta $name")
|
||||||
}
|
}
|
||||||
"&" -> {
|
"&" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
asmgen.out(" and $name | sta $name")
|
asmgen.out(" and $name | sta $name")
|
||||||
}
|
}
|
||||||
"^" -> {
|
"^" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
asmgen.out(" eor $name | sta $name")
|
asmgen.out(" eor $name | sta $name")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -1108,7 +1168,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
private fun inplaceModification_word_memread_to_variable(name: String, dt: DataType, operator: String, memread: PtMemoryByte) {
|
private fun inplaceModification_word_memread_to_variable(name: String, dt: DataType, operator: String, memread: PtMemoryByte) {
|
||||||
when (operator) {
|
when (operator) {
|
||||||
"+" -> {
|
"+" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
clc
|
clc
|
||||||
adc $name
|
adc $name
|
||||||
|
@ -1118,7 +1178,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
+""")
|
+""")
|
||||||
}
|
}
|
||||||
"-" -> {
|
"-" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
val tmpByte = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG"
|
val tmpByte = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG"
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sta $tmpByte
|
sta $tmpByte
|
||||||
|
@ -1131,11 +1191,11 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
+""")
|
+""")
|
||||||
}
|
}
|
||||||
"|" -> {
|
"|" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
asmgen.out(" ora $name | sta $name")
|
asmgen.out(" ora $name | sta $name")
|
||||||
}
|
}
|
||||||
"&" -> {
|
"&" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
asmgen.out(" and $name | sta $name")
|
asmgen.out(" and $name | sta $name")
|
||||||
if(dt in WordDatatypes) {
|
if(dt in WordDatatypes) {
|
||||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||||
|
@ -1145,7 +1205,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"^" -> {
|
"^" -> {
|
||||||
asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||||
asmgen.out(" eor $name | sta $name")
|
asmgen.out(" eor $name | sta $name")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -1998,8 +2058,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inplaceModification_word_value_to_variable(name: String, dt: DataType, operator: String, value: PtExpression) {
|
private fun inplaceModification_word_value_to_variable(name: String, dt: DataType, operator: String, value: PtExpression) {
|
||||||
// this should be the last resort for code generation for this,
|
|
||||||
// because the value is evaluated onto the eval stack (=slow).
|
|
||||||
fun multiplyVarByWordInAY() {
|
fun multiplyVarByWordInAY() {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
|
@ -2286,9 +2344,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression, scope: IPtSubroutine) {
|
private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression) {
|
||||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.FAC1)
|
asmgen.assignExpressionToRegister(value, RegisterOrPair.FAC1)
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
|
||||||
when (operator) {
|
when (operator) {
|
||||||
"+" -> {
|
"+" -> {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
@ -2330,11 +2387,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr floats.MOVMF
|
jsr floats.MOVMF
|
||||||
""")
|
""")
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, otherName: String, scope: IPtSubroutine) {
|
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, otherName: String) {
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
|
||||||
when (operator) {
|
when (operator) {
|
||||||
"+" -> {
|
"+" -> {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
@ -2446,12 +2501,10 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr floats.MOVMF
|
jsr floats.MOVMF
|
||||||
""")
|
""")
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: IPtSubroutine) {
|
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) {
|
||||||
val constValueName = allocator.getFloatAsmConst(value)
|
val constValueName = allocator.getFloatAsmConst(value)
|
||||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
|
||||||
when (operator) {
|
when (operator) {
|
||||||
"+" -> {
|
"+" -> {
|
||||||
if (value == 0.0)
|
if (value == 0.0)
|
||||||
|
@ -2569,6 +2622,5 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr floats.MOVMF
|
jsr floats.MOVMF
|
||||||
""")
|
""")
|
||||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,8 +96,6 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
|
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
|
||||||
if (codeGen.options.slowCodegenWarnings)
|
|
||||||
codeGen.errors.warn("indirect code for in-place assignment", origAssign.position)
|
|
||||||
val value: PtExpression
|
val value: PtExpression
|
||||||
if(origAssign.operator in PrefixOperators) {
|
if(origAssign.operator in PrefixOperators) {
|
||||||
value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position)
|
value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position)
|
||||||
|
|
|
@ -24,10 +24,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||||
"popw" -> funcPopw(call)
|
"popw" -> funcPopw(call)
|
||||||
"push" -> funcPush(call)
|
"push" -> funcPush(call)
|
||||||
"pushw" -> funcPushw(call)
|
"pushw" -> funcPushw(call)
|
||||||
"rsave",
|
"rsave", "rrestore" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore
|
||||||
"rsavex",
|
|
||||||
"rrestore",
|
|
||||||
"rrestorex" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore
|
|
||||||
"callfar" -> funcCallfar(call)
|
"callfar" -> funcCallfar(call)
|
||||||
"msb" -> funcMsb(call)
|
"msb" -> funcMsb(call)
|
||||||
"lsb" -> funcLsb(call)
|
"lsb" -> funcLsb(call)
|
||||||
|
|
|
@ -29,9 +29,6 @@ class IRCodeGen(
|
||||||
irSymbolTable = IRSymbolTable(symbolTable)
|
irSymbolTable = IRSymbolTable(symbolTable)
|
||||||
val irProg = IRProgram(program.name, irSymbolTable, options, program.encoding)
|
val irProg = IRProgram(program.name, irSymbolTable, options, program.encoding)
|
||||||
|
|
||||||
if(options.evalStackBaseAddress!=null)
|
|
||||||
throw AssemblyError("IR doesn't use eval-stack")
|
|
||||||
|
|
||||||
// collect global variables initializers
|
// collect global variables initializers
|
||||||
program.allBlocks().forEach {
|
program.allBlocks().forEach {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
package prog8.optimizer
|
|
||||||
|
|
||||||
import prog8.ast.IStatementContainer
|
|
||||||
import prog8.ast.Node
|
|
||||||
import prog8.ast.Program
|
|
||||||
import prog8.ast.expressions.BinaryExpression
|
|
||||||
import prog8.ast.statements.AssignTarget
|
|
||||||
import prog8.ast.statements.Assignment
|
|
||||||
import prog8.ast.statements.AssignmentOrigin
|
|
||||||
import prog8.ast.walk.AstWalker
|
|
||||||
import prog8.ast.walk.IAstModification
|
|
||||||
import prog8.code.core.AugmentAssignmentOperators
|
|
||||||
import prog8.code.core.CompilationOptions
|
|
||||||
import prog8.code.core.DataType
|
|
||||||
import prog8.code.target.VMTarget
|
|
||||||
|
|
||||||
|
|
||||||
class BinExprSplitter(private val program: Program, private val options: CompilationOptions) : AstWalker() {
|
|
||||||
|
|
||||||
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
|
||||||
|
|
||||||
if(options.compTarget.name == VMTarget.NAME)
|
|
||||||
return noModifications // don't split expressions when targeting the vm codegen, it handles nested expressions well
|
|
||||||
|
|
||||||
if(assignment.value.inferType(program) istype DataType.FLOAT && !options.optimizeFloatExpressions)
|
|
||||||
return noModifications
|
|
||||||
|
|
||||||
val binExpr = assignment.value as? BinaryExpression
|
|
||||||
if (binExpr != null) {
|
|
||||||
|
|
||||||
if(binExpr.operator in AugmentAssignmentOperators && isSimpleTarget(assignment.target)) {
|
|
||||||
if(assignment.target isSameAs binExpr.right)
|
|
||||||
return noModifications
|
|
||||||
if(assignment.target isSameAs binExpr.left) {
|
|
||||||
if(binExpr.right.isSimple)
|
|
||||||
return noModifications
|
|
||||||
val leftBx = binExpr.left as? BinaryExpression
|
|
||||||
if(leftBx!=null && (!leftBx.left.isSimple || !leftBx.right.isSimple))
|
|
||||||
return noModifications
|
|
||||||
val rightBx = binExpr.right as? BinaryExpression
|
|
||||||
if(rightBx!=null && (!rightBx.left.isSimple || !rightBx.right.isSimple))
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
if(binExpr.right.isSimple) {
|
|
||||||
val firstAssign = Assignment(assignment.target.copy(), binExpr.left, AssignmentOrigin.OPTIMIZER, binExpr.left.position)
|
|
||||||
val targetExpr = assignment.target.toExpression()
|
|
||||||
val augExpr = BinaryExpression(targetExpr, binExpr.operator, binExpr.right, binExpr.right.position)
|
|
||||||
return listOf(
|
|
||||||
IAstModification.ReplaceNode(binExpr, augExpr, assignment),
|
|
||||||
IAstModification.InsertBefore(assignment, firstAssign, assignment.parent as IStatementContainer)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Further unraveling of binary expressions is really complicated here and
|
|
||||||
// often results in much bigger code, thereby defeating the purpose a bit.
|
|
||||||
// All in all this should probably be fixed in a better code generation backend
|
|
||||||
// that doesn't require this at all.
|
|
||||||
}
|
|
||||||
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSimpleTarget(target: AssignTarget) =
|
|
||||||
if (target.identifier!=null || target.memoryAddress!=null)
|
|
||||||
!target.isIOAddress(options.compTarget.machine)
|
|
||||||
else
|
|
||||||
false
|
|
||||||
|
|
||||||
}
|
|
|
@ -235,6 +235,47 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(rightconst!=null && (expr.operator=="<<" || expr.operator==">>")) {
|
||||||
|
val dt = expr.left.inferType(program)
|
||||||
|
if(dt.isBytes && rightconst.number>=8) {
|
||||||
|
if(dt.istype(DataType.UBYTE)) {
|
||||||
|
val zeroUB = NumericLiteral(DataType.UBYTE, 0.0, expr.position)
|
||||||
|
modifications.add(IAstModification.ReplaceNode(expr, zeroUB, parent))
|
||||||
|
} else {
|
||||||
|
if(leftconst!=null) {
|
||||||
|
val zeroB = NumericLiteral(DataType.BYTE, 0.0, expr.position)
|
||||||
|
val minusoneB = NumericLiteral(DataType.BYTE, -1.0, expr.position)
|
||||||
|
if(leftconst.number<0.0) {
|
||||||
|
if(expr.operator=="<<")
|
||||||
|
modifications.add(IAstModification.ReplaceNode(expr, zeroB, parent))
|
||||||
|
else
|
||||||
|
modifications.add(IAstModification.ReplaceNode(expr, minusoneB, parent))
|
||||||
|
} else {
|
||||||
|
modifications.add(IAstModification.ReplaceNode(expr, zeroB, parent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(dt.isWords && rightconst.number>=16) {
|
||||||
|
if(dt.istype(DataType.UWORD)) {
|
||||||
|
val zeroUW = NumericLiteral(DataType.UWORD, 0.0, expr.position)
|
||||||
|
modifications.add(IAstModification.ReplaceNode(expr, zeroUW, parent))
|
||||||
|
} else {
|
||||||
|
if(leftconst!=null) {
|
||||||
|
val zeroW = NumericLiteral(DataType.WORD, 0.0, expr.position)
|
||||||
|
val minusoneW = NumericLiteral(DataType.WORD, -1.0, expr.position)
|
||||||
|
if(leftconst.number<0.0) {
|
||||||
|
if(expr.operator=="<<")
|
||||||
|
modifications.add(IAstModification.ReplaceNode(expr, zeroW, parent))
|
||||||
|
else
|
||||||
|
modifications.add(IAstModification.ReplaceNode(expr, minusoneW, parent))
|
||||||
|
} else {
|
||||||
|
modifications.add(IAstModification.ReplaceNode(expr, zeroW, parent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return modifications
|
return modifications
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,9 +65,3 @@ fun Program.simplifyExpressions(errors: IErrorReporter, target: ICompilationTarg
|
||||||
opti.visit(this)
|
opti.visit(this)
|
||||||
return opti.applyModifications()
|
return opti.applyModifications()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Program.splitBinaryExpressions(options: CompilationOptions) : Int {
|
|
||||||
val opti = BinExprSplitter(this, options)
|
|
||||||
opti.visit(this)
|
|
||||||
return opti.applyModifications()
|
|
||||||
}
|
|
||||||
|
|
|
@ -111,8 +111,6 @@ class StatementOptimizer(private val program: Program,
|
||||||
// remove obvious dangling elses (else after a return)
|
// remove obvious dangling elses (else after a return)
|
||||||
if(ifElse.elsepart.isNotEmpty() && ifElse.truepart.statements.singleOrNull() is Return) {
|
if(ifElse.elsepart.isNotEmpty() && ifElse.truepart.statements.singleOrNull() is Return) {
|
||||||
val elsePart = AnonymousScope(ifElse.elsepart.statements, ifElse.elsepart.position)
|
val elsePart = AnonymousScope(ifElse.elsepart.statements, ifElse.elsepart.position)
|
||||||
if(options.slowCodegenWarnings)
|
|
||||||
errors.warn("else can be omitted", ifElse.elsepart.position)
|
|
||||||
return listOf(
|
return listOf(
|
||||||
IAstModification.ReplaceNode(ifElse.elsepart, AnonymousScope(mutableListOf(), ifElse.elsepart.position), ifElse),
|
IAstModification.ReplaceNode(ifElse.elsepart, AnonymousScope(mutableListOf(), ifElse.elsepart.position), ifElse),
|
||||||
IAstModification.InsertAfter(ifElse, elsePart, parent as IStatementContainer)
|
IAstModification.InsertAfter(ifElse, elsePart, parent as IStatementContainer)
|
||||||
|
|
|
@ -153,10 +153,9 @@ asmsub print (str text @ AY) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
asmsub print_ub0 (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
pha
|
pha
|
||||||
tya
|
tya
|
||||||
|
@ -164,16 +163,13 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||||
pla
|
pla
|
||||||
jsr chrout
|
jsr chrout
|
||||||
txa
|
txa
|
||||||
jsr chrout
|
jmp chrout
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ub (ubyte value @ A) clobbers(A,Y) {
|
asmsub print_ub (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in decimal form, without left padding 0s
|
; ---- print the ubyte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
_print_byte_digits
|
_print_byte_digits
|
||||||
pha
|
pha
|
||||||
|
@ -189,16 +185,13 @@ _print_byte_digits
|
||||||
beq _ones
|
beq _ones
|
||||||
jsr chrout
|
jsr chrout
|
||||||
_ones txa
|
_ones txa
|
||||||
jsr chrout
|
jmp chrout
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_b (byte value @ A) clobbers(A,Y) {
|
asmsub print_b (byte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the byte in A in decimal form, without left padding 0s
|
; ---- print the byte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
pha
|
pha
|
||||||
cmp #0
|
cmp #0
|
||||||
bpl +
|
bpl +
|
||||||
|
@ -210,10 +203,9 @@ asmsub print_b (byte value @ A) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc +
|
bcc +
|
||||||
pha
|
pha
|
||||||
lda #'$'
|
lda #'$'
|
||||||
|
@ -222,16 +214,13 @@ asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
+ jsr conv.ubyte2hex
|
+ jsr conv.ubyte2hex
|
||||||
jsr chrout
|
jsr chrout
|
||||||
tya
|
tya
|
||||||
jsr chrout
|
jmp chrout
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
bcc +
|
bcc +
|
||||||
lda #'%'
|
lda #'%'
|
||||||
|
@ -244,12 +233,11 @@ asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
+ jsr chrout
|
+ jsr chrout
|
||||||
dey
|
dey
|
||||||
bne -
|
bne -
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
pha
|
pha
|
||||||
|
@ -261,7 +249,7 @@ asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
||||||
; (if Carry is set, a radix prefix '$' is printed as well)
|
; (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
|
@ -274,10 +262,9 @@ asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
asmsub print_uw0 (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
|
@ -285,17 +272,14 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||||
jsr chrout
|
jsr chrout
|
||||||
iny
|
iny
|
||||||
bne -
|
bne -
|
||||||
+ ldx P8ZP_SCRATCH_REG
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uw (uword value @ AY) clobbers(A,Y) {
|
asmsub print_uw (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
beq _allzero
|
beq _allzero
|
||||||
|
@ -316,7 +300,7 @@ _allzero
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_w (word value @ AY) clobbers(A,Y) {
|
asmsub print_w (word value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
||||||
%asm {{
|
%asm {{
|
||||||
cpy #0
|
cpy #0
|
||||||
|
@ -388,7 +372,7 @@ sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) {
|
asmsub plot (ubyte col @ Y, ubyte row @ A) {
|
||||||
; ---- set cursor at specific position
|
; ---- set cursor at specific position
|
||||||
; TODO
|
; TODO
|
||||||
%asm {{
|
%asm {{
|
||||||
|
|
|
@ -104,34 +104,26 @@ romsub $FFF3 = IOBASE() -> uword @ XY ; read base addr
|
||||||
|
|
||||||
; ---- utilities -----
|
; ---- utilities -----
|
||||||
|
|
||||||
asmsub STOP2() -> ubyte @A {
|
asmsub STOP2() clobbers(X) -> ubyte @A {
|
||||||
; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag.
|
; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag.
|
||||||
%asm {{
|
%asm {{
|
||||||
txa
|
|
||||||
pha
|
|
||||||
jsr cbm.STOP
|
jsr cbm.STOP
|
||||||
beq +
|
beq +
|
||||||
pla
|
|
||||||
tax
|
|
||||||
lda #0
|
lda #0
|
||||||
rts
|
rts
|
||||||
+ pla
|
+ lda #1
|
||||||
tax
|
|
||||||
lda #1
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub RDTIM16() -> uword @AY {
|
asmsub RDTIM16() clobbers(X) -> uword @AY {
|
||||||
; -- like RDTIM() but only returning the lower 16 bits in AY for convenience
|
; -- like RDTIM() but only returning the lower 16 bits in AY for convenience
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr cbm.RDTIM
|
jsr cbm.RDTIM
|
||||||
pha
|
pha
|
||||||
txa
|
txa
|
||||||
tay
|
tay
|
||||||
pla
|
pla
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -446,10 +438,6 @@ _irq_handler_init
|
||||||
sta IRQ_SCRATCH_ZPWORD2
|
sta IRQ_SCRATCH_ZPWORD2
|
||||||
lda P8ZP_SCRATCH_W2+1
|
lda P8ZP_SCRATCH_W2+1
|
||||||
sta IRQ_SCRATCH_ZPWORD2+1
|
sta IRQ_SCRATCH_ZPWORD2+1
|
||||||
; Set X to the bottom 32 bytes of the evaluation stack, to HOPEFULLY not clobber it.
|
|
||||||
; This leaves 128-32=96 stack entries for the main program, and 32 stack entries for the IRQ handler.
|
|
||||||
; We assume IRQ handlers don't contain complex expressions taking up more than that.
|
|
||||||
ldx #32
|
|
||||||
cld
|
cld
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
@ -774,111 +762,108 @@ cx16 {
|
||||||
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
||||||
; they are simulated on the C128 as well but their location in memory is different
|
; they are simulated on the C128 as well but their location in memory is different
|
||||||
; (because there's no room for them in the zeropage)
|
; (because there's no room for them in the zeropage)
|
||||||
; $1300-$1bff is unused RAM on C128. We'll use $1a00-$1bff as the lo/hi evalstack.
|
; $1300-$1bff is unused RAM on C128.
|
||||||
; the virtual registers are allocated at the bottom of the eval-stack (should be ample space unless
|
&uword r0 = $1be0
|
||||||
; you're doing insane nesting of expressions...)
|
&uword r1 = $1be2
|
||||||
; NOTE: the memory location of these registers can change based on the "-esa" compiler option
|
&uword r2 = $1be4
|
||||||
&uword r0 = $1b00
|
&uword r3 = $1be6
|
||||||
&uword r1 = $1b02
|
&uword r4 = $1be8
|
||||||
&uword r2 = $1b04
|
&uword r5 = $1bea
|
||||||
&uword r3 = $1b06
|
&uword r6 = $1bec
|
||||||
&uword r4 = $1b08
|
&uword r7 = $1bee
|
||||||
&uword r5 = $1b0a
|
&uword r8 = $1bf0
|
||||||
&uword r6 = $1b0c
|
&uword r9 = $1bf2
|
||||||
&uword r7 = $1b0e
|
&uword r10 = $1bf4
|
||||||
&uword r8 = $1b10
|
&uword r11 = $1bf6
|
||||||
&uword r9 = $1b12
|
&uword r12 = $1bf8
|
||||||
&uword r10 = $1b14
|
&uword r13 = $1bfa
|
||||||
&uword r11 = $1b16
|
&uword r14 = $1bfc
|
||||||
&uword r12 = $1b18
|
&uword r15 = $1bfe
|
||||||
&uword r13 = $1b1a
|
|
||||||
&uword r14 = $1b1c
|
|
||||||
&uword r15 = $1b1e
|
|
||||||
|
|
||||||
&word r0s = $1b00
|
&word r0s = $1be0
|
||||||
&word r1s = $1b02
|
&word r1s = $1be2
|
||||||
&word r2s = $1b04
|
&word r2s = $1be4
|
||||||
&word r3s = $1b06
|
&word r3s = $1be6
|
||||||
&word r4s = $1b08
|
&word r4s = $1be8
|
||||||
&word r5s = $1b0a
|
&word r5s = $1bea
|
||||||
&word r6s = $1b0c
|
&word r6s = $1bec
|
||||||
&word r7s = $1b0e
|
&word r7s = $1bee
|
||||||
&word r8s = $1b10
|
&word r8s = $1bf0
|
||||||
&word r9s = $1b12
|
&word r9s = $1bf2
|
||||||
&word r10s = $1b14
|
&word r10s = $1bf4
|
||||||
&word r11s = $1b16
|
&word r11s = $1bf6
|
||||||
&word r12s = $1b18
|
&word r12s = $1bf8
|
||||||
&word r13s = $1b1a
|
&word r13s = $1bfa
|
||||||
&word r14s = $1b1c
|
&word r14s = $1bfc
|
||||||
&word r15s = $1b1e
|
&word r15s = $1bfe
|
||||||
|
|
||||||
&ubyte r0L = $1b00
|
&ubyte r0L = $1be0
|
||||||
&ubyte r1L = $1b02
|
&ubyte r1L = $1be2
|
||||||
&ubyte r2L = $1b04
|
&ubyte r2L = $1be4
|
||||||
&ubyte r3L = $1b06
|
&ubyte r3L = $1be6
|
||||||
&ubyte r4L = $1b08
|
&ubyte r4L = $1be8
|
||||||
&ubyte r5L = $1b0a
|
&ubyte r5L = $1bea
|
||||||
&ubyte r6L = $1b0c
|
&ubyte r6L = $1bec
|
||||||
&ubyte r7L = $1b0e
|
&ubyte r7L = $1bee
|
||||||
&ubyte r8L = $1b10
|
&ubyte r8L = $1bf0
|
||||||
&ubyte r9L = $1b12
|
&ubyte r9L = $1bf2
|
||||||
&ubyte r10L = $1b14
|
&ubyte r10L = $1bf4
|
||||||
&ubyte r11L = $1b16
|
&ubyte r11L = $1bf6
|
||||||
&ubyte r12L = $1b18
|
&ubyte r12L = $1bf8
|
||||||
&ubyte r13L = $1b1a
|
&ubyte r13L = $1bfa
|
||||||
&ubyte r14L = $1b1c
|
&ubyte r14L = $1bfc
|
||||||
&ubyte r15L = $1b1e
|
&ubyte r15L = $1bfe
|
||||||
|
|
||||||
&ubyte r0H = $1b01
|
&ubyte r0H = $1be1
|
||||||
&ubyte r1H = $1b03
|
&ubyte r1H = $1be3
|
||||||
&ubyte r2H = $1b05
|
&ubyte r2H = $1be5
|
||||||
&ubyte r3H = $1b07
|
&ubyte r3H = $1be7
|
||||||
&ubyte r4H = $1b09
|
&ubyte r4H = $1be9
|
||||||
&ubyte r5H = $1b0b
|
&ubyte r5H = $1beb
|
||||||
&ubyte r6H = $1b0d
|
&ubyte r6H = $1bed
|
||||||
&ubyte r7H = $1b0f
|
&ubyte r7H = $1bef
|
||||||
&ubyte r8H = $1b11
|
&ubyte r8H = $1bf1
|
||||||
&ubyte r9H = $1b13
|
&ubyte r9H = $1bf3
|
||||||
&ubyte r10H = $1b15
|
&ubyte r10H = $1bf5
|
||||||
&ubyte r11H = $1b17
|
&ubyte r11H = $1bf7
|
||||||
&ubyte r12H = $1b19
|
&ubyte r12H = $1bf9
|
||||||
&ubyte r13H = $1b1b
|
&ubyte r13H = $1bfb
|
||||||
&ubyte r14H = $1b1d
|
&ubyte r14H = $1bfd
|
||||||
&ubyte r15H = $1b1f
|
&ubyte r15H = $1bff
|
||||||
|
|
||||||
&byte r0sL = $1b00
|
&byte r0sL = $1be0
|
||||||
&byte r1sL = $1b02
|
&byte r1sL = $1be2
|
||||||
&byte r2sL = $1b04
|
&byte r2sL = $1be4
|
||||||
&byte r3sL = $1b06
|
&byte r3sL = $1be6
|
||||||
&byte r4sL = $1b08
|
&byte r4sL = $1be8
|
||||||
&byte r5sL = $1b0a
|
&byte r5sL = $1bea
|
||||||
&byte r6sL = $1b0c
|
&byte r6sL = $1bec
|
||||||
&byte r7sL = $1b0e
|
&byte r7sL = $1bee
|
||||||
&byte r8sL = $1b10
|
&byte r8sL = $1bf0
|
||||||
&byte r9sL = $1b12
|
&byte r9sL = $1bf2
|
||||||
&byte r10sL = $1b14
|
&byte r10sL = $1bf4
|
||||||
&byte r11sL = $1b16
|
&byte r11sL = $1bf6
|
||||||
&byte r12sL = $1b18
|
&byte r12sL = $1bf8
|
||||||
&byte r13sL = $1b1a
|
&byte r13sL = $1bfa
|
||||||
&byte r14sL = $1b1c
|
&byte r14sL = $1bfc
|
||||||
&byte r15sL = $1b1e
|
&byte r15sL = $1bfe
|
||||||
|
|
||||||
&byte r0sH = $1b01
|
&byte r0sH = $1be1
|
||||||
&byte r1sH = $1b03
|
&byte r1sH = $1be3
|
||||||
&byte r2sH = $1b05
|
&byte r2sH = $1be5
|
||||||
&byte r3sH = $1b07
|
&byte r3sH = $1be7
|
||||||
&byte r4sH = $1b09
|
&byte r4sH = $1be9
|
||||||
&byte r5sH = $1b0b
|
&byte r5sH = $1beb
|
||||||
&byte r6sH = $1b0d
|
&byte r6sH = $1bed
|
||||||
&byte r7sH = $1b0f
|
&byte r7sH = $1bef
|
||||||
&byte r8sH = $1b11
|
&byte r8sH = $1bf1
|
||||||
&byte r9sH = $1b13
|
&byte r9sH = $1bf3
|
||||||
&byte r10sH = $1b15
|
&byte r10sH = $1bf5
|
||||||
&byte r11sH = $1b17
|
&byte r11sH = $1bf7
|
||||||
&byte r12sH = $1b19
|
&byte r12sH = $1bf9
|
||||||
&byte r13sH = $1b1b
|
&byte r13sH = $1bfb
|
||||||
&byte r14sH = $1b1d
|
&byte r14sH = $1bfd
|
||||||
&byte r15sH = $1b1f
|
&byte r15sH = $1bff
|
||||||
|
|
||||||
asmsub save_virtual_registers() clobbers(A,Y) {
|
asmsub save_virtual_registers() clobbers(A,Y) {
|
||||||
%asm {{
|
%asm {{
|
||||||
|
|
|
@ -97,13 +97,12 @@ sub uppercase() {
|
||||||
c128.VM1 &= ~2
|
c128.VM1 &= ~2
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, Y) {
|
asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, X, Y) {
|
||||||
; ---- scroll the whole screen 1 character to the left
|
; ---- scroll the whole screen 1 character to the left
|
||||||
; contents of the rightmost column are unchanged, you should clear/refill this yourself
|
; contents of the rightmost column are unchanged, you should clear/refill this yourself
|
||||||
; Carry flag determines if screen color data must be scrolled too
|
; Carry flag determines if screen color data must be scrolled too
|
||||||
|
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc _scroll_screen
|
bcc _scroll_screen
|
||||||
|
|
||||||
+ ; scroll the screen and the color memory
|
+ ; scroll the screen and the color memory
|
||||||
|
@ -133,17 +132,15 @@ _scroll_screen ; scroll only the screen memory
|
||||||
dey
|
dey
|
||||||
bpl -
|
bpl -
|
||||||
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_right (bool alsocolors @ Pc) clobbers(A) {
|
asmsub scroll_right (bool alsocolors @ Pc) clobbers(A,X) {
|
||||||
; ---- scroll the whole screen 1 character to the right
|
; ---- scroll the whole screen 1 character to the right
|
||||||
; contents of the leftmost column are unchanged, you should clear/refill this yourself
|
; contents of the leftmost column are unchanged, you should clear/refill this yourself
|
||||||
; Carry flag determines if screen color data must be scrolled too
|
; Carry flag determines if screen color data must be scrolled too
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc _scroll_screen
|
bcc _scroll_screen
|
||||||
|
|
||||||
+ ; scroll the screen and the color memory
|
+ ; scroll the screen and the color memory
|
||||||
|
@ -169,17 +166,15 @@ _scroll_screen ; scroll only the screen memory
|
||||||
dex
|
dex
|
||||||
bpl -
|
bpl -
|
||||||
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_up (bool alsocolors @ Pc) clobbers(A) {
|
asmsub scroll_up (bool alsocolors @ Pc) clobbers(A,X) {
|
||||||
; ---- scroll the whole screen 1 character up
|
; ---- scroll the whole screen 1 character up
|
||||||
; contents of the bottom row are unchanged, you should refill/clear this yourself
|
; contents of the bottom row are unchanged, you should refill/clear this yourself
|
||||||
; Carry flag determines if screen color data must be scrolled too
|
; Carry flag determines if screen color data must be scrolled too
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc _scroll_screen
|
bcc _scroll_screen
|
||||||
|
|
||||||
+ ; scroll the screen and the color memory
|
+ ; scroll the screen and the color memory
|
||||||
|
@ -205,17 +200,15 @@ _scroll_screen ; scroll only the screen memory
|
||||||
dex
|
dex
|
||||||
bpl -
|
bpl -
|
||||||
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_down (bool alsocolors @ Pc) clobbers(A) {
|
asmsub scroll_down (bool alsocolors @ Pc) clobbers(A,X) {
|
||||||
; ---- scroll the whole screen 1 character down
|
; ---- scroll the whole screen 1 character down
|
||||||
; contents of the top row are unchanged, you should refill/clear this yourself
|
; contents of the top row are unchanged, you should refill/clear this yourself
|
||||||
; Carry flag determines if screen color data must be scrolled too
|
; Carry flag determines if screen color data must be scrolled too
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc _scroll_screen
|
bcc _scroll_screen
|
||||||
|
|
||||||
+ ; scroll the screen and the color memory
|
+ ; scroll the screen and the color memory
|
||||||
|
@ -241,7 +234,6 @@ _scroll_screen ; scroll only the screen memory
|
||||||
dex
|
dex
|
||||||
bpl -
|
bpl -
|
||||||
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -266,10 +258,9 @@ asmsub print (str text @ AY) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
asmsub print_ub0 (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
pha
|
pha
|
||||||
tya
|
tya
|
||||||
|
@ -277,16 +268,13 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||||
pla
|
pla
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
txa
|
txa
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ub (ubyte value @ A) clobbers(A,Y) {
|
asmsub print_ub (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in decimal form, without left padding 0s
|
; ---- print the ubyte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
_print_byte_digits
|
_print_byte_digits
|
||||||
pha
|
pha
|
||||||
|
@ -302,16 +290,13 @@ _print_byte_digits
|
||||||
beq _ones
|
beq _ones
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
_ones txa
|
_ones txa
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_b (byte value @ A) clobbers(A,Y) {
|
asmsub print_b (byte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the byte in A in decimal form, without left padding 0s
|
; ---- print the byte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
pha
|
pha
|
||||||
cmp #0
|
cmp #0
|
||||||
bpl +
|
bpl +
|
||||||
|
@ -323,10 +308,9 @@ asmsub print_b (byte value @ A) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc +
|
bcc +
|
||||||
pha
|
pha
|
||||||
lda #'$'
|
lda #'$'
|
||||||
|
@ -335,16 +319,13 @@ asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
+ jsr conv.ubyte2hex
|
+ jsr conv.ubyte2hex
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
tya
|
tya
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
bcc +
|
bcc +
|
||||||
lda #'%'
|
lda #'%'
|
||||||
|
@ -357,12 +338,11 @@ asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
+ jsr cbm.CHROUT
|
+ jsr cbm.CHROUT
|
||||||
dey
|
dey
|
||||||
bne -
|
bne -
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
pha
|
pha
|
||||||
|
@ -374,7 +354,7 @@ asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
||||||
; (if Carry is set, a radix prefix '$' is printed as well)
|
; (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
|
@ -387,10 +367,9 @@ asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
asmsub print_uw0 (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
|
@ -398,17 +377,14 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
iny
|
iny
|
||||||
bne -
|
bne -
|
||||||
+ ldx P8ZP_SCRATCH_REG
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uw (uword value @ AY) clobbers(A,Y) {
|
asmsub print_uw (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
beq _allzero
|
beq _allzero
|
||||||
|
@ -429,7 +405,7 @@ _allzero
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_w (word value @ AY) clobbers(A,Y) {
|
asmsub print_w (word value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
||||||
%asm {{
|
%asm {{
|
||||||
cpy #0
|
cpy #0
|
||||||
|
@ -583,15 +559,10 @@ _colormod sta $ffff ; modified
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) {
|
asmsub plot (ubyte col @ Y, ubyte row @ X) {
|
||||||
; ---- safe wrapper around PLOT kernal routine, to save the X register.
|
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
tax
|
|
||||||
clc
|
clc
|
||||||
jsr cbm.PLOT
|
jmp cbm.PLOT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,11 @@ FL_ZERO_const .byte 0,0,0,0,0 ; 0.0
|
||||||
FL_LOG2_const .byte $80, $31, $72, $17, $f8 ; log(2)
|
FL_LOG2_const .byte $80, $31, $72, $17, $f8 ; log(2)
|
||||||
|
|
||||||
|
|
||||||
floats_store_reg .byte 0 ; temp storage
|
|
||||||
floats_temp_var .byte 0,0,0,0,0 ; temporary storage for a float
|
floats_temp_var .byte 0,0,0,0,0 ; temporary storage for a float
|
||||||
|
|
||||||
ub2float .proc
|
ub2float .proc
|
||||||
; -- convert ubyte in SCRATCH_ZPB1 to float at address A/Y
|
; -- convert ubyte in SCRATCH_ZPB1 to float at address A/Y
|
||||||
; clobbers A, Y
|
; clobbers A, X, Y
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
sty P8ZP_SCRATCH_W2+1
|
sty P8ZP_SCRATCH_W2+1
|
||||||
ldy P8ZP_SCRATCH_B1
|
ldy P8ZP_SCRATCH_B1
|
||||||
|
@ -19,15 +17,12 @@ ub2float .proc
|
||||||
jsr GIVAYF
|
jsr GIVAYF
|
||||||
_fac_to_mem ldx P8ZP_SCRATCH_W2
|
_fac_to_mem ldx P8ZP_SCRATCH_W2
|
||||||
ldy P8ZP_SCRATCH_W2+1
|
ldy P8ZP_SCRATCH_W2+1
|
||||||
jsr MOVMF
|
jmp MOVMF
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
b2float .proc
|
b2float .proc
|
||||||
; -- convert byte in SCRATCH_ZPB1 to float at address A/Y
|
; -- convert byte in SCRATCH_ZPB1 to float at address A/Y
|
||||||
; clobbers A, Y
|
; clobbers A, X, Y
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
sty P8ZP_SCRATCH_W2+1
|
sty P8ZP_SCRATCH_W2+1
|
||||||
lda P8ZP_SCRATCH_B1
|
lda P8ZP_SCRATCH_B1
|
||||||
|
@ -37,7 +32,7 @@ b2float .proc
|
||||||
|
|
||||||
uw2float .proc
|
uw2float .proc
|
||||||
; -- convert uword in SCRATCH_ZPWORD1 to float at address A/Y
|
; -- convert uword in SCRATCH_ZPWORD1 to float at address A/Y
|
||||||
stx P8ZP_SCRATCH_REG
|
; clobbers X
|
||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
sty P8ZP_SCRATCH_W2+1
|
sty P8ZP_SCRATCH_W2+1
|
||||||
lda P8ZP_SCRATCH_W1
|
lda P8ZP_SCRATCH_W1
|
||||||
|
@ -48,7 +43,7 @@ uw2float .proc
|
||||||
|
|
||||||
w2float .proc
|
w2float .proc
|
||||||
; -- convert word in SCRATCH_ZPWORD1 to float at address A/Y
|
; -- convert word in SCRATCH_ZPWORD1 to float at address A/Y
|
||||||
stx P8ZP_SCRATCH_REG
|
; clobbers X
|
||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
sty P8ZP_SCRATCH_W2+1
|
sty P8ZP_SCRATCH_W2+1
|
||||||
ldy P8ZP_SCRATCH_W1
|
ldy P8ZP_SCRATCH_W1
|
||||||
|
@ -60,7 +55,7 @@ w2float .proc
|
||||||
|
|
||||||
cast_from_uw .proc
|
cast_from_uw .proc
|
||||||
; -- uword in A/Y into float var at (P8ZP_SCRATCH_W2)
|
; -- uword in A/Y into float var at (P8ZP_SCRATCH_W2)
|
||||||
stx P8ZP_SCRATCH_REG
|
; clobbers X
|
||||||
jsr GIVUAYFAY
|
jsr GIVUAYFAY
|
||||||
jmp ub2float._fac_to_mem
|
jmp ub2float._fac_to_mem
|
||||||
.pend
|
.pend
|
||||||
|
@ -68,7 +63,7 @@ cast_from_uw .proc
|
||||||
|
|
||||||
cast_from_w .proc
|
cast_from_w .proc
|
||||||
; -- word in A/Y into float var at (P8ZP_SCRATCH_W2)
|
; -- word in A/Y into float var at (P8ZP_SCRATCH_W2)
|
||||||
stx P8ZP_SCRATCH_REG
|
; clobbers X
|
||||||
jsr GIVAYFAY
|
jsr GIVAYFAY
|
||||||
jmp ub2float._fac_to_mem
|
jmp ub2float._fac_to_mem
|
||||||
.pend
|
.pend
|
||||||
|
@ -76,7 +71,7 @@ cast_from_w .proc
|
||||||
|
|
||||||
cast_from_ub .proc
|
cast_from_ub .proc
|
||||||
; -- ubyte in Y into float var at (P8ZP_SCRATCH_W2)
|
; -- ubyte in Y into float var at (P8ZP_SCRATCH_W2)
|
||||||
stx P8ZP_SCRATCH_REG
|
; clobbers X
|
||||||
jsr FREADUY
|
jsr FREADUY
|
||||||
jmp ub2float._fac_to_mem
|
jmp ub2float._fac_to_mem
|
||||||
.pend
|
.pend
|
||||||
|
@ -84,169 +79,41 @@ cast_from_ub .proc
|
||||||
|
|
||||||
cast_from_b .proc
|
cast_from_b .proc
|
||||||
; -- byte in A into float var at (P8ZP_SCRATCH_W2)
|
; -- byte in A into float var at (P8ZP_SCRATCH_W2)
|
||||||
stx P8ZP_SCRATCH_REG
|
; clobbers X
|
||||||
jsr FREADSA
|
jsr FREADSA
|
||||||
jmp ub2float._fac_to_mem
|
jmp ub2float._fac_to_mem
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
cast_as_uw_into_ya .proc ; also used for float 2 ub
|
cast_as_uw_into_ya .proc ; also used for float 2 ub
|
||||||
; -- cast float at A/Y to uword into Y/A
|
; -- cast float at A/Y to uword into Y/A
|
||||||
|
; clobbers X
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
jmp cast_FAC1_as_uw_into_ya
|
jmp cast_FAC1_as_uw_into_ya
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
cast_as_w_into_ay .proc ; also used for float 2 b
|
cast_as_w_into_ay .proc ; also used for float 2 b
|
||||||
; -- cast float at A/Y to word into A/Y
|
; -- cast float at A/Y to word into A/Y
|
||||||
|
; clobbers X
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
jmp cast_FAC1_as_w_into_ay
|
jmp cast_FAC1_as_w_into_ay
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
cast_FAC1_as_uw_into_ya .proc ; also used for float 2 ub
|
cast_FAC1_as_uw_into_ya .proc ; also used for float 2 ub
|
||||||
; -- cast fac1 to uword into Y/A
|
; -- cast fac1 to uword into Y/A
|
||||||
stx P8ZP_SCRATCH_REG
|
; clobbers X
|
||||||
jsr GETADR ; into Y/A
|
jmp GETADR ; into Y/A
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
cast_FAC1_as_w_into_ay .proc ; also used for float 2 b
|
cast_FAC1_as_w_into_ay .proc ; also used for float 2 b
|
||||||
; -- cast fac1 to word into A/Y
|
; -- cast fac1 to word into A/Y
|
||||||
stx P8ZP_SCRATCH_REG
|
; clobbers X
|
||||||
jsr AYINT
|
jsr AYINT
|
||||||
ldy floats.AYINT_facmo
|
ldy floats.AYINT_facmo
|
||||||
lda floats.AYINT_facmo+1
|
lda floats.AYINT_facmo+1
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
stack_b2float .proc
|
|
||||||
; -- b2float operating on the stack
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FREADSA
|
|
||||||
jmp push_fac1._internal
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_w2float .proc
|
|
||||||
; -- w2float operating on the stack
|
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
lda P8ESTACK_HI,x
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr GIVAYF
|
|
||||||
jmp push_fac1._internal
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_ub2float .proc
|
|
||||||
; -- ub2float operating on the stack
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
tay
|
|
||||||
lda #0
|
|
||||||
jsr GIVAYF
|
|
||||||
jmp push_fac1._internal
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_uw2float .proc
|
|
||||||
; -- uw2float operating on the stack
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
ldy P8ESTACK_HI,x
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr GIVUAYFAY
|
|
||||||
jmp push_fac1._internal
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_float2w .proc ; also used for float2b
|
|
||||||
jsr pop_float_fac1
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr AYINT
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
lda floats.AYINT_facmo
|
|
||||||
sta P8ESTACK_HI,x
|
|
||||||
lda floats.AYINT_facmo+1
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_float2uw .proc ; also used for float2ub
|
|
||||||
jsr pop_float_fac1
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr GETADR
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
sta P8ESTACK_HI,x
|
|
||||||
tya
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
push_float .proc
|
|
||||||
; ---- push mflpt5 in A/Y onto stack
|
|
||||||
; (taking 3 stack positions = 6 bytes of which 1 is padding)
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
sty P8ZP_SCRATCH_W1+1
|
|
||||||
ldy #0
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
sta P8ESTACK_HI,x
|
|
||||||
dex
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
sta P8ESTACK_HI,x
|
|
||||||
dex
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
pop_float .proc
|
|
||||||
; ---- pops mflpt5 from stack to memory A/Y
|
|
||||||
; (frees 3 stack positions = 6 bytes of which 1 is padding)
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
sty P8ZP_SCRATCH_W1+1
|
|
||||||
ldy #4
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
sta (P8ZP_SCRATCH_W1),y
|
|
||||||
dey
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_HI,x
|
|
||||||
sta (P8ZP_SCRATCH_W1),y
|
|
||||||
dey
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
sta (P8ZP_SCRATCH_W1),y
|
|
||||||
dey
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_HI,x
|
|
||||||
sta (P8ZP_SCRATCH_W1),y
|
|
||||||
dey
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
sta (P8ZP_SCRATCH_W1),y
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
pop_float_fac1 .proc
|
|
||||||
; -- pops float from stack into FAC1
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr pop_float
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jmp MOVFM
|
|
||||||
.pend
|
|
||||||
|
|
||||||
copy_float .proc
|
copy_float .proc
|
||||||
; -- copies the 5 bytes of the mflt value pointed to by P8ZP_SCRATCH_W1,
|
; -- copies the 5 bytes of the mflt value pointed to by P8ZP_SCRATCH_W1,
|
||||||
; into the 5 bytes pointed to by A/Y. Clobbers A,Y.
|
; into the 5 bytes pointed to by A/Y. Clobbers A,Y.
|
||||||
|
@ -272,25 +139,23 @@ copy_float .proc
|
||||||
|
|
||||||
inc_var_f .proc
|
inc_var_f .proc
|
||||||
; -- add 1 to float pointed to by A/Y
|
; -- add 1 to float pointed to by A/Y
|
||||||
|
; clobbers X
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
sty P8ZP_SCRATCH_W1+1
|
sty P8ZP_SCRATCH_W1+1
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
lda #<FL_ONE_const
|
lda #<FL_ONE_const
|
||||||
ldy #>FL_ONE_const
|
ldy #>FL_ONE_const
|
||||||
jsr FADD
|
jsr FADD
|
||||||
ldx P8ZP_SCRATCH_W1
|
ldx P8ZP_SCRATCH_W1
|
||||||
ldy P8ZP_SCRATCH_W1+1
|
ldy P8ZP_SCRATCH_W1+1
|
||||||
jsr MOVMF
|
jmp MOVMF
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
dec_var_f .proc
|
dec_var_f .proc
|
||||||
; -- subtract 1 from float pointed to by A/Y
|
; -- subtract 1 from float pointed to by A/Y
|
||||||
|
; clobbers X
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
sty P8ZP_SCRATCH_W1+1
|
sty P8ZP_SCRATCH_W1+1
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #<FL_ONE_const
|
lda #<FL_ONE_const
|
||||||
ldy #>FL_ONE_const
|
ldy #>FL_ONE_const
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
|
@ -299,23 +164,7 @@ dec_var_f .proc
|
||||||
jsr FSUB
|
jsr FSUB
|
||||||
ldx P8ZP_SCRATCH_W1
|
ldx P8ZP_SCRATCH_W1
|
||||||
ldy P8ZP_SCRATCH_W1+1
|
ldy P8ZP_SCRATCH_W1+1
|
||||||
jsr MOVMF
|
jmp MOVMF
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
pop_2_floats_f2_in_fac1 .proc
|
|
||||||
; -- pop 2 floats from stack, load the second one in FAC1 as well
|
|
||||||
lda #<fmath_float2
|
|
||||||
ldy #>fmath_float2
|
|
||||||
jsr pop_float
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr pop_float
|
|
||||||
lda #<fmath_float2
|
|
||||||
ldy #>fmath_float2
|
|
||||||
jmp MOVFM
|
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
|
@ -323,71 +172,9 @@ fmath_float1 .byte 0,0,0,0,0 ; storage for a mflpt5 value
|
||||||
fmath_float2 .byte 0,0,0,0,0 ; storage for a mflpt5 value
|
fmath_float2 .byte 0,0,0,0,0 ; storage for a mflpt5 value
|
||||||
|
|
||||||
|
|
||||||
push_fac1 .proc
|
|
||||||
; -- push the float in FAC1 onto the stack
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
_internal ldx #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr MOVMF
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
jmp push_float
|
|
||||||
.pend
|
|
||||||
|
|
||||||
div_f .proc
|
|
||||||
; -- push f1/f2 on stack
|
|
||||||
jsr pop_2_floats_f2_in_fac1
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr FDIV
|
|
||||||
jmp push_fac1._internal
|
|
||||||
.pend
|
|
||||||
|
|
||||||
add_f .proc
|
|
||||||
; -- push f1+f2 on stack
|
|
||||||
jsr pop_2_floats_f2_in_fac1
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr FADD
|
|
||||||
jmp push_fac1._internal
|
|
||||||
.pend
|
|
||||||
|
|
||||||
sub_f .proc
|
|
||||||
; -- push f1-f2 on stack
|
|
||||||
jsr pop_2_floats_f2_in_fac1
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr FSUB
|
|
||||||
jmp push_fac1._internal
|
|
||||||
.pend
|
|
||||||
|
|
||||||
mul_f .proc
|
|
||||||
; -- push f1*f2 on stack
|
|
||||||
jsr pop_2_floats_f2_in_fac1
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr FMULT
|
|
||||||
jmp push_fac1._internal
|
|
||||||
.pend
|
|
||||||
|
|
||||||
neg_f .proc
|
|
||||||
; -- toggle the sign bit on the stack
|
|
||||||
lda P8ESTACK_HI+3,x
|
|
||||||
eor #$80
|
|
||||||
sta P8ESTACK_HI+3,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
var_fac1_less_f .proc
|
var_fac1_less_f .proc
|
||||||
; -- is the float in FAC1 < the variable AY?
|
; -- is the float in FAC1 < the variable AY? Result in A. Clobbers X.
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FCOMP
|
jsr FCOMP
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
cmp #255
|
cmp #255
|
||||||
beq +
|
beq +
|
||||||
lda #0
|
lda #0
|
||||||
|
@ -397,10 +184,8 @@ var_fac1_less_f .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
var_fac1_lesseq_f .proc
|
var_fac1_lesseq_f .proc
|
||||||
; -- is the float in FAC1 <= the variable AY?
|
; -- is the float in FAC1 <= the variable AY? Result in A. Clobbers X.
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FCOMP
|
jsr FCOMP
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
cmp #0
|
cmp #0
|
||||||
beq +
|
beq +
|
||||||
cmp #255
|
cmp #255
|
||||||
|
@ -412,10 +197,8 @@ var_fac1_lesseq_f .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
var_fac1_greater_f .proc
|
var_fac1_greater_f .proc
|
||||||
; -- is the float in FAC1 > the variable AY?
|
; -- is the float in FAC1 > the variable AY? Result in A. Clobbers X.
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FCOMP
|
jsr FCOMP
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
cmp #1
|
cmp #1
|
||||||
beq +
|
beq +
|
||||||
lda #0
|
lda #0
|
||||||
|
@ -425,10 +208,8 @@ var_fac1_greater_f .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
var_fac1_greatereq_f .proc
|
var_fac1_greatereq_f .proc
|
||||||
; -- is the float in FAC1 >= the variable AY?
|
; -- is the float in FAC1 >= the variable AY? Result in A. Clobbers X.
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FCOMP
|
jsr FCOMP
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
cmp #0
|
cmp #0
|
||||||
beq +
|
beq +
|
||||||
cmp #1
|
cmp #1
|
||||||
|
@ -439,17 +220,23 @@ var_fac1_greatereq_f .proc
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
var_fac1_notequal_f .proc
|
var_fac1_equal_f .proc
|
||||||
; -- are the floats numbers in FAC1 and the variable AY *not* identical?
|
; -- are the floats numbers in FAC1 and the variable AY *not* identical? Result in A. Clobbers X.
|
||||||
stx P8ZP_SCRATCH_REG
|
jsr FCOMP
|
||||||
|
and #1
|
||||||
|
eor #1
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
|
var_fac1_notequal_f .proc
|
||||||
|
; -- are the floats numbers in FAC1 and the variable AY *not* identical? Result in A. Clobbers X.
|
||||||
jsr FCOMP
|
jsr FCOMP
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
and #1
|
and #1
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
vars_equal_f .proc
|
vars_equal_f .proc
|
||||||
; -- are the mflpt5 numbers in P8ZP_SCRATCH_W1 and AY identical?
|
; -- are the mflpt5 numbers in P8ZP_SCRATCH_W1 and AY identical? Result in A
|
||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
sty P8ZP_SCRATCH_W2+1
|
sty P8ZP_SCRATCH_W2+1
|
||||||
ldy #0
|
ldy #0
|
||||||
|
@ -478,51 +265,13 @@ _false lda #0
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
equal_f .proc
|
|
||||||
; -- are the two mflpt5 numbers on the stack identical?
|
|
||||||
inx
|
|
||||||
inx
|
|
||||||
inx
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO-3,x
|
|
||||||
cmp P8ESTACK_LO,x
|
|
||||||
bne _equals_false
|
|
||||||
lda P8ESTACK_LO-2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
bne _equals_false
|
|
||||||
lda P8ESTACK_LO-1,x
|
|
||||||
cmp P8ESTACK_LO+2,x
|
|
||||||
bne _equals_false
|
|
||||||
lda P8ESTACK_HI-2,x
|
|
||||||
cmp P8ESTACK_HI+1,x
|
|
||||||
bne _equals_false
|
|
||||||
lda P8ESTACK_HI-1,x
|
|
||||||
cmp P8ESTACK_HI+2,x
|
|
||||||
bne _equals_false
|
|
||||||
_equals_true lda #1
|
|
||||||
_equals_store inx
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
_equals_false lda #0
|
|
||||||
beq _equals_store
|
|
||||||
.pend
|
|
||||||
|
|
||||||
notequal_f .proc
|
|
||||||
; -- are the two mflpt5 numbers on the stack different?
|
|
||||||
jsr equal_f
|
|
||||||
eor #1 ; invert the result
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
vars_less_f .proc
|
vars_less_f .proc
|
||||||
; -- is float in AY < float in P8ZP_SCRATCH_W2 ?
|
; -- is float in AY < float in P8ZP_SCRATCH_W2 ? Result in A. Clobbers X.
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
lda P8ZP_SCRATCH_W2
|
lda P8ZP_SCRATCH_W2
|
||||||
ldy P8ZP_SCRATCH_W2+1
|
ldy P8ZP_SCRATCH_W2+1
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FCOMP
|
jsr FCOMP
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
cmp #255
|
cmp #255
|
||||||
bne +
|
bne +
|
||||||
lda #1
|
lda #1
|
||||||
|
@ -532,13 +281,11 @@ vars_less_f .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
vars_lesseq_f .proc
|
vars_lesseq_f .proc
|
||||||
; -- is float in AY <= float in P8ZP_SCRATCH_W2 ?
|
; -- is float in AY <= float in P8ZP_SCRATCH_W2 ? Result in A. Clobbers X.
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
lda P8ZP_SCRATCH_W2
|
lda P8ZP_SCRATCH_W2
|
||||||
ldy P8ZP_SCRATCH_W2+1
|
ldy P8ZP_SCRATCH_W2+1
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FCOMP
|
jsr FCOMP
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
cmp #255
|
cmp #255
|
||||||
bne +
|
bne +
|
||||||
- lda #1
|
- lda #1
|
||||||
|
@ -550,7 +297,7 @@ vars_lesseq_f .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
less_f .proc
|
less_f .proc
|
||||||
; -- is f1 < f2?
|
; -- is f1 < f2? Result in A. Clobbers X.
|
||||||
jsr compare_floats
|
jsr compare_floats
|
||||||
cmp #255
|
cmp #255
|
||||||
beq compare_floats._return_true
|
beq compare_floats._return_true
|
||||||
|
@ -559,7 +306,7 @@ less_f .proc
|
||||||
|
|
||||||
|
|
||||||
lesseq_f .proc
|
lesseq_f .proc
|
||||||
; -- is f1 <= f2?
|
; -- is f1 <= f2? Result in A. Clobbers X.
|
||||||
jsr compare_floats
|
jsr compare_floats
|
||||||
cmp #255
|
cmp #255
|
||||||
beq compare_floats._return_true
|
beq compare_floats._return_true
|
||||||
|
@ -569,7 +316,7 @@ lesseq_f .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
greater_f .proc
|
greater_f .proc
|
||||||
; -- is f1 > f2?
|
; -- is f1 > f2? Result in A. Clobbers X.
|
||||||
jsr compare_floats
|
jsr compare_floats
|
||||||
cmp #1
|
cmp #1
|
||||||
beq compare_floats._return_true
|
beq compare_floats._return_true
|
||||||
|
@ -577,7 +324,7 @@ greater_f .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
greatereq_f .proc
|
greatereq_f .proc
|
||||||
; -- is f1 >= f2?
|
; -- is f1 >= f2? Result in A. Clobbers X.
|
||||||
jsr compare_floats
|
jsr compare_floats
|
||||||
cmp #1
|
cmp #1
|
||||||
beq compare_floats._return_true
|
beq compare_floats._return_true
|
||||||
|
@ -586,32 +333,9 @@ greatereq_f .proc
|
||||||
bne compare_floats._return_false
|
bne compare_floats._return_false
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
compare_floats .proc
|
|
||||||
lda #<fmath_float2
|
|
||||||
ldy #>fmath_float2
|
|
||||||
jsr pop_float
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr pop_float
|
|
||||||
lda #<fmath_float1
|
|
||||||
ldy #>fmath_float1
|
|
||||||
jsr MOVFM ; fac1 = flt1
|
|
||||||
lda #<fmath_float2
|
|
||||||
ldy #>fmath_float2
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FCOMP ; A = flt1 compared with flt2 (0=equal, 1=flt1>flt2, 255=flt1<flt2)
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
_return_false lda #0
|
|
||||||
_return_result sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
_return_true lda #1
|
|
||||||
bne _return_result
|
|
||||||
.pend
|
|
||||||
|
|
||||||
set_array_float_from_fac1 .proc
|
set_array_float_from_fac1 .proc
|
||||||
; -- set the float in FAC1 in the array (index in A, array in P8ZP_SCRATCH_W1)
|
; -- set the float in FAC1 in the array (index in A, array in P8ZP_SCRATCH_W1)
|
||||||
|
; clobbers X
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
asl a
|
asl a
|
||||||
asl a
|
asl a
|
||||||
|
@ -622,11 +346,8 @@ set_array_float_from_fac1 .proc
|
||||||
adc P8ZP_SCRATCH_W1
|
adc P8ZP_SCRATCH_W1
|
||||||
bcc +
|
bcc +
|
||||||
iny
|
iny
|
||||||
+ stx floats_store_reg
|
+ tax
|
||||||
tax
|
jmp MOVMF
|
||||||
jsr MOVMF
|
|
||||||
ldx floats_store_reg
|
|
||||||
rts
|
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
|
@ -669,54 +390,59 @@ set_array_float .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
equal_zero .proc
|
pushFAC1 .proc
|
||||||
jsr floats.pop_float_fac1
|
;-- push floating point in FAC onto the cpu stack
|
||||||
jsr floats.SIGN
|
; save return address
|
||||||
beq _true
|
pla
|
||||||
bne _false
|
sta P8ZP_SCRATCH_W2
|
||||||
_true lda #1
|
pla
|
||||||
sta P8ESTACK_LO,x
|
sta P8ZP_SCRATCH_W2+1
|
||||||
dex
|
ldx #<floats.floats_temp_var
|
||||||
rts
|
ldy #>floats.floats_temp_var
|
||||||
_false lda #0
|
jsr floats.MOVMF
|
||||||
sta P8ESTACK_LO,x
|
lda floats.floats_temp_var
|
||||||
dex
|
pha
|
||||||
rts
|
lda floats.floats_temp_var+1
|
||||||
.pend
|
pha
|
||||||
|
lda floats.floats_temp_var+2
|
||||||
|
pha
|
||||||
|
lda floats.floats_temp_var+3
|
||||||
|
pha
|
||||||
|
lda floats.floats_temp_var+4
|
||||||
|
pha
|
||||||
|
; re-push return address
|
||||||
|
lda P8ZP_SCRATCH_W2+1
|
||||||
|
pha
|
||||||
|
lda P8ZP_SCRATCH_W2
|
||||||
|
pha
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
notequal_zero .proc
|
popFAC1 .proc
|
||||||
jsr floats.pop_float_fac1
|
; -- pop floating point value from cpu stack into FAC1
|
||||||
jsr floats.SIGN
|
; save return address
|
||||||
bne equal_zero._true
|
pla
|
||||||
beq equal_zero._false
|
sta P8ZP_SCRATCH_W2
|
||||||
.pend
|
pla
|
||||||
|
sta P8ZP_SCRATCH_W2+1
|
||||||
|
pla
|
||||||
|
sta floats.floats_temp_var+4
|
||||||
|
pla
|
||||||
|
sta floats.floats_temp_var+3
|
||||||
|
pla
|
||||||
|
sta floats.floats_temp_var+2
|
||||||
|
pla
|
||||||
|
sta floats.floats_temp_var+1
|
||||||
|
pla
|
||||||
|
sta floats.floats_temp_var
|
||||||
|
lda #<floats.floats_temp_var
|
||||||
|
ldy #>floats.floats_temp_var
|
||||||
|
jsr floats.MOVFM
|
||||||
|
; re-push return address
|
||||||
|
lda P8ZP_SCRATCH_W2+1
|
||||||
|
pha
|
||||||
|
lda P8ZP_SCRATCH_W2
|
||||||
|
pha
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
greater_zero .proc
|
|
||||||
jsr floats.pop_float_fac1
|
|
||||||
jsr floats.SIGN
|
|
||||||
beq equal_zero._false
|
|
||||||
bpl equal_zero._true
|
|
||||||
jmp equal_zero._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
less_zero .proc
|
|
||||||
jsr floats.pop_float_fac1
|
|
||||||
jsr floats.SIGN
|
|
||||||
bmi equal_zero._true
|
|
||||||
jmp equal_zero._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greaterequal_zero .proc
|
|
||||||
jsr floats.pop_float_fac1
|
|
||||||
jsr floats.SIGN
|
|
||||||
bpl equal_zero._true
|
|
||||||
jmp equal_zero._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
lessequal_zero .proc
|
|
||||||
jsr floats.pop_float_fac1
|
|
||||||
jsr floats.SIGN
|
|
||||||
beq equal_zero._true
|
|
||||||
bmi equal_zero._true
|
|
||||||
jmp equal_zero._false
|
|
||||||
.pend
|
|
||||||
|
|
|
@ -159,12 +159,9 @@ asmsub GETADRAY () clobbers(X) -> uword @ AY {
|
||||||
|
|
||||||
sub rndf() -> float {
|
sub rndf() -> float {
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #1
|
lda #1
|
||||||
jsr FREADSA
|
jsr FREADSA
|
||||||
jsr RND ; rng into fac1
|
jmp RND ; rng into fac1
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
; --- floating point builtin functions
|
; --- floating point builtin functions
|
||||||
|
|
||||||
|
|
||||||
func_sign_f_stack .proc
|
|
||||||
jsr func_sign_f_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_sign_f_into_A .proc
|
func_sign_f_into_A .proc
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
jmp SIGN
|
jmp SIGN
|
||||||
|
@ -146,17 +139,11 @@ func_all_f_stack .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
func_abs_f_into_FAC1 .proc
|
func_abs_f_into_FAC1 .proc
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
jsr ABS
|
jmp ABS
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
func_sqrt_into_FAC1 .proc
|
func_sqrt_into_FAC1 .proc
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
jsr SQR
|
jmp SQR
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
.pend
|
.pend
|
||||||
|
|
|
@ -185,7 +185,6 @@ graphics {
|
||||||
lda length
|
lda length
|
||||||
and #7
|
and #7
|
||||||
sta separate_pixels
|
sta separate_pixels
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lsr length+1
|
lsr length+1
|
||||||
ror length
|
ror length
|
||||||
lsr length+1
|
lsr length+1
|
||||||
|
@ -210,8 +209,7 @@ _modified stx $ffff ; modified
|
||||||
inc _modified+2
|
inc _modified+2
|
||||||
+ dey
|
+ dey
|
||||||
bne _modified
|
bne _modified
|
||||||
_zero ldx P8ZP_SCRATCH_REG
|
_zero
|
||||||
|
|
||||||
ldy separate_pixels
|
ldy separate_pixels
|
||||||
beq hline_zero2
|
beq hline_zero2
|
||||||
lda _modified+1
|
lda _modified+1
|
||||||
|
|
|
@ -104,34 +104,26 @@ romsub $FFED = SCREEN() -> ubyte @ X, ubyte @ Y ; read number of
|
||||||
romsub $FFF0 = PLOT(ubyte col @ Y, ubyte row @ X, bool dir @ Pc) -> ubyte @ X, ubyte @ Y ; read/set position of cursor on screen. Use txt.plot for a 'safe' wrapper that preserves X.
|
romsub $FFF0 = PLOT(ubyte col @ Y, ubyte row @ X, bool dir @ Pc) -> ubyte @ X, ubyte @ Y ; read/set position of cursor on screen. Use txt.plot for a 'safe' wrapper that preserves X.
|
||||||
romsub $FFF3 = IOBASE() -> uword @ XY ; read base address of I/O devices
|
romsub $FFF3 = IOBASE() -> uword @ XY ; read base address of I/O devices
|
||||||
|
|
||||||
asmsub STOP2() -> ubyte @A {
|
asmsub STOP2() clobbers(X) -> ubyte @A {
|
||||||
; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag.
|
; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag.
|
||||||
%asm {{
|
%asm {{
|
||||||
txa
|
|
||||||
pha
|
|
||||||
jsr cbm.STOP
|
jsr cbm.STOP
|
||||||
beq +
|
beq +
|
||||||
pla
|
|
||||||
tax
|
|
||||||
lda #0
|
lda #0
|
||||||
rts
|
rts
|
||||||
+ pla
|
+ lda #1
|
||||||
tax
|
|
||||||
lda #1
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub RDTIM16() -> uword @AY {
|
asmsub RDTIM16() clobbers(X) -> uword @AY {
|
||||||
; -- like RDTIM() but only returning the lower 16 bits in AY for convenience
|
; -- like RDTIM() but only returning the lower 16 bits in AY for convenience
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr cbm.RDTIM
|
jsr cbm.RDTIM
|
||||||
pha
|
pha
|
||||||
txa
|
txa
|
||||||
tay
|
tay
|
||||||
pla
|
pla
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -413,10 +405,6 @@ _irq_handler_init
|
||||||
sta IRQ_SCRATCH_ZPWORD2
|
sta IRQ_SCRATCH_ZPWORD2
|
||||||
lda P8ZP_SCRATCH_W2+1
|
lda P8ZP_SCRATCH_W2+1
|
||||||
sta IRQ_SCRATCH_ZPWORD2+1
|
sta IRQ_SCRATCH_ZPWORD2+1
|
||||||
; Set X to the bottom 32 bytes of the evaluation stack, to HOPEFULLY not clobber it.
|
|
||||||
; This leaves 128-32=96 stack entries for the main program, and 32 stack entries for the IRQ handler.
|
|
||||||
; We assume IRQ handlers don't contain complex expressions taking up more than that.
|
|
||||||
ldx #32
|
|
||||||
cld
|
cld
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
@ -742,111 +730,110 @@ cx16 {
|
||||||
|
|
||||||
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
||||||
; they are simulated on the C64 as well but their location in memory is different
|
; they are simulated on the C64 as well but their location in memory is different
|
||||||
; (because there's no room for them in the zeropage)
|
; (because there's no room for them in the zeropage in the default configuration)
|
||||||
; they are allocated at the bottom of the eval-stack (should be ample space unless
|
; Note that when using ZP options that free up more of the zeropage (such as %zeropage kernalsafe)
|
||||||
; you're doing insane nesting of expressions...)
|
; there might be enough space to put them there after all, and the compiler will change these addresses!
|
||||||
; NOTE: the memory location of these registers can change based on the "-esa" compiler option
|
&uword r0 = $cfe0
|
||||||
&uword r0 = $cf00
|
&uword r1 = $cfe2
|
||||||
&uword r1 = $cf02
|
&uword r2 = $cfe4
|
||||||
&uword r2 = $cf04
|
&uword r3 = $cfe6
|
||||||
&uword r3 = $cf06
|
&uword r4 = $cfe8
|
||||||
&uword r4 = $cf08
|
&uword r5 = $cfea
|
||||||
&uword r5 = $cf0a
|
&uword r6 = $cfec
|
||||||
&uword r6 = $cf0c
|
&uword r7 = $cfee
|
||||||
&uword r7 = $cf0e
|
&uword r8 = $cff0
|
||||||
&uword r8 = $cf10
|
&uword r9 = $cff2
|
||||||
&uword r9 = $cf12
|
&uword r10 = $cff4
|
||||||
&uword r10 = $cf14
|
&uword r11 = $cff6
|
||||||
&uword r11 = $cf16
|
&uword r12 = $cff8
|
||||||
&uword r12 = $cf18
|
&uword r13 = $cffa
|
||||||
&uword r13 = $cf1a
|
&uword r14 = $cffc
|
||||||
&uword r14 = $cf1c
|
&uword r15 = $cffe
|
||||||
&uword r15 = $cf1e
|
|
||||||
|
|
||||||
&word r0s = $cf00
|
&word r0s = $cfe0
|
||||||
&word r1s = $cf02
|
&word r1s = $cfe2
|
||||||
&word r2s = $cf04
|
&word r2s = $cfe4
|
||||||
&word r3s = $cf06
|
&word r3s = $cfe6
|
||||||
&word r4s = $cf08
|
&word r4s = $cfe8
|
||||||
&word r5s = $cf0a
|
&word r5s = $cfea
|
||||||
&word r6s = $cf0c
|
&word r6s = $cfec
|
||||||
&word r7s = $cf0e
|
&word r7s = $cfee
|
||||||
&word r8s = $cf10
|
&word r8s = $cff0
|
||||||
&word r9s = $cf12
|
&word r9s = $cff2
|
||||||
&word r10s = $cf14
|
&word r10s = $cff4
|
||||||
&word r11s = $cf16
|
&word r11s = $cff6
|
||||||
&word r12s = $cf18
|
&word r12s = $cff8
|
||||||
&word r13s = $cf1a
|
&word r13s = $cffa
|
||||||
&word r14s = $cf1c
|
&word r14s = $cffc
|
||||||
&word r15s = $cf1e
|
&word r15s = $cffe
|
||||||
|
|
||||||
&ubyte r0L = $cf00
|
&ubyte r0L = $cfe0
|
||||||
&ubyte r1L = $cf02
|
&ubyte r1L = $cfe2
|
||||||
&ubyte r2L = $cf04
|
&ubyte r2L = $cfe4
|
||||||
&ubyte r3L = $cf06
|
&ubyte r3L = $cfe6
|
||||||
&ubyte r4L = $cf08
|
&ubyte r4L = $cfe8
|
||||||
&ubyte r5L = $cf0a
|
&ubyte r5L = $cfea
|
||||||
&ubyte r6L = $cf0c
|
&ubyte r6L = $cfec
|
||||||
&ubyte r7L = $cf0e
|
&ubyte r7L = $cfee
|
||||||
&ubyte r8L = $cf10
|
&ubyte r8L = $cff0
|
||||||
&ubyte r9L = $cf12
|
&ubyte r9L = $cff2
|
||||||
&ubyte r10L = $cf14
|
&ubyte r10L = $cff4
|
||||||
&ubyte r11L = $cf16
|
&ubyte r11L = $cff6
|
||||||
&ubyte r12L = $cf18
|
&ubyte r12L = $cff8
|
||||||
&ubyte r13L = $cf1a
|
&ubyte r13L = $cffa
|
||||||
&ubyte r14L = $cf1c
|
&ubyte r14L = $cffc
|
||||||
&ubyte r15L = $cf1e
|
&ubyte r15L = $cffe
|
||||||
|
|
||||||
&ubyte r0H = $cf01
|
&ubyte r0H = $cfe1
|
||||||
&ubyte r1H = $cf03
|
&ubyte r1H = $cfe3
|
||||||
&ubyte r2H = $cf05
|
&ubyte r2H = $cfe5
|
||||||
&ubyte r3H = $cf07
|
&ubyte r3H = $cfe7
|
||||||
&ubyte r4H = $cf09
|
&ubyte r4H = $cfe9
|
||||||
&ubyte r5H = $cf0b
|
&ubyte r5H = $cfeb
|
||||||
&ubyte r6H = $cf0d
|
&ubyte r6H = $cfed
|
||||||
&ubyte r7H = $cf0f
|
&ubyte r7H = $cfef
|
||||||
&ubyte r8H = $cf11
|
&ubyte r8H = $cff1
|
||||||
&ubyte r9H = $cf13
|
&ubyte r9H = $cff3
|
||||||
&ubyte r10H = $cf15
|
&ubyte r10H = $cff5
|
||||||
&ubyte r11H = $cf17
|
&ubyte r11H = $cff7
|
||||||
&ubyte r12H = $cf19
|
&ubyte r12H = $cff9
|
||||||
&ubyte r13H = $cf1b
|
&ubyte r13H = $cffb
|
||||||
&ubyte r14H = $cf1d
|
&ubyte r14H = $cffd
|
||||||
&ubyte r15H = $cf1f
|
&ubyte r15H = $cfff
|
||||||
|
|
||||||
&byte r0sL = $cf00
|
&byte r0sL = $cfe0
|
||||||
&byte r1sL = $cf02
|
&byte r1sL = $cfe2
|
||||||
&byte r2sL = $cf04
|
&byte r2sL = $cfe4
|
||||||
&byte r3sL = $cf06
|
&byte r3sL = $cfe6
|
||||||
&byte r4sL = $cf08
|
&byte r4sL = $cfe8
|
||||||
&byte r5sL = $cf0a
|
&byte r5sL = $cfea
|
||||||
&byte r6sL = $cf0c
|
&byte r6sL = $cfec
|
||||||
&byte r7sL = $cf0e
|
&byte r7sL = $cfee
|
||||||
&byte r8sL = $cf10
|
&byte r8sL = $cff0
|
||||||
&byte r9sL = $cf12
|
&byte r9sL = $cff2
|
||||||
&byte r10sL = $cf14
|
&byte r10sL = $cff4
|
||||||
&byte r11sL = $cf16
|
&byte r11sL = $cff6
|
||||||
&byte r12sL = $cf18
|
&byte r12sL = $cff8
|
||||||
&byte r13sL = $cf1a
|
&byte r13sL = $cffa
|
||||||
&byte r14sL = $cf1c
|
&byte r14sL = $cffc
|
||||||
&byte r15sL = $cf1e
|
&byte r15sL = $cffe
|
||||||
|
|
||||||
&byte r0sH = $cf01
|
&byte r0sH = $cfe1
|
||||||
&byte r1sH = $cf03
|
&byte r1sH = $cfe3
|
||||||
&byte r2sH = $cf05
|
&byte r2sH = $cfe5
|
||||||
&byte r3sH = $cf07
|
&byte r3sH = $cfe7
|
||||||
&byte r4sH = $cf09
|
&byte r4sH = $cfe9
|
||||||
&byte r5sH = $cf0b
|
&byte r5sH = $cfeb
|
||||||
&byte r6sH = $cf0d
|
&byte r6sH = $cfed
|
||||||
&byte r7sH = $cf0f
|
&byte r7sH = $cfef
|
||||||
&byte r8sH = $cf11
|
&byte r8sH = $cff1
|
||||||
&byte r9sH = $cf13
|
&byte r9sH = $cff3
|
||||||
&byte r10sH = $cf15
|
&byte r10sH = $cff5
|
||||||
&byte r11sH = $cf17
|
&byte r11sH = $cff7
|
||||||
&byte r12sH = $cf19
|
&byte r12sH = $cff9
|
||||||
&byte r13sH = $cf1b
|
&byte r13sH = $cffb
|
||||||
&byte r14sH = $cf1d
|
&byte r14sH = $cffd
|
||||||
&byte r15sH = $cf1f
|
&byte r15sH = $cfff
|
||||||
|
|
||||||
asmsub save_virtual_registers() clobbers(A,Y) {
|
asmsub save_virtual_registers() clobbers(A,Y) {
|
||||||
%asm {{
|
%asm {{
|
||||||
|
|
|
@ -96,13 +96,12 @@ sub uppercase() {
|
||||||
c64.VMCSB &= ~2
|
c64.VMCSB &= ~2
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, Y) {
|
asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, X, Y) {
|
||||||
; ---- scroll the whole screen 1 character to the left
|
; ---- scroll the whole screen 1 character to the left
|
||||||
; contents of the rightmost column are unchanged, you should clear/refill this yourself
|
; contents of the rightmost column are unchanged, you should clear/refill this yourself
|
||||||
; Carry flag determines if screen color data must be scrolled too
|
; Carry flag determines if screen color data must be scrolled too
|
||||||
|
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc _scroll_screen
|
bcc _scroll_screen
|
||||||
|
|
||||||
+ ; scroll the screen and the color memory
|
+ ; scroll the screen and the color memory
|
||||||
|
@ -132,17 +131,15 @@ _scroll_screen ; scroll only the screen memory
|
||||||
dey
|
dey
|
||||||
bpl -
|
bpl -
|
||||||
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_right (bool alsocolors @ Pc) clobbers(A) {
|
asmsub scroll_right (bool alsocolors @ Pc) clobbers(A,X) {
|
||||||
; ---- scroll the whole screen 1 character to the right
|
; ---- scroll the whole screen 1 character to the right
|
||||||
; contents of the leftmost column are unchanged, you should clear/refill this yourself
|
; contents of the leftmost column are unchanged, you should clear/refill this yourself
|
||||||
; Carry flag determines if screen color data must be scrolled too
|
; Carry flag determines if screen color data must be scrolled too
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc _scroll_screen
|
bcc _scroll_screen
|
||||||
|
|
||||||
+ ; scroll the screen and the color memory
|
+ ; scroll the screen and the color memory
|
||||||
|
@ -168,17 +165,15 @@ _scroll_screen ; scroll only the screen memory
|
||||||
dex
|
dex
|
||||||
bpl -
|
bpl -
|
||||||
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_up (bool alsocolors @ Pc) clobbers(A) {
|
asmsub scroll_up (bool alsocolors @ Pc) clobbers(A,X) {
|
||||||
; ---- scroll the whole screen 1 character up
|
; ---- scroll the whole screen 1 character up
|
||||||
; contents of the bottom row are unchanged, you should refill/clear this yourself
|
; contents of the bottom row are unchanged, you should refill/clear this yourself
|
||||||
; Carry flag determines if screen color data must be scrolled too
|
; Carry flag determines if screen color data must be scrolled too
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc _scroll_screen
|
bcc _scroll_screen
|
||||||
|
|
||||||
+ ; scroll the screen and the color memory
|
+ ; scroll the screen and the color memory
|
||||||
|
@ -204,17 +199,15 @@ _scroll_screen ; scroll only the screen memory
|
||||||
dex
|
dex
|
||||||
bpl -
|
bpl -
|
||||||
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_down (bool alsocolors @ Pc) clobbers(A) {
|
asmsub scroll_down (bool alsocolors @ Pc) clobbers(A,X) {
|
||||||
; ---- scroll the whole screen 1 character down
|
; ---- scroll the whole screen 1 character down
|
||||||
; contents of the top row are unchanged, you should refill/clear this yourself
|
; contents of the top row are unchanged, you should refill/clear this yourself
|
||||||
; Carry flag determines if screen color data must be scrolled too
|
; Carry flag determines if screen color data must be scrolled too
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc _scroll_screen
|
bcc _scroll_screen
|
||||||
|
|
||||||
+ ; scroll the screen and the color memory
|
+ ; scroll the screen and the color memory
|
||||||
|
@ -240,7 +233,6 @@ _scroll_screen ; scroll only the screen memory
|
||||||
dex
|
dex
|
||||||
bpl -
|
bpl -
|
||||||
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -265,10 +257,9 @@ asmsub print (str text @ AY) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
asmsub print_ub0 (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
pha
|
pha
|
||||||
tya
|
tya
|
||||||
|
@ -276,16 +267,13 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||||
pla
|
pla
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
txa
|
txa
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ub (ubyte value @ A) clobbers(A,Y) {
|
asmsub print_ub (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in decimal form, without left padding 0s
|
; ---- print the ubyte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
_print_byte_digits
|
_print_byte_digits
|
||||||
pha
|
pha
|
||||||
|
@ -301,16 +289,13 @@ _print_byte_digits
|
||||||
beq _ones
|
beq _ones
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
_ones txa
|
_ones txa
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_b (byte value @ A) clobbers(A,Y) {
|
asmsub print_b (byte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the byte in A in decimal form, without left padding 0s
|
; ---- print the byte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
pha
|
pha
|
||||||
cmp #0
|
cmp #0
|
||||||
bpl +
|
bpl +
|
||||||
|
@ -322,10 +307,9 @@ asmsub print_b (byte value @ A) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
bcc +
|
bcc +
|
||||||
pha
|
pha
|
||||||
lda #'$'
|
lda #'$'
|
||||||
|
@ -334,16 +318,13 @@ asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
+ jsr conv.ubyte2hex
|
+ jsr conv.ubyte2hex
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
tya
|
tya
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
bcc +
|
bcc +
|
||||||
lda #'%'
|
lda #'%'
|
||||||
|
@ -356,12 +337,11 @@ asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
+ jsr cbm.CHROUT
|
+ jsr cbm.CHROUT
|
||||||
dey
|
dey
|
||||||
bne -
|
bne -
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
pha
|
pha
|
||||||
|
@ -373,7 +353,7 @@ asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
||||||
; (if Carry is set, a radix prefix '$' is printed as well)
|
; (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
|
@ -386,10 +366,9 @@ asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
asmsub print_uw0 (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
|
@ -397,17 +376,14 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
iny
|
iny
|
||||||
bne -
|
bne -
|
||||||
+ ldx P8ZP_SCRATCH_REG
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uw (uword value @ AY) clobbers(A,Y) {
|
asmsub print_uw (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
beq _allzero
|
beq _allzero
|
||||||
|
@ -428,7 +404,7 @@ _allzero
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_w (word value @ AY) clobbers(A,Y) {
|
asmsub print_w (word value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
||||||
%asm {{
|
%asm {{
|
||||||
cpy #0
|
cpy #0
|
||||||
|
@ -582,15 +558,10 @@ _colormod sta $ffff ; modified
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) {
|
asmsub plot (ubyte col @ Y, ubyte row @ X) {
|
||||||
; ---- safe wrapper around PLOT kernal routine, to save the X register.
|
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
tax
|
|
||||||
clc
|
clc
|
||||||
jsr cbm.PLOT
|
jmp cbm.PLOT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,25 +8,22 @@ conv {
|
||||||
|
|
||||||
str @shared string_out = "????????????????" ; result buffer for the string conversion routines
|
str @shared string_out = "????????????????" ; result buffer for the string conversion routines
|
||||||
|
|
||||||
asmsub str_ub0 (ubyte value @ A) clobbers(A,Y) {
|
asmsub str_ub0 (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- convert the ubyte in A in decimal string form, with left padding 0s (3 positions total)
|
; ---- convert the ubyte in A in decimal string form, with left padding 0s (3 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
sty string_out
|
sty string_out
|
||||||
sta string_out+1
|
sta string_out+1
|
||||||
stx string_out+2
|
stx string_out+2
|
||||||
lda #0
|
lda #0
|
||||||
sta string_out+3
|
sta string_out+3
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str_ub (ubyte value @ A) clobbers(A,Y) {
|
asmsub str_ub (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- convert the ubyte in A in decimal string form, without left padding 0s
|
; ---- convert the ubyte in A in decimal string form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
ldy #0
|
ldy #0
|
||||||
sty P8ZP_SCRATCH_B1
|
sty P8ZP_SCRATCH_B1
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
|
@ -52,15 +49,13 @@ _output_byte_digits
|
||||||
iny
|
iny
|
||||||
lda #0
|
lda #0
|
||||||
sta string_out,y
|
sta string_out,y
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str_b (byte value @ A) clobbers(A,Y) {
|
asmsub str_b (byte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- convert the byte in A in decimal string form, without left padding 0s
|
; ---- convert the byte in A in decimal string form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
ldy #0
|
ldy #0
|
||||||
sty P8ZP_SCRATCH_B1
|
sty P8ZP_SCRATCH_B1
|
||||||
cmp #0
|
cmp #0
|
||||||
|
@ -75,7 +70,7 @@ asmsub str_b (byte value @ A) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str_ubhex (ubyte value @ A) clobbers(A,Y) {
|
asmsub str_ubhex (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- convert the ubyte in A in hex string form
|
; ---- convert the ubyte in A in hex string form
|
||||||
%asm {{
|
%asm {{
|
||||||
jsr conv.ubyte2hex
|
jsr conv.ubyte2hex
|
||||||
|
@ -87,7 +82,7 @@ asmsub str_ubhex (ubyte value @ A) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str_ubbin (ubyte value @ A) clobbers(A,Y) {
|
asmsub str_ubbin (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- convert the ubyte in A in binary string form
|
; ---- convert the ubyte in A in binary string form
|
||||||
%asm {{
|
%asm {{
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
|
@ -106,7 +101,7 @@ _digit sta string_out,y
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str_uwbin (uword value @ AY) clobbers(A,Y) {
|
asmsub str_uwbin (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- convert the uword in A/Y in binary string form
|
; ---- convert the uword in A/Y in binary string form
|
||||||
%asm {{
|
%asm {{
|
||||||
sta P8ZP_SCRATCH_REG
|
sta P8ZP_SCRATCH_REG
|
||||||
|
@ -145,10 +140,9 @@ asmsub str_uwhex (uword value @ AY) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str_uw0 (uword value @ AY) clobbers(A,Y) {
|
asmsub str_uw0 (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- convert the uword in A/Y in decimal string form, with left padding 0s (5 positions total)
|
; ---- convert the uword in A/Y in decimal string form, with left padding 0s (5 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
|
@ -156,15 +150,13 @@ asmsub str_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||||
beq +
|
beq +
|
||||||
iny
|
iny
|
||||||
bne -
|
bne -
|
||||||
+ ldx P8ZP_SCRATCH_REG
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str_uw (uword value @ AY) clobbers(A,Y) {
|
asmsub str_uw (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- convert the uword in A/Y in decimal string form, without left padding 0s
|
; ---- convert the uword in A/Y in decimal string form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldx #0
|
ldx #0
|
||||||
_output_digits
|
_output_digits
|
||||||
|
@ -182,7 +174,6 @@ _gotdigit sta string_out,x
|
||||||
bne _gotdigit
|
bne _gotdigit
|
||||||
_end lda #0
|
_end lda #0
|
||||||
sta string_out,x
|
sta string_out,x
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
_allzero lda #'0'
|
_allzero lda #'0'
|
||||||
|
@ -192,12 +183,11 @@ _allzero lda #'0'
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str_w (word value @ AY) clobbers(A,Y) {
|
asmsub str_w (word value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- convert the (signed) word in A/Y in decimal string form, without left padding 0's
|
; ---- convert the (signed) word in A/Y in decimal string form, without left padding 0's
|
||||||
%asm {{
|
%asm {{
|
||||||
cpy #0
|
cpy #0
|
||||||
bpl str_uw
|
bpl str_uw
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
pha
|
pha
|
||||||
lda #'-'
|
lda #'-'
|
||||||
sta string_out
|
sta string_out
|
||||||
|
@ -700,10 +690,9 @@ asmsub byte2decimal (byte value @A) -> ubyte @Y, ubyte @A, ubyte @X {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub ubyte2hex (ubyte value @A) -> ubyte @A, ubyte @Y {
|
asmsub ubyte2hex (ubyte value @A) clobbers(X) -> ubyte @A, ubyte @Y {
|
||||||
; ---- A to hex petscii string in AY (first hex char in A, second hex char in Y)
|
; ---- A to hex petscii string in AY (first hex char in A, second hex char in Y)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
pha
|
pha
|
||||||
and #$0f
|
and #$0f
|
||||||
tax
|
tax
|
||||||
|
@ -715,7 +704,6 @@ asmsub ubyte2hex (ubyte value @A) -> ubyte @A, ubyte @Y {
|
||||||
lsr a
|
lsr a
|
||||||
tax
|
tax
|
||||||
lda _hex_digits,x
|
lda _hex_digits,x
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
_hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
|
_hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
|
||||||
|
|
|
@ -490,7 +490,6 @@ io_error:
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
lda address+1
|
lda address+1
|
||||||
sta P8ZP_SCRATCH_W1+1
|
sta P8ZP_SCRATCH_W1+1
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
ldx end_address
|
ldx end_address
|
||||||
ldy end_address+1
|
ldy end_address+1
|
||||||
lda headerless
|
lda headerless
|
||||||
|
@ -501,7 +500,6 @@ io_error:
|
||||||
+ lda #<P8ZP_SCRATCH_W1
|
+ lda #<P8ZP_SCRATCH_W1
|
||||||
jsr cbm.SAVE
|
jsr cbm.SAVE
|
||||||
+ php
|
+ php
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
plp
|
plp
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -549,7 +547,6 @@ io_error:
|
||||||
secondary |= %00000010 ; activate cx16 kernal headerless load support
|
secondary |= %00000010 ; activate cx16 kernal headerless load support
|
||||||
cbm.SETLFS(1, drivenumber, secondary)
|
cbm.SETLFS(1, drivenumber, secondary)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #0
|
lda #0
|
||||||
ldx address_override
|
ldx address_override
|
||||||
ldy address_override+1
|
ldy address_override+1
|
||||||
|
@ -557,7 +554,7 @@ io_error:
|
||||||
bcs +
|
bcs +
|
||||||
stx cx16.r1
|
stx cx16.r1
|
||||||
sty cx16.r1+1
|
sty cx16.r1+1
|
||||||
+ ldx P8ZP_SCRATCH_REG
|
+
|
||||||
}}
|
}}
|
||||||
|
|
||||||
cbm.CLRCHN()
|
cbm.CLRCHN()
|
||||||
|
@ -609,14 +606,13 @@ io_error:
|
||||||
return $2000 * (cx16.getrambank() - startbank) + endaddress - startaddress
|
return $2000 * (cx16.getrambank() - startbank) + endaddress - startaddress
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub vload(str name @R0, ubyte bank @A, uword address @R1) -> ubyte @A {
|
asmsub vload(str name @R0, ubyte bank @A, uword address @R1) clobbers(X, Y) -> ubyte @A {
|
||||||
; -- like the basic command VLOAD "filename",drivenumber,bank,address
|
; -- like the basic command VLOAD "filename",drivenumber,bank,address
|
||||||
; loads a file into Vera's video memory in the given bank:address, returns success in A
|
; loads a file into Vera's video memory in the given bank:address, returns success in A
|
||||||
; the file has to have the usual 2 byte header (which will be skipped)
|
; the file has to have the usual 2 byte header (which will be skipped)
|
||||||
%asm {{
|
%asm {{
|
||||||
clc
|
clc
|
||||||
internal_vload:
|
internal_vload:
|
||||||
phx
|
|
||||||
pha
|
pha
|
||||||
ldx drivenumber
|
ldx drivenumber
|
||||||
bcc +
|
bcc +
|
||||||
|
@ -644,13 +640,12 @@ internal_vload:
|
||||||
+ jsr cbm.CLRCHN
|
+ jsr cbm.CLRCHN
|
||||||
lda #1
|
lda #1
|
||||||
jsr cbm.CLOSE
|
jsr cbm.CLOSE
|
||||||
plx
|
|
||||||
lda P8ZP_SCRATCH_B1
|
lda P8ZP_SCRATCH_B1
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub vload_raw(str name @R0, ubyte bank @A, uword address @R1) -> ubyte @A {
|
asmsub vload_raw(str name @R0, ubyte bank @A, uword address @R1) clobbers(X, Y) -> ubyte @A {
|
||||||
; -- like the basic command BVLOAD "filename",drivenumber,bank,address
|
; -- like the basic command BVLOAD "filename",drivenumber,bank,address
|
||||||
; loads a file into Vera's video memory in the given bank:address, returns success in A
|
; loads a file into Vera's video memory in the given bank:address, returns success in A
|
||||||
; the file is read fully including the first two bytes.
|
; the file is read fully including the first two bytes.
|
||||||
|
|
|
@ -99,14 +99,11 @@ asmsub FREADSA (byte value @A) clobbers(A,X,Y) {
|
||||||
asmsub GIVUAYFAY (uword value @ AY) clobbers(A,X,Y) {
|
asmsub GIVUAYFAY (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- unsigned 16 bit word in A/Y (lo/hi) to fac1
|
; ---- unsigned 16 bit word in A/Y (lo/hi) to fac1
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
sty $c4 ; facmo ($64 on c128)
|
sty $c4 ; facmo ($64 on c128)
|
||||||
sta $c5 ; facmo+1 ($65 on c128)
|
sta $c5 ; facmo+1 ($65 on c128)
|
||||||
ldx #$90
|
ldx #$90
|
||||||
sec
|
sec
|
||||||
jsr FLOATC
|
jmp FLOATC
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,11 +141,8 @@ asmsub FREADUY (ubyte value @Y) {
|
||||||
|
|
||||||
sub rndf() -> float {
|
sub rndf() -> float {
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
lda #1
|
lda #1
|
||||||
jsr RND_0
|
jmp RND_0
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
; mode 6 = bitmap 640 x 480 x 4c
|
; mode 6 = bitmap 640 x 480 x 4c
|
||||||
; higher color dephts in highres are not supported due to lack of VRAM
|
; higher color dephts in highres are not supported due to lack of VRAM
|
||||||
|
|
||||||
; TODO remove the phx/plx pairs in non-stack compiler version
|
|
||||||
|
|
||||||
gfx2 {
|
gfx2 {
|
||||||
|
|
||||||
%option no_symbol_prefixing
|
%option no_symbol_prefixing
|
||||||
|
@ -223,7 +221,6 @@ _done
|
||||||
position(x, y)
|
position(x, y)
|
||||||
%asm {{
|
%asm {{
|
||||||
lda color
|
lda color
|
||||||
phx
|
|
||||||
ldx length+1
|
ldx length+1
|
||||||
beq +
|
beq +
|
||||||
ldy #0
|
ldy #0
|
||||||
|
@ -237,7 +234,7 @@ _done
|
||||||
- sta cx16.VERA_DATA0
|
- sta cx16.VERA_DATA0
|
||||||
dey
|
dey
|
||||||
bne -
|
bne -
|
||||||
+ plx
|
+
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
6 -> {
|
6 -> {
|
||||||
|
@ -262,7 +259,6 @@ _done
|
||||||
sta cx16.VERA_ADDR_L
|
sta cx16.VERA_ADDR_L
|
||||||
lda cx16.r0+1
|
lda cx16.r0+1
|
||||||
sta cx16.VERA_ADDR_M
|
sta cx16.VERA_ADDR_M
|
||||||
phx
|
|
||||||
ldx x
|
ldx x
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -285,10 +281,6 @@ _done
|
||||||
+ inx ; next pixel
|
+ inx ; next pixel
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
%asm {{
|
|
||||||
plx
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -923,13 +915,12 @@ skip:
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub next_pixels(uword pixels @AY, uword amount @R0) clobbers(A, Y) {
|
asmsub next_pixels(uword pixels @AY, uword amount @R0) clobbers(A, X, Y) {
|
||||||
; -- sets the next bunch of pixels from a prepared array of bytes.
|
; -- sets the next bunch of pixels from a prepared array of bytes.
|
||||||
; for 8 bpp screens this will plot 1 pixel per byte.
|
; for 8 bpp screens this will plot 1 pixel per byte.
|
||||||
; for 1 bpp screens it will plot 8 pixels at once (colors are the bit patterns per byte).
|
; for 1 bpp screens it will plot 8 pixels at once (colors are the bit patterns per byte).
|
||||||
; for 2 bpp screens it will plot 4 pixels at once (colors are the bit patterns per byte).
|
; for 2 bpp screens it will plot 4 pixels at once (colors are the bit patterns per byte).
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
sty P8ZP_SCRATCH_W1+1
|
sty P8ZP_SCRATCH_W1+1
|
||||||
ldx cx16.r0+1
|
ldx cx16.r0+1
|
||||||
|
@ -951,14 +942,13 @@ skip:
|
||||||
iny
|
iny
|
||||||
dex
|
dex
|
||||||
bne -
|
bne -
|
||||||
+ plx
|
+ rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub set_8_pixels_from_bits(ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) {
|
asmsub set_8_pixels_from_bits(ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) clobbers(X) {
|
||||||
; this is only useful in 256 color mode where one pixel equals one byte value.
|
; this is only useful in 256 color mode where one pixel equals one byte value.
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
ldx #8
|
ldx #8
|
||||||
- asl cx16.r0
|
- asl cx16.r0
|
||||||
bcc +
|
bcc +
|
||||||
|
@ -967,7 +957,6 @@ skip:
|
||||||
+ sty cx16.VERA_DATA0
|
+ sty cx16.VERA_DATA0
|
||||||
+ dex
|
+ dex
|
||||||
bne -
|
bne -
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -999,7 +988,6 @@ skip:
|
||||||
cx16.vaddr_autoincr(charset_bank, chardataptr, 0, 1)
|
cx16.vaddr_autoincr(charset_bank, chardataptr, 0, 1)
|
||||||
%asm {{
|
%asm {{
|
||||||
; pre-shift the bits
|
; pre-shift the bits
|
||||||
phx ; TODO remove in non-stack version
|
|
||||||
lda text.x
|
lda text.x
|
||||||
and #7
|
and #7
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
|
@ -1019,7 +1007,6 @@ skip:
|
||||||
iny
|
iny
|
||||||
cpy #8
|
cpy #8
|
||||||
bne --
|
bne --
|
||||||
plx ; TODO remove in non-stack version
|
|
||||||
}}
|
}}
|
||||||
; left part of shifted char
|
; left part of shifted char
|
||||||
position2(x, y, true)
|
position2(x, y, true)
|
||||||
|
@ -1086,7 +1073,6 @@ skip:
|
||||||
position(x,y)
|
position(x,y)
|
||||||
y++
|
y++
|
||||||
%asm {{
|
%asm {{
|
||||||
phx ; TODO remove in non-stack version
|
|
||||||
ldx color
|
ldx color
|
||||||
lda cx16.VERA_DATA1
|
lda cx16.VERA_DATA1
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
|
@ -1098,7 +1084,6 @@ skip:
|
||||||
+ lda cx16.VERA_DATA0 ; don't write a pixel, but do advance to the next address
|
+ lda cx16.VERA_DATA0 ; don't write a pixel, but do advance to the next address
|
||||||
+ dey
|
+ dey
|
||||||
bne -
|
bne -
|
||||||
plx ; TODO remove in non-stack version
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
x+=8
|
x+=8
|
||||||
|
|
|
@ -53,25 +53,21 @@ romsub $FFF3 = IOBASE() -> uword @ XY ; read base addr
|
||||||
|
|
||||||
; ---- utility
|
; ---- utility
|
||||||
|
|
||||||
asmsub STOP2() -> ubyte @A {
|
asmsub STOP2() clobbers(X) -> ubyte @A {
|
||||||
; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag.
|
; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag.
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr cbm.STOP
|
jsr cbm.STOP
|
||||||
beq +
|
beq +
|
||||||
plx
|
|
||||||
lda #0
|
lda #0
|
||||||
rts
|
rts
|
||||||
+ plx
|
+ lda #1
|
||||||
lda #1
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub RDTIM16() -> uword @AY {
|
asmsub RDTIM16() clobbers(X) -> uword @AY {
|
||||||
; -- like RDTIM() but only returning the lower 16 bits in AY for convenience. Also avoids ram bank issue for irqs.
|
; -- like RDTIM() but only returning the lower 16 bits in AY for convenience. Also avoids ram bank issue for irqs.
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
php
|
php
|
||||||
sei
|
sei
|
||||||
jsr cbm.RDTIM
|
jsr cbm.RDTIM
|
||||||
|
@ -81,7 +77,6 @@ asmsub RDTIM16() -> uword @AY {
|
||||||
txa
|
txa
|
||||||
tay
|
tay
|
||||||
pla
|
pla
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -454,15 +449,12 @@ asmsub mouse_config2(ubyte shape @A) clobbers (A, X, Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub mouse_pos() -> ubyte @A {
|
asmsub mouse_pos() clobbers(X) -> ubyte @A {
|
||||||
; -- short wrapper around mouse_get() kernal routine:
|
; -- short wrapper around mouse_get() kernal routine:
|
||||||
; -- gets the position of the mouse cursor in cx16.r0 and cx16.r1 (x/y coordinate), returns mouse button status.
|
; -- gets the position of the mouse cursor in cx16.r0 and cx16.r1 (x/y coordinate), returns mouse button status.
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
ldx #cx16.r0
|
ldx #cx16.r0
|
||||||
jsr cx16.mouse_get
|
jmp cx16.mouse_get
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,7 +492,7 @@ inline asmsub getrambank() -> ubyte @A {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub numbanks() -> uword @AY {
|
asmsub numbanks() clobbers(X) -> uword @AY {
|
||||||
; -- Returns the number of available RAM banks according to the kernal (each bank is 8 Kb).
|
; -- Returns the number of available RAM banks according to the kernal (each bank is 8 Kb).
|
||||||
; Note that the number of such banks can be 256 so a word is returned.
|
; Note that the number of such banks can be 256 so a word is returned.
|
||||||
; But just looking at the A register (the LSB of the result word) could suffice if you know that A=0 means 256 banks:
|
; But just looking at the A register (the LSB of the result word) could suffice if you know that A=0 means 256 banks:
|
||||||
|
@ -508,15 +500,13 @@ asmsub numbanks() -> uword @AY {
|
||||||
; Kernal's MEMTOP routine reports 0 in this case but that doesn't mean 'zero banks', instead it means 256 banks,
|
; Kernal's MEMTOP routine reports 0 in this case but that doesn't mean 'zero banks', instead it means 256 banks,
|
||||||
; as there is no X16 without at least 1 page of banked RAM. So this routine returns 256 instead of 0.
|
; as there is no X16 without at least 1 page of banked RAM. So this routine returns 256 instead of 0.
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
sec
|
sec
|
||||||
jsr cbm.MEMTOP
|
jsr cbm.MEMTOP
|
||||||
ldy #0
|
ldy #0
|
||||||
cmp #0
|
cmp #0
|
||||||
bne +
|
bne +
|
||||||
iny
|
iny
|
||||||
+ plx
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -956,10 +946,6 @@ _irq_handler_init
|
||||||
sta IRQ_SCRATCH_ZPWORD2
|
sta IRQ_SCRATCH_ZPWORD2
|
||||||
lda P8ZP_SCRATCH_W2+1
|
lda P8ZP_SCRATCH_W2+1
|
||||||
sta IRQ_SCRATCH_ZPWORD2+1
|
sta IRQ_SCRATCH_ZPWORD2+1
|
||||||
; Set X to the bottom 32 bytes of the evaluation stack, to HOPEFULLY not clobber it.
|
|
||||||
; This leaves 128-32=96 stack entries for the main program, and 32 stack entries for the IRQ handler.
|
|
||||||
; We assume IRQ handlers don't contain complex expressions taking up more than that.
|
|
||||||
ldx #32
|
|
||||||
cld
|
cld
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
@ -1079,19 +1065,17 @@ asmsub set_rasterline(uword line @AY) {
|
||||||
void cx16.i2c_write_byte($42, $05, activity)
|
void cx16.i2c_write_byte($42, $05, activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub wait(uword jiffies @AY) {
|
asmsub wait(uword jiffies @AY) clobbers(X) {
|
||||||
; --- wait approximately the given number of jiffies (1/60th seconds) (N or N+1)
|
; --- wait approximately the given number of jiffies (1/60th seconds) (N or N+1)
|
||||||
; note: the system irq handler has to be active for this to work as it depends on the system jiffy clock
|
; note: the system irq handler has to be active for this to work as it depends on the system jiffy clock
|
||||||
; note: this routine cannot be used from inside a irq handler
|
; note: this routine cannot be used from inside a irq handler
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
sty P8ZP_SCRATCH_W1+1
|
sty P8ZP_SCRATCH_W1+1
|
||||||
|
|
||||||
_loop lda P8ZP_SCRATCH_W1
|
_loop lda P8ZP_SCRATCH_W1
|
||||||
ora P8ZP_SCRATCH_W1+1
|
ora P8ZP_SCRATCH_W1+1
|
||||||
bne +
|
bne +
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
+ sei
|
+ sei
|
||||||
|
|
|
@ -42,11 +42,10 @@ asmsub column(ubyte col @A) clobbers(A, X, Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub fill_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) {
|
asmsub fill_screen (ubyte char @ A, ubyte color @ Y) clobbers(A, X) {
|
||||||
; ---- fill the character screen with the given fill character and character color.
|
; ---- fill the character screen with the given fill character and character color.
|
||||||
%asm {{
|
%asm {{
|
||||||
sty _ly+1
|
sty _ly+1
|
||||||
phx
|
|
||||||
pha
|
pha
|
||||||
jsr cbm.SCREEN ; get dimensions in X/Y
|
jsr cbm.SCREEN ; get dimensions in X/Y
|
||||||
txa
|
txa
|
||||||
|
@ -75,8 +74,7 @@ _ly ldy #1 ; modified
|
||||||
stz cx16.VERA_ADDR_L
|
stz cx16.VERA_ADDR_L
|
||||||
inc cx16.VERA_ADDR_M ; next line
|
inc cx16.VERA_ADDR_M ; next line
|
||||||
bra _lx
|
bra _lx
|
||||||
+ plx
|
+ rts
|
||||||
rts
|
|
||||||
|
|
||||||
set_vera_textmatrix_addresses:
|
set_vera_textmatrix_addresses:
|
||||||
stz cx16.VERA_CTRL
|
stz cx16.VERA_CTRL
|
||||||
|
@ -90,11 +88,10 @@ set_vera_textmatrix_addresses:
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub clear_screenchars (ubyte char @ A) clobbers(Y) {
|
asmsub clear_screenchars (ubyte char @ A) clobbers(X, Y) {
|
||||||
; ---- clear the character screen with the given fill character (leaves colors)
|
; ---- clear the character screen with the given fill character (leaves colors)
|
||||||
; (assumes screen matrix is at the default address)
|
; (assumes screen matrix is at the default address)
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
pha
|
pha
|
||||||
jsr cbm.SCREEN ; get dimensions in X/Y
|
jsr cbm.SCREEN ; get dimensions in X/Y
|
||||||
txa
|
txa
|
||||||
|
@ -116,16 +113,14 @@ _lx ldx #0 ; modified
|
||||||
stz cx16.VERA_ADDR_L
|
stz cx16.VERA_ADDR_L
|
||||||
inc cx16.VERA_ADDR_M ; next line
|
inc cx16.VERA_ADDR_M ; next line
|
||||||
bra _lx
|
bra _lx
|
||||||
+ plx
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub clear_screencolors (ubyte color @ A) clobbers(Y) {
|
asmsub clear_screencolors (ubyte color @ A) clobbers(X, Y) {
|
||||||
; ---- clear the character screen colors with the given color (leaves characters).
|
; ---- clear the character screen colors with the given color (leaves characters).
|
||||||
; (assumes color matrix is at the default address)
|
; (assumes color matrix is at the default address)
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
sta _la+1
|
sta _la+1
|
||||||
jsr cbm.SCREEN ; get dimensions in X/Y
|
jsr cbm.SCREEN ; get dimensions in X/Y
|
||||||
txa
|
txa
|
||||||
|
@ -150,8 +145,7 @@ _la lda #0 ; modified
|
||||||
sta cx16.VERA_ADDR_L
|
sta cx16.VERA_ADDR_L
|
||||||
inc cx16.VERA_ADDR_M ; next line
|
inc cx16.VERA_ADDR_M ; next line
|
||||||
bra _lx
|
bra _lx
|
||||||
+ plx
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,11 +186,10 @@ sub iso_off() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
asmsub scroll_left() clobbers(A, Y) {
|
asmsub scroll_left() clobbers(A, X, Y) {
|
||||||
; ---- scroll the whole screen 1 character to the left
|
; ---- scroll the whole screen 1 character to the left
|
||||||
; contents of the rightmost column are unchanged, you should clear/refill this yourself
|
; contents of the rightmost column are unchanged, you should clear/refill this yourself
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr cbm.SCREEN
|
jsr cbm.SCREEN
|
||||||
dex
|
dex
|
||||||
stx _lx+1
|
stx _lx+1
|
||||||
|
@ -233,16 +226,14 @@ _lx ldx #0 ; modified
|
||||||
|
|
||||||
lda #0
|
lda #0
|
||||||
sta cx16.VERA_CTRL
|
sta cx16.VERA_CTRL
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_right() clobbers(A,Y) {
|
asmsub scroll_right() clobbers(A,X,Y) {
|
||||||
; ---- scroll the whole screen 1 character to the right
|
; ---- scroll the whole screen 1 character to the right
|
||||||
; contents of the leftmost column are unchanged, you should clear/refill this yourself
|
; contents of the leftmost column are unchanged, you should clear/refill this yourself
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr cbm.SCREEN
|
jsr cbm.SCREEN
|
||||||
dex
|
dex
|
||||||
stx _lx+1
|
stx _lx+1
|
||||||
|
@ -287,16 +278,14 @@ _lx ldx #0 ; modified
|
||||||
|
|
||||||
lda #0
|
lda #0
|
||||||
sta cx16.VERA_CTRL
|
sta cx16.VERA_CTRL
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_up() clobbers(A, Y) {
|
asmsub scroll_up() clobbers(A, X, Y) {
|
||||||
; ---- scroll the whole screen 1 character up
|
; ---- scroll the whole screen 1 character up
|
||||||
; contents of the bottom row are unchanged, you should refill/clear this yourself
|
; contents of the bottom row are unchanged, you should refill/clear this yourself
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr cbm.SCREEN
|
jsr cbm.SCREEN
|
||||||
stx _nextline+1
|
stx _nextline+1
|
||||||
dey
|
dey
|
||||||
|
@ -337,16 +326,14 @@ _nextline
|
||||||
|
|
||||||
+ lda #0
|
+ lda #0
|
||||||
sta cx16.VERA_CTRL
|
sta cx16.VERA_CTRL
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub scroll_down() clobbers(A, Y) {
|
asmsub scroll_down() clobbers(A, X, Y) {
|
||||||
; ---- scroll the whole screen 1 character down
|
; ---- scroll the whole screen 1 character down
|
||||||
; contents of the top row are unchanged, you should refill/clear this yourself
|
; contents of the top row are unchanged, you should refill/clear this yourself
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr cbm.SCREEN
|
jsr cbm.SCREEN
|
||||||
stx _nextline+1
|
stx _nextline+1
|
||||||
dey
|
dey
|
||||||
|
@ -393,7 +380,6 @@ _nextline
|
||||||
|
|
||||||
+ lda #0
|
+ lda #0
|
||||||
sta cx16.VERA_CTRL
|
sta cx16.VERA_CTRL
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -418,10 +404,9 @@ asmsub print (str text @ AY) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
asmsub print_ub0 (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
pha
|
pha
|
||||||
tya
|
tya
|
||||||
|
@ -429,16 +414,13 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||||
pla
|
pla
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
txa
|
txa
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ub (ubyte value @ A) clobbers(A,Y) {
|
asmsub print_ub (ubyte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in decimal form, without left padding 0s
|
; ---- print the ubyte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
_print_byte_digits
|
_print_byte_digits
|
||||||
pha
|
pha
|
||||||
|
@ -454,16 +436,13 @@ _print_byte_digits
|
||||||
beq _ones
|
beq _ones
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
_ones txa
|
_ones txa
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_b (byte value @ A) clobbers(A,Y) {
|
asmsub print_b (byte value @ A) clobbers(A,X,Y) {
|
||||||
; ---- print the byte in A in decimal form, without left padding 0s
|
; ---- print the byte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
pha
|
pha
|
||||||
cmp #0
|
cmp #0
|
||||||
bpl +
|
bpl +
|
||||||
|
@ -475,10 +454,9 @@ asmsub print_b (byte value @ A) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
bcc +
|
bcc +
|
||||||
pha
|
pha
|
||||||
lda #'$'
|
lda #'$'
|
||||||
|
@ -487,16 +465,13 @@ asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
+ jsr conv.ubyte2hex
|
+ jsr conv.ubyte2hex
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
tya
|
tya
|
||||||
jsr cbm.CHROUT
|
jmp cbm.CHROUT
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
bcc +
|
bcc +
|
||||||
lda #'%'
|
lda #'%'
|
||||||
|
@ -509,12 +484,11 @@ asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
+ jsr cbm.CHROUT
|
+ jsr cbm.CHROUT
|
||||||
dey
|
dey
|
||||||
bne -
|
bne -
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
pha
|
pha
|
||||||
|
@ -526,7 +500,7 @@ asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
||||||
; (if Carry is set, a radix prefix '$' is printed as well)
|
; (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
%asm {{
|
%asm {{
|
||||||
|
@ -539,10 +513,9 @@ asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
asmsub print_uw0 (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
|
@ -550,17 +523,14 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
iny
|
iny
|
||||||
bne -
|
bne -
|
||||||
+ plx
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_uw (uword value @ AY) clobbers(A,Y) {
|
asmsub print_uw (uword value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr conv.uword2decimal
|
jsr conv.uword2decimal
|
||||||
plx
|
|
||||||
ldy #0
|
ldy #0
|
||||||
- lda conv.uword2decimal.decTenThousands,y
|
- lda conv.uword2decimal.decTenThousands,y
|
||||||
beq _allzero
|
beq _allzero
|
||||||
|
@ -581,7 +551,7 @@ _allzero
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_w (word value @ AY) clobbers(A,Y) {
|
asmsub print_w (word value @ AY) clobbers(A,X,Y) {
|
||||||
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
||||||
%asm {{
|
%asm {{
|
||||||
cpy #0
|
cpy #0
|
||||||
|
@ -704,12 +674,11 @@ asmsub getclr (ubyte col @A, ubyte row @Y) -> ubyte @ A {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) {
|
sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) {
|
||||||
; ---- set char+color at the given position on the screen
|
; ---- set char+color at the given position on the screen
|
||||||
; note: color handling is the same as on the C64: it only sets the foreground color and leaves the background color as is.
|
; note: color handling is the same as on the C64: it only sets the foreground color and leaves the background color as is.
|
||||||
; Use setcc2 if you want Cx-16 specific feature of setting both Bg+Fg colors (is faster as well).
|
; Use setcc2 if you want Cx-16 specific feature of setting both Bg+Fg colors (is faster as well).
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
lda column
|
lda column
|
||||||
asl a
|
asl a
|
||||||
tax
|
tax
|
||||||
|
@ -732,7 +701,6 @@ sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) {
|
||||||
and #$f0
|
and #$f0
|
||||||
ora P8ZP_SCRATCH_B1
|
ora P8ZP_SCRATCH_B1
|
||||||
sta cx16.VERA_DATA0
|
sta cx16.VERA_DATA0
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -742,7 +710,6 @@ sub setcc2 (ubyte column, ubyte row, ubyte char, ubyte colors) {
|
||||||
; note: on the CommanderX16 this allows you to set both Fg and Bg colors;
|
; note: on the CommanderX16 this allows you to set both Fg and Bg colors;
|
||||||
; use the high nybble in A to set the Bg color! Is a bit faster than setcc() too.
|
; use the high nybble in A to set the Bg color! Is a bit faster than setcc() too.
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
lda column
|
lda column
|
||||||
asl a
|
asl a
|
||||||
tax
|
tax
|
||||||
|
@ -760,20 +727,14 @@ sub setcc2 (ubyte column, ubyte row, ubyte char, ubyte colors) {
|
||||||
inc cx16.VERA_ADDR_L
|
inc cx16.VERA_ADDR_L
|
||||||
lda colors
|
lda colors
|
||||||
sta cx16.VERA_DATA0
|
sta cx16.VERA_DATA0
|
||||||
plx
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) {
|
asmsub plot (ubyte col @ Y, ubyte row @ X) {
|
||||||
; ---- safe wrapper around PLOT kernal routine, to save the X register.
|
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
tax
|
|
||||||
clc
|
clc
|
||||||
jsr cbm.PLOT
|
jmp cbm.PLOT
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -455,13 +455,11 @@ io_error:
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
lda address+1
|
lda address+1
|
||||||
sta P8ZP_SCRATCH_W1+1
|
sta P8ZP_SCRATCH_W1+1
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #<P8ZP_SCRATCH_W1
|
lda #<P8ZP_SCRATCH_W1
|
||||||
ldx end_address
|
ldx end_address
|
||||||
ldy end_address+1
|
ldy end_address+1
|
||||||
jsr cbm.SAVE
|
jsr cbm.SAVE
|
||||||
php
|
php
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
plp
|
plp
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -488,7 +486,6 @@ io_error:
|
||||||
secondary = 0
|
secondary = 0
|
||||||
cbm.SETLFS(1, drivenumber, secondary)
|
cbm.SETLFS(1, drivenumber, secondary)
|
||||||
%asm {{
|
%asm {{
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #0
|
lda #0
|
||||||
ldx address_override
|
ldx address_override
|
||||||
ldy address_override+1
|
ldy address_override+1
|
||||||
|
@ -496,7 +493,7 @@ io_error:
|
||||||
bcs +
|
bcs +
|
||||||
stx cx16.r1
|
stx cx16.r1
|
||||||
sty cx16.r1+1
|
sty cx16.r1+1
|
||||||
+ ldx P8ZP_SCRATCH_REG
|
+
|
||||||
}}
|
}}
|
||||||
|
|
||||||
cbm.CLRCHN()
|
cbm.CLRCHN()
|
||||||
|
|
|
@ -5,7 +5,6 @@ floats {
|
||||||
sub print_f(float value) {
|
sub print_f(float value) {
|
||||||
; ---- prints the floating point value (without a newline).
|
; ---- prints the floating point value (without a newline).
|
||||||
%asm {{
|
%asm {{
|
||||||
stx floats_store_reg
|
|
||||||
lda #<value
|
lda #<value
|
||||||
ldy #>value
|
ldy #>value
|
||||||
jsr MOVFM ; load float into fac1
|
jsr MOVFM ; load float into fac1
|
||||||
|
@ -18,8 +17,7 @@ sub print_f(float value) {
|
||||||
jsr cbm.CHROUT
|
jsr cbm.CHROUT
|
||||||
iny
|
iny
|
||||||
bne -
|
bne -
|
||||||
+ ldx floats_store_reg
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +42,7 @@ sub sin(float angle) -> float {
|
||||||
lda #<angle
|
lda #<angle
|
||||||
ldy #>angle
|
ldy #>angle
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
jmp SIN
|
||||||
jsr SIN
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,9 +51,7 @@ sub cos(float angle) -> float {
|
||||||
lda #<angle
|
lda #<angle
|
||||||
ldy #>angle
|
ldy #>angle
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
jmp COS
|
||||||
jsr COS
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -68,10 +61,7 @@ sub tan(float value) -> float {
|
||||||
lda #<value
|
lda #<value
|
||||||
ldy #>value
|
ldy #>value
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
jmp TAN
|
||||||
jsr TAN
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,10 +70,7 @@ sub atan(float value) -> float {
|
||||||
lda #<value
|
lda #<value
|
||||||
ldy #>value
|
ldy #>value
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
jmp ATN
|
||||||
jsr ATN
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,10 +79,7 @@ sub ln(float value) -> float {
|
||||||
lda #<value
|
lda #<value
|
||||||
ldy #>value
|
ldy #>value
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
jmp LOG
|
||||||
jsr LOG
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,15 +88,12 @@ sub log2(float value) -> float {
|
||||||
lda #<value
|
lda #<value
|
||||||
ldy #>value
|
ldy #>value
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr LOG
|
jsr LOG
|
||||||
jsr MOVEF
|
jsr MOVEF
|
||||||
lda #<FL_LOG2_const
|
lda #<FL_LOG2_const
|
||||||
ldy #>FL_LOG2_const
|
ldy #>FL_LOG2_const
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
jsr FDIVT
|
jmp FDIVT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,12 +103,9 @@ sub rad(float angle) -> float {
|
||||||
lda #<angle
|
lda #<angle
|
||||||
ldy #>angle
|
ldy #>angle
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #<_pi_div_180
|
lda #<_pi_div_180
|
||||||
ldy #>_pi_div_180
|
ldy #>_pi_div_180
|
||||||
jsr FMULT
|
jmp FMULT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
_pi_div_180 .byte 123, 14, 250, 53, 18 ; pi / 180
|
_pi_div_180 .byte 123, 14, 250, 53, 18 ; pi / 180
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -138,11 +116,9 @@ sub deg(float angle) -> float {
|
||||||
lda #<angle
|
lda #<angle
|
||||||
ldy #>angle
|
ldy #>angle
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #<_one_over_pi_div_180
|
lda #<_one_over_pi_div_180
|
||||||
ldy #>_one_over_pi_div_180
|
ldy #>_one_over_pi_div_180
|
||||||
jsr FMULT
|
jmp FMULT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
_one_over_pi_div_180 .byte 134, 101, 46, 224, 211 ; 1 / (pi * 180)
|
_one_over_pi_div_180 .byte 134, 101, 46, 224, 211 ; 1 / (pi * 180)
|
||||||
}}
|
}}
|
||||||
|
@ -153,11 +129,8 @@ sub round(float value) -> float {
|
||||||
lda #<value
|
lda #<value
|
||||||
ldy #>value
|
ldy #>value
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr FADDH
|
jsr FADDH
|
||||||
jsr INT
|
jmp INT
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,10 +139,7 @@ sub floor(float value) -> float {
|
||||||
lda #<value
|
lda #<value
|
||||||
ldy #>value
|
ldy #>value
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
jmp INT
|
||||||
jsr INT
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +149,6 @@ sub ceil(float value) -> float {
|
||||||
lda #<value
|
lda #<value
|
||||||
ldy #>value
|
ldy #>value
|
||||||
jsr MOVFM
|
jsr MOVFM
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
ldx #<fmath_float1
|
ldx #<fmath_float1
|
||||||
ldy #>fmath_float1
|
ldy #>fmath_float1
|
||||||
jsr MOVMF
|
jsr MOVMF
|
||||||
|
@ -192,8 +161,7 @@ sub ceil(float value) -> float {
|
||||||
lda #<FL_ONE_const
|
lda #<FL_ONE_const
|
||||||
ldy #>FL_ONE_const
|
ldy #>FL_ONE_const
|
||||||
jsr FADD
|
jsr FADD
|
||||||
+ ldx P8ZP_SCRATCH_REG
|
+ rts
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,14 +170,11 @@ sub rndseedf(float seed) {
|
||||||
seed = -seed ; make sure fp seed is always negative
|
seed = -seed ; make sure fp seed is always negative
|
||||||
|
|
||||||
%asm {{
|
%asm {{
|
||||||
stx floats_store_reg
|
|
||||||
lda #<seed
|
lda #<seed
|
||||||
ldy #>seed
|
ldy #>seed
|
||||||
jsr MOVFM ; load float into fac1
|
jsr MOVFM ; load float into fac1
|
||||||
lda #-1
|
lda #-1
|
||||||
jsr floats.RND
|
jmp floats.RND
|
||||||
ldx floats_store_reg
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,6 @@
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
math_store_reg .byte 0 ; temporary storage
|
|
||||||
|
|
||||||
|
|
||||||
multiply_bytes .proc
|
multiply_bytes .proc
|
||||||
; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned)
|
; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned)
|
||||||
sta P8ZP_SCRATCH_B1 ; num1
|
sta P8ZP_SCRATCH_B1 ; num1
|
||||||
|
@ -30,7 +27,6 @@ multiply_bytes_into_word .proc
|
||||||
; -- multiply 2 bytes A and Y, result as word in A/Y (unsigned)
|
; -- multiply 2 bytes A and Y, result as word in A/Y (unsigned)
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
sty P8ZP_SCRATCH_REG
|
sty P8ZP_SCRATCH_REG
|
||||||
stx math_store_reg
|
|
||||||
lda #0
|
lda #0
|
||||||
ldx #8
|
ldx #8
|
||||||
lsr P8ZP_SCRATCH_B1
|
lsr P8ZP_SCRATCH_B1
|
||||||
|
@ -43,7 +39,6 @@ multiply_bytes_into_word .proc
|
||||||
bne -
|
bne -
|
||||||
tay
|
tay
|
||||||
lda P8ZP_SCRATCH_B1
|
lda P8ZP_SCRATCH_B1
|
||||||
ldx math_store_reg
|
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
@ -55,7 +50,6 @@ multiply_words .proc
|
||||||
|
|
||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
sty P8ZP_SCRATCH_W2+1
|
sty P8ZP_SCRATCH_W2+1
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
|
|
||||||
mult16 lda #0
|
mult16 lda #0
|
||||||
sta result+2 ; clear upper bits of product
|
sta result+2 ; clear upper bits of product
|
||||||
|
@ -77,7 +71,6 @@ mult16 lda #0
|
||||||
ror result
|
ror result
|
||||||
dex
|
dex
|
||||||
bne -
|
bne -
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
lda result
|
lda result
|
||||||
ldy result+1
|
ldy result+1
|
||||||
rts
|
rts
|
||||||
|
@ -124,7 +117,6 @@ divmod_ub_asm .proc
|
||||||
; division by zero will result in quotient = 255 and remainder = original number
|
; division by zero will result in quotient = 255 and remainder = original number
|
||||||
sty P8ZP_SCRATCH_REG
|
sty P8ZP_SCRATCH_REG
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
stx math_store_reg
|
|
||||||
|
|
||||||
lda #0
|
lda #0
|
||||||
ldx #8
|
ldx #8
|
||||||
|
@ -137,7 +129,6 @@ divmod_ub_asm .proc
|
||||||
dex
|
dex
|
||||||
bne -
|
bne -
|
||||||
ldy P8ZP_SCRATCH_B1
|
ldy P8ZP_SCRATCH_B1
|
||||||
ldx math_store_reg
|
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
@ -197,7 +188,6 @@ result = dividend ;save memory by reusing divident to store the result
|
||||||
|
|
||||||
sta _divisor
|
sta _divisor
|
||||||
sty _divisor+1
|
sty _divisor+1
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
lda #0 ;preset remainder to 0
|
lda #0 ;preset remainder to 0
|
||||||
sta remainder
|
sta remainder
|
||||||
sta remainder+1
|
sta remainder+1
|
||||||
|
@ -224,7 +214,6 @@ result = dividend ;save memory by reusing divident to store the result
|
||||||
|
|
||||||
lda result
|
lda result
|
||||||
ldy result+1
|
ldy result+1
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
_divisor .word 0
|
_divisor .word 0
|
||||||
.pend
|
.pend
|
||||||
|
@ -257,501 +246,6 @@ b1=*+1
|
||||||
randbyte = randword ; -- 8 bit pseudo random number generator into A (by just reusing randword)
|
randbyte = randword ; -- 8 bit pseudo random number generator into A (by just reusing randword)
|
||||||
|
|
||||||
|
|
||||||
; ----------- optimized multiplications (stack) : ---------
|
|
||||||
stack_mul_byte_3 .proc
|
|
||||||
; X + X*2
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_3 .proc
|
|
||||||
; W*2 + W
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
stack_mul_byte_5 .proc
|
|
||||||
; X*4 + X
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_5 .proc
|
|
||||||
; W*4 + W
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
stack_mul_byte_6 .proc
|
|
||||||
; (X*2 + X)*2
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_6 .proc
|
|
||||||
; (W*2 + W)*2
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_7 .proc
|
|
||||||
; X*8 - X
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_7 .proc
|
|
||||||
; W*8 - W
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
sbc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_9 .proc
|
|
||||||
; X*8 + X
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_9 .proc
|
|
||||||
; W*8 + W
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_10 .proc
|
|
||||||
; (X*4 + X)*2
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_10 .proc
|
|
||||||
; (W*4 + W)*2
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_11 .proc
|
|
||||||
; (X*2 + X)*4 - X
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
; mul_word_11 is skipped (too much code)
|
|
||||||
|
|
||||||
stack_mul_byte_12 .proc
|
|
||||||
; (X*2 + X)*4
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_12 .proc
|
|
||||||
; (W*2 + W)*4
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_13 .proc
|
|
||||||
; (X*2 + X)*4 + X
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
; mul_word_13 is skipped (too much code)
|
|
||||||
|
|
||||||
stack_mul_byte_14 .proc
|
|
||||||
; (X*8 - X)*2
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
; mul_word_14 is skipped (too much code)
|
|
||||||
|
|
||||||
stack_mul_byte_15 .proc
|
|
||||||
; X*16 - X
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_15 .proc
|
|
||||||
; W*16 - W
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
sbc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_20 .proc
|
|
||||||
; (X*4 + X)*4
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_20 .proc
|
|
||||||
; (W*4 + W)*4
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_25 .proc
|
|
||||||
; (X*2 + X)*8 + X
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
asl a
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_25 .proc
|
|
||||||
; W = (W*2 + W) *8 + W
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_W1+1
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
lda P8ZP_SCRATCH_W1
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_W1+1
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_W1+1
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_W1+1
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_40 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
and #7
|
|
||||||
tay
|
|
||||||
lda mul_byte_40._forties,y
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_40 .proc
|
|
||||||
; (W*4 + W)*8
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_REG
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol a
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_50 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
and #7
|
|
||||||
tay
|
|
||||||
lda mul_byte_50._fifties, y
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_50 .proc
|
|
||||||
; W = W * 25 * 2
|
|
||||||
jsr stack_mul_word_25
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_80 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
and #3
|
|
||||||
tay
|
|
||||||
lda mul_byte_80._eighties, y
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_80 .proc
|
|
||||||
; W = W * 40 * 2
|
|
||||||
jsr stack_mul_word_40
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_byte_100 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
and #3
|
|
||||||
tay
|
|
||||||
lda mul_byte_100._hundreds, y
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_100 .proc
|
|
||||||
; W = W * 25 * 4
|
|
||||||
jsr stack_mul_word_25
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_320 .proc
|
|
||||||
; stackW = stackLo * 256 + stackLo * 64 (stackHi doesn't matter)
|
|
||||||
ldy P8ESTACK_LO+1,x
|
|
||||||
lda #0
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
tya
|
|
||||||
asl a
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
asl a
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
tya
|
|
||||||
clc
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
stack_mul_word_640 .proc
|
|
||||||
; stackW = (stackLo * 2 * 320) (stackHi doesn't matter)
|
|
||||||
asl P8ESTACK_LO+1,x
|
|
||||||
jmp stack_mul_word_320
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
; ----------- optimized multiplications (in-place A (byte) and ?? (word)) : ---------
|
; ----------- optimized multiplications (in-place A (byte) and ?? (word)) : ---------
|
||||||
mul_byte_3 .proc
|
mul_byte_3 .proc
|
||||||
; A = A + A*2
|
; A = A + A*2
|
||||||
|
@ -1252,250 +746,69 @@ mul_word_640 .proc
|
||||||
; ----------- end optimized multiplications -----------
|
; ----------- end optimized multiplications -----------
|
||||||
|
|
||||||
|
|
||||||
; bit shifts.
|
|
||||||
; anything below 3 is done inline. anything above 7 is done via other optimizations.
|
|
||||||
|
|
||||||
shift_left_w_7 .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_B1
|
|
||||||
_shift6 asl a
|
|
||||||
rol P8ZP_SCRATCH_B1
|
|
||||||
_shift5 asl a
|
|
||||||
rol P8ZP_SCRATCH_B1
|
|
||||||
_shift4 asl a
|
|
||||||
rol P8ZP_SCRATCH_B1
|
|
||||||
_shift3 asl a
|
|
||||||
rol P8ZP_SCRATCH_B1
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_B1
|
|
||||||
asl a
|
|
||||||
rol P8ZP_SCRATCH_B1
|
|
||||||
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_B1
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_left_w_6 .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
jmp shift_left_w_7._shift6
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_left_w_5 .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
jmp shift_left_w_7._shift5
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_left_w_4 .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
jmp shift_left_w_7._shift4
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_left_w_3 .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
jmp shift_left_w_7._shift3
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
shift_left_w .proc
|
|
||||||
; -- variable number of shifts left
|
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
bne _shift
|
|
||||||
rts
|
|
||||||
_shift asl P8ESTACK_LO+1,x
|
|
||||||
rol P8ESTACK_HI+1,x
|
|
||||||
dey
|
|
||||||
bne _shift
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_uw .proc
|
|
||||||
; -- uword variable number of shifts right
|
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
bne _shift
|
|
||||||
rts
|
|
||||||
_shift lsr P8ESTACK_HI+1,x
|
|
||||||
ror P8ESTACK_LO+1,x
|
|
||||||
dey
|
|
||||||
bne _shift
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_uw_7 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
|
|
||||||
lsr a
|
|
||||||
ror P8ZP_SCRATCH_B1
|
|
||||||
_shift6 lsr a
|
|
||||||
ror P8ZP_SCRATCH_B1
|
|
||||||
_shift5 lsr a
|
|
||||||
ror P8ZP_SCRATCH_B1
|
|
||||||
_shift4 lsr a
|
|
||||||
ror P8ZP_SCRATCH_B1
|
|
||||||
_shift3 lsr a
|
|
||||||
ror P8ZP_SCRATCH_B1
|
|
||||||
lsr a
|
|
||||||
ror P8ZP_SCRATCH_B1
|
|
||||||
lsr a
|
|
||||||
ror P8ZP_SCRATCH_B1
|
|
||||||
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
lda P8ZP_SCRATCH_B1
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_uw_6 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
jmp shift_right_uw_7._shift6
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_uw_5 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
jmp shift_right_uw_7._shift5
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_uw_4 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
jmp shift_right_uw_7._shift4
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_uw_3 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_B1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
jmp shift_right_uw_7._shift3
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
shift_right_w_7 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
|
|
||||||
asl a
|
|
||||||
ror P8ZP_SCRATCH_W1+1
|
|
||||||
ror P8ZP_SCRATCH_W1
|
|
||||||
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
_shift6 asl a
|
|
||||||
ror P8ZP_SCRATCH_W1+1
|
|
||||||
ror P8ZP_SCRATCH_W1
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
_shift5 asl a
|
|
||||||
ror P8ZP_SCRATCH_W1+1
|
|
||||||
ror P8ZP_SCRATCH_W1
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
_shift4 asl a
|
|
||||||
ror P8ZP_SCRATCH_W1+1
|
|
||||||
ror P8ZP_SCRATCH_W1
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
_shift3 asl a
|
|
||||||
ror P8ZP_SCRATCH_W1+1
|
|
||||||
ror P8ZP_SCRATCH_W1
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
asl a
|
|
||||||
ror P8ZP_SCRATCH_W1+1
|
|
||||||
ror P8ZP_SCRATCH_W1
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
asl a
|
|
||||||
ror P8ZP_SCRATCH_W1+1
|
|
||||||
ror P8ZP_SCRATCH_W1
|
|
||||||
|
|
||||||
lda P8ZP_SCRATCH_W1
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_W1+1
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_w_6 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
jmp shift_right_w_7._shift6
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_w_5 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
jmp shift_right_w_7._shift5
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_w_4 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
jmp shift_right_w_7._shift4
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shift_right_w_3 .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
jmp shift_right_w_7._shift3
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
shift_right_w .proc
|
|
||||||
; -- signed word variable number of shifts right
|
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
bne _shift
|
|
||||||
rts
|
|
||||||
_shift lda P8ESTACK_HI+1,x
|
|
||||||
asl a
|
|
||||||
ror P8ESTACK_HI+1,x
|
|
||||||
ror P8ESTACK_LO+1,x
|
|
||||||
dey
|
|
||||||
bne _shift
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
; support for bit shifting that is too large to be unrolled:
|
; support for bit shifting that is too large to be unrolled:
|
||||||
|
|
||||||
lsr_byte_A .proc
|
lsr_byte_A .proc
|
||||||
; -- lsr signed byte in A times the value in Y (assume >0)
|
; -- lsr signed byte in A times the value in Y (>1)
|
||||||
cmp #0
|
cmp #0
|
||||||
bmi _negative
|
bpl lsr_ubyte_A
|
||||||
|
- sec
|
||||||
|
ror a
|
||||||
|
dey
|
||||||
|
bne -
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
|
lsr_ubyte_A .proc
|
||||||
|
; -- lsr unsigned byte in A times the value in Y (>1)
|
||||||
- lsr a
|
- lsr a
|
||||||
dey
|
dey
|
||||||
bne -
|
bne -
|
||||||
rts
|
rts
|
||||||
_negative lsr a
|
.pend
|
||||||
ora #$80
|
|
||||||
|
asl_byte_A .proc
|
||||||
|
; -- asl any byte in A times the value in Y (>1)
|
||||||
|
- asl a
|
||||||
dey
|
dey
|
||||||
|
bne -
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
|
|
||||||
|
lsr_word_AY .proc
|
||||||
|
; -- lsr signed word in AY times the value in X (>1)
|
||||||
|
cpy #0
|
||||||
|
bpl lsr_uword_AY
|
||||||
|
sty P8ZP_SCRATCH_B1
|
||||||
|
_negative sec
|
||||||
|
ror P8ZP_SCRATCH_B1
|
||||||
|
ror a
|
||||||
|
dex
|
||||||
bne _negative
|
bne _negative
|
||||||
|
ldy P8ZP_SCRATCH_B1
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
|
lsr_uword_AY .proc
|
||||||
|
; -- lsr unsigned word in AY times the value in X (>1)
|
||||||
|
sty P8ZP_SCRATCH_B1
|
||||||
|
- lsr P8ZP_SCRATCH_B1
|
||||||
|
ror a
|
||||||
|
dex
|
||||||
|
bne -
|
||||||
|
ldy P8ZP_SCRATCH_B1
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
|
asl_word_AY .proc
|
||||||
|
; -- asl any word in AY times the value in X (>1)
|
||||||
|
sty P8ZP_SCRATCH_B1
|
||||||
|
- asl a
|
||||||
|
rol P8ZP_SCRATCH_B1
|
||||||
|
dex
|
||||||
|
bne -
|
||||||
|
ldy P8ZP_SCRATCH_B1
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
@ -1525,7 +838,6 @@ tempsq = P8ZP_SCRATCH_B1 ; temp byte for intermediate result
|
||||||
|
|
||||||
sta numberl
|
sta numberl
|
||||||
sty numberh
|
sty numberh
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
|
|
||||||
lda #$00 ; clear a
|
lda #$00 ; clear a
|
||||||
sta squarel ; clear square low byte
|
sta squarel ; clear square low byte
|
||||||
|
@ -1563,7 +875,6 @@ _nosqadd:
|
||||||
|
|
||||||
lda squarel
|
lda squarel
|
||||||
ldy squareh
|
ldy squareh
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
.pend
|
.pend
|
||||||
|
|
|
@ -1,20 +1,6 @@
|
||||||
; ---- builtin functions
|
; ---- builtin functions
|
||||||
|
|
||||||
|
|
||||||
func_any_b_stack .proc
|
|
||||||
jsr func_any_b_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_all_b_stack .proc
|
|
||||||
jsr func_all_b_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_any_b_into_A .proc
|
func_any_b_into_A .proc
|
||||||
; -- any(array), array in P8ZP_SCRATCH_W1, num bytes in A
|
; -- any(array), array in P8ZP_SCRATCH_W1, num bytes in A
|
||||||
sta _cmp_mod+1 ; self-modifying code
|
sta _cmp_mod+1 ; self-modifying code
|
||||||
|
@ -49,14 +35,6 @@ func_any_w_into_A .proc
|
||||||
jmp func_any_b_into_A
|
jmp func_any_b_into_A
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
func_any_w_stack .proc
|
|
||||||
asl a
|
|
||||||
jsr func_any_b_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_all_w_into_A .proc
|
func_all_w_into_A .proc
|
||||||
; -- all(warray), array in P8ZP_SCRATCH_W1, num bytes in A
|
; -- all(warray), array in P8ZP_SCRATCH_W1, num bytes in A
|
||||||
asl a ; times 2 because of word
|
asl a ; times 2 because of word
|
||||||
|
@ -77,22 +55,6 @@ _cmp_mod cpy #255 ; modified
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
func_all_w_stack .proc
|
|
||||||
jsr func_all_w_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
abs_b_stack .proc
|
|
||||||
; -- push abs(A) on stack (as unsigned word)
|
|
||||||
jsr abs_b_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
stz P8ESTACK_HI,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
abs_b_into_A .proc
|
abs_b_into_A .proc
|
||||||
; -- A = abs(A)
|
; -- A = abs(A)
|
||||||
cmp #0
|
cmp #0
|
||||||
|
@ -104,16 +66,6 @@ abs_b_into_A .proc
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
abs_w_stack .proc
|
|
||||||
; -- push abs(AY) on stack (as word)
|
|
||||||
jsr abs_w_into_AY
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
tya
|
|
||||||
sta P8ESTACK_HI,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
abs_w_into_AY .proc
|
abs_w_into_AY .proc
|
||||||
; -- AY = abs(AY)
|
; -- AY = abs(AY)
|
||||||
cpy #0
|
cpy #0
|
||||||
|
@ -142,13 +94,6 @@ _neg lda #-1
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
func_sign_b_stack .proc
|
|
||||||
jsr func_sign_b_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_sign_ub_into_A .proc
|
func_sign_ub_into_A .proc
|
||||||
cmp #0
|
cmp #0
|
||||||
bne _pos
|
bne _pos
|
||||||
|
@ -157,13 +102,6 @@ _pos lda #1
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
func_sign_ub_stack .proc
|
|
||||||
jsr func_sign_ub_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_sign_uw_into_A .proc
|
func_sign_uw_into_A .proc
|
||||||
cpy #0
|
cpy #0
|
||||||
beq _possibly_zero
|
beq _possibly_zero
|
||||||
|
@ -174,13 +112,6 @@ _possibly_zero cmp #0
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
func_sign_uw_stack .proc
|
|
||||||
jsr func_sign_uw_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_sign_w_into_A .proc
|
func_sign_w_into_A .proc
|
||||||
cpy #0
|
cpy #0
|
||||||
beq _possibly_zero
|
beq _possibly_zero
|
||||||
|
@ -195,26 +126,10 @@ _possibly_zero cmp #0
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
func_sign_w_stack .proc
|
|
||||||
jsr func_sign_w_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_sqrt16_stack .proc
|
|
||||||
jsr func_sqrt16_into_A
|
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
func_sqrt16_into_A .proc
|
func_sqrt16_into_A .proc
|
||||||
; integer square root from http://6502org.wikidot.com/software-math-sqrt
|
; integer square root from http://6502org.wikidot.com/software-math-sqrt
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
sty P8ZP_SCRATCH_W1+1
|
sty P8ZP_SCRATCH_W1+1
|
||||||
txa
|
|
||||||
pha
|
|
||||||
lda #0
|
lda #0
|
||||||
sta P8ZP_SCRATCH_B1
|
sta P8ZP_SCRATCH_B1
|
||||||
sta P8ZP_SCRATCH_REG
|
sta P8ZP_SCRATCH_REG
|
||||||
|
@ -237,8 +152,6 @@ func_sqrt16_into_A .proc
|
||||||
rol P8ZP_SCRATCH_REG
|
rol P8ZP_SCRATCH_REG
|
||||||
dex
|
dex
|
||||||
bne -
|
bne -
|
||||||
pla
|
|
||||||
tax
|
|
||||||
lda P8ZP_SCRATCH_B1
|
lda P8ZP_SCRATCH_B1
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
|
|
||||||
orig_stackpointer .byte 0 ; stores the Stack pointer register at program start
|
orig_stackpointer .byte 0 ; stores the Stack pointer register at program start
|
||||||
|
|
||||||
read_byte_from_address_on_stack .proc
|
|
||||||
; -- read the byte from the memory address on the top of the stack, return in A (stack remains unchanged)
|
read_byte_from_address_in_AY .proc
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
ldy P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
sty P8ZP_SCRATCH_W2+1
|
sty P8ZP_SCRATCH_W2+1
|
||||||
ldy #0
|
ldy #0
|
||||||
|
@ -16,318 +14,16 @@ read_byte_from_address_on_stack .proc
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
write_byte_to_address_on_stack .proc
|
write_byte_X_to_address_in_AY .proc
|
||||||
; -- write the byte in A to the memory address on the top of the stack (stack remains unchanged)
|
sta P8ZP_SCRATCH_W2
|
||||||
ldy P8ESTACK_LO+1,x
|
|
||||||
sty P8ZP_SCRATCH_W2
|
|
||||||
ldy P8ESTACK_HI+1,x
|
|
||||||
sty P8ZP_SCRATCH_W2+1
|
sty P8ZP_SCRATCH_W2+1
|
||||||
ldy #0
|
ldy #0
|
||||||
|
txa
|
||||||
sta (P8ZP_SCRATCH_W2),y
|
sta (P8ZP_SCRATCH_W2),y
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
neg_b .proc
|
|
||||||
lda #0
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
neg_w .proc
|
|
||||||
sec
|
|
||||||
lda #0
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda #0
|
|
||||||
sbc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
inv_word .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
eor #255
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
eor #255
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
bitand_b .proc
|
|
||||||
; -- bitwise and (of 2 bytes)
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
and P8ESTACK_LO+1,x
|
|
||||||
inx
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
bitor_b .proc
|
|
||||||
; -- bitwise or (of 2 bytes)
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
ora P8ESTACK_LO+1,x
|
|
||||||
inx
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
bitxor_b .proc
|
|
||||||
; -- bitwise xor (of 2 bytes)
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
eor P8ESTACK_LO+1,x
|
|
||||||
inx
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
bitand_w .proc
|
|
||||||
; -- bitwise and (of 2 words)
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
and P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+2,x
|
|
||||||
lda P8ESTACK_HI+2,x
|
|
||||||
and P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+2,x
|
|
||||||
inx
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
bitor_w .proc
|
|
||||||
; -- bitwise or (of 2 words)
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
ora P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+2,x
|
|
||||||
lda P8ESTACK_HI+2,x
|
|
||||||
ora P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+2,x
|
|
||||||
inx
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
bitxor_w .proc
|
|
||||||
; -- bitwise xor (of 2 bytes)
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
eor P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+2,x
|
|
||||||
lda P8ESTACK_HI+2,x
|
|
||||||
eor P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+2,x
|
|
||||||
inx
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
add_w .proc
|
|
||||||
; -- push word+word / uword+uword
|
|
||||||
inx
|
|
||||||
clc
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
adc P8ESTACK_LO+1,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ESTACK_HI,x
|
|
||||||
adc P8ESTACK_HI+1,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
sub_w .proc
|
|
||||||
; -- push word-word
|
|
||||||
inx
|
|
||||||
sec
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sbc P8ESTACK_LO,x
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sbc P8ESTACK_HI,x
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
mul_byte .proc
|
|
||||||
; -- b*b->b (signed and unsigned)
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
ldy P8ESTACK_LO+1,x
|
|
||||||
jsr math.multiply_bytes
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
mul_word .proc
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
ldy P8ESTACK_HI+1,x
|
|
||||||
jsr math.multiply_words
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
tya
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
idiv_b .proc
|
|
||||||
; signed division: use unsigned division and fix sign of result afterwards
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
eor P8ESTACK_LO+1,x
|
|
||||||
php ; save sign of result
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
bpl +
|
|
||||||
eor #$ff
|
|
||||||
sec
|
|
||||||
adc #0 ; make num1 positive
|
|
||||||
+ tay
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
bpl +
|
|
||||||
eor #$ff
|
|
||||||
sec
|
|
||||||
adc #0 ; make num2 positive
|
|
||||||
+ jsr math.divmod_ub_asm
|
|
||||||
sta _remainder
|
|
||||||
tya
|
|
||||||
plp ; get sign of result
|
|
||||||
bpl +
|
|
||||||
eor #$ff
|
|
||||||
sec
|
|
||||||
adc #0 ; negate result
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex
|
|
||||||
rts
|
|
||||||
_remainder .byte 0
|
|
||||||
.pend
|
|
||||||
|
|
||||||
idiv_ub .proc
|
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
jsr math.divmod_ub_asm
|
|
||||||
tya
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
idiv_w .proc
|
|
||||||
; signed division: use unsigned division and fix sign of result afterwards
|
|
||||||
lda P8ESTACK_HI+2,x
|
|
||||||
eor P8ESTACK_HI+1,x
|
|
||||||
php ; save sign of result
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
bpl +
|
|
||||||
jsr neg_w ; make value positive
|
|
||||||
+ inx
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
bpl +
|
|
||||||
jsr neg_w ; make value positive
|
|
||||||
+ lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
ldy P8ESTACK_HI,x
|
|
||||||
jsr math.divmod_uw_asm
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
tya
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
plp
|
|
||||||
bpl +
|
|
||||||
jmp neg_w ; negate result
|
|
||||||
+ rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
idiv_uw .proc
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
ldy P8ESTACK_HI,x
|
|
||||||
jsr math.divmod_uw_asm
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
tya
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
remainder_ub .proc
|
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x ; right operand
|
|
||||||
lda P8ESTACK_LO+1,x ; left operand
|
|
||||||
jsr math.divmod_ub_asm
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
remainder_uw .proc
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
ldy P8ESTACK_HI,x
|
|
||||||
jsr math.divmod_uw_asm
|
|
||||||
lda P8ZP_SCRATCH_W2
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
lda P8ZP_SCRATCH_W2+1
|
|
||||||
sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
equal_w .proc
|
|
||||||
; -- are the two words on the stack identical?
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
cmp P8ESTACK_LO+2,x
|
|
||||||
bne equal_b._equal_b_false
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
cmp P8ESTACK_HI+2,x
|
|
||||||
bne equal_b._equal_b_false
|
|
||||||
beq equal_b._equal_b_true
|
|
||||||
.pend
|
|
||||||
|
|
||||||
notequal_b .proc
|
|
||||||
; -- are the two bytes on the stack different?
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
cmp P8ESTACK_LO+2,x
|
|
||||||
beq equal_b._equal_b_false
|
|
||||||
bne equal_b._equal_b_true
|
|
||||||
.pend
|
|
||||||
|
|
||||||
notequal_w .proc
|
|
||||||
; -- are the two words on the stack different?
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
cmp P8ESTACK_HI+2,x
|
|
||||||
beq notequal_b
|
|
||||||
bne equal_b._equal_b_true
|
|
||||||
.pend
|
|
||||||
|
|
||||||
less_ub .proc
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
bcc equal_b._equal_b_true
|
|
||||||
bcs equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
less_b .proc
|
|
||||||
; see http://www.6502.org/tutorials/compare_beyond.html
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
bvc +
|
|
||||||
eor #$80
|
|
||||||
+ bmi equal_b._equal_b_true
|
|
||||||
bpl equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
reg_less_uw .proc
|
reg_less_uw .proc
|
||||||
; AY < P8ZP_SCRATCH_W2?
|
; AY < P8ZP_SCRATCH_W2?
|
||||||
cpy P8ZP_SCRATCH_W2+1
|
cpy P8ZP_SCRATCH_W2+1
|
||||||
|
@ -341,17 +37,6 @@ _true lda #1
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
less_uw .proc
|
|
||||||
lda P8ESTACK_HI+2,x
|
|
||||||
cmp P8ESTACK_HI+1,x
|
|
||||||
bcc equal_b._equal_b_true
|
|
||||||
bne equal_b._equal_b_false
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
bcc equal_b._equal_b_true
|
|
||||||
bcs equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
reg_less_w .proc
|
reg_less_w .proc
|
||||||
; -- AY < P8ZP_SCRATCH_W2?
|
; -- AY < P8ZP_SCRATCH_W2?
|
||||||
cmp P8ZP_SCRATCH_W2
|
cmp P8ZP_SCRATCH_W2
|
||||||
|
@ -366,48 +51,6 @@ _true lda #1
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
less_w .proc
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
lda P8ESTACK_HI+2,x
|
|
||||||
sbc P8ESTACK_HI+1,x
|
|
||||||
bvc +
|
|
||||||
eor #$80
|
|
||||||
+ bmi equal_b._equal_b_true
|
|
||||||
bpl equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
equal_b .proc
|
|
||||||
; -- are the two bytes on the stack identical?
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
bne _equal_b_false
|
|
||||||
_equal_b_true lda #1
|
|
||||||
_equal_b_store inx
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
_equal_b_false lda #0
|
|
||||||
beq _equal_b_store
|
|
||||||
.pend
|
|
||||||
|
|
||||||
lesseq_ub .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
cmp P8ESTACK_LO+2,x
|
|
||||||
bcs equal_b._equal_b_true
|
|
||||||
bcc equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
lesseq_b .proc
|
|
||||||
; see http://www.6502.org/tutorials/compare_beyond.html
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
clc
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
bvc +
|
|
||||||
eor #$80
|
|
||||||
+ bmi equal_b._equal_b_true
|
|
||||||
bpl equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
reg_lesseq_uw .proc
|
reg_lesseq_uw .proc
|
||||||
; AY <= P8ZP_SCRATCH_W2?
|
; AY <= P8ZP_SCRATCH_W2?
|
||||||
cpy P8ZP_SCRATCH_W2+1
|
cpy P8ZP_SCRATCH_W2+1
|
||||||
|
@ -424,17 +67,6 @@ _true lda #1
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
lesseq_uw .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
cmp P8ESTACK_HI+2,x
|
|
||||||
bcc equal_b._equal_b_false
|
|
||||||
bne equal_b._equal_b_true
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
cmp P8ESTACK_LO+2,x
|
|
||||||
bcs equal_b._equal_b_true
|
|
||||||
bcc equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
reg_lesseq_w .proc
|
reg_lesseq_w .proc
|
||||||
; -- P8ZP_SCRATCH_W2 <= AY ? (note: order different from other routines)
|
; -- P8ZP_SCRATCH_W2 <= AY ? (note: order different from other routines)
|
||||||
cmp P8ZP_SCRATCH_W2
|
cmp P8ZP_SCRATCH_W2
|
||||||
|
@ -449,224 +81,6 @@ reg_lesseq_w .proc
|
||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
lesseq_w .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
cmp P8ESTACK_LO+2,x
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sbc P8ESTACK_HI+2,x
|
|
||||||
bvc +
|
|
||||||
eor #$80
|
|
||||||
+ bpl equal_b._equal_b_true
|
|
||||||
bmi equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greater_ub .proc
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
beq equal_b._equal_b_false
|
|
||||||
bcs equal_b._equal_b_true
|
|
||||||
bcc equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greater_b .proc
|
|
||||||
; see http://www.6502.org/tutorials/compare_beyond.html
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
clc
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
bvc +
|
|
||||||
eor #$80
|
|
||||||
+ bpl equal_b._equal_b_true
|
|
||||||
bmi equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greater_uw .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
cmp P8ESTACK_HI+2,x
|
|
||||||
bcc equal_b._equal_b_true
|
|
||||||
bne equal_b._equal_b_false
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
cmp P8ESTACK_LO+2,x
|
|
||||||
bcc equal_b._equal_b_true
|
|
||||||
bcs equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greater_w .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
cmp P8ESTACK_LO+2,x
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
sbc P8ESTACK_HI+2,x
|
|
||||||
bvc +
|
|
||||||
eor #$80
|
|
||||||
+ bmi equal_b._equal_b_true
|
|
||||||
bpl equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greatereq_ub .proc
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
bcs equal_b._equal_b_true
|
|
||||||
bcc equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greatereq_b .proc
|
|
||||||
; see http://www.6502.org/tutorials/compare_beyond.html
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
sec
|
|
||||||
sbc P8ESTACK_LO+1,x
|
|
||||||
bvc +
|
|
||||||
eor #$80
|
|
||||||
+ bpl equal_b._equal_b_true
|
|
||||||
bmi equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greatereq_uw .proc
|
|
||||||
lda P8ESTACK_HI+2,x
|
|
||||||
cmp P8ESTACK_HI+1,x
|
|
||||||
bcc equal_b._equal_b_false
|
|
||||||
bne equal_b._equal_b_true
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
bcs equal_b._equal_b_true
|
|
||||||
bcc equal_b._equal_b_false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greatereq_w .proc
|
|
||||||
lda P8ESTACK_LO+2,x
|
|
||||||
cmp P8ESTACK_LO+1,x
|
|
||||||
lda P8ESTACK_HI+2,x
|
|
||||||
sbc P8ESTACK_HI+1,x
|
|
||||||
bvc +
|
|
||||||
eor #$80
|
|
||||||
+ bmi equal_b._equal_b_false
|
|
||||||
bpl equal_b._equal_b_true
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
shiftleft_b .proc
|
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
bne +
|
|
||||||
rts
|
|
||||||
+ lda P8ESTACK_LO+1,x
|
|
||||||
- asl a
|
|
||||||
dey
|
|
||||||
bne -
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
shiftright_b .proc
|
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
bne +
|
|
||||||
rts
|
|
||||||
+ lda P8ESTACK_LO+1,x
|
|
||||||
- lsr a
|
|
||||||
dey
|
|
||||||
bne -
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
equalzero_b .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
beq _true
|
|
||||||
bne _false
|
|
||||||
_true lda #1
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
_false lda #0
|
|
||||||
sta P8ESTACK_LO+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
equalzero_w .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
ora P8ESTACK_HI+1,x
|
|
||||||
beq equalzero_b._true
|
|
||||||
bne equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
notequalzero_b .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
beq equalzero_b._false
|
|
||||||
bne equalzero_b._true
|
|
||||||
.pend
|
|
||||||
|
|
||||||
notequalzero_w .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
ora P8ESTACK_HI+1,x
|
|
||||||
beq equalzero_b._false
|
|
||||||
bne equalzero_b._true
|
|
||||||
.pend
|
|
||||||
|
|
||||||
lesszero_b .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
bmi equalzero_b._true
|
|
||||||
jmp equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
lesszero_w .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
bmi equalzero_b._true
|
|
||||||
jmp equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greaterzero_ub .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
bne equalzero_b._true
|
|
||||||
beq equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greaterzero_sb .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
beq equalzero_b._false
|
|
||||||
bpl equalzero_b._true
|
|
||||||
bmi equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greaterzero_uw .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
ora P8ESTACK_HI+1,x
|
|
||||||
bne equalzero_b._true
|
|
||||||
beq equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greaterzero_sw .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
bmi equalzero_b._false
|
|
||||||
ora P8ESTACK_LO+1,x
|
|
||||||
beq equalzero_b._false
|
|
||||||
bne equalzero_b._true
|
|
||||||
.pend
|
|
||||||
|
|
||||||
lessequalzero_sb .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
bmi equalzero_b._true
|
|
||||||
beq equalzero_b._true
|
|
||||||
bne equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
lessequalzero_sw .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
bmi equalzero_b._true
|
|
||||||
ora P8ESTACK_LO+1,x
|
|
||||||
beq equalzero_b._true
|
|
||||||
bne equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greaterequalzero_sb .proc
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
bpl equalzero_b._true
|
|
||||||
bmi equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
greaterequalzero_sw .proc
|
|
||||||
lda P8ESTACK_HI+1,x
|
|
||||||
bpl equalzero_b._true
|
|
||||||
bmi equalzero_b._false
|
|
||||||
.pend
|
|
||||||
|
|
||||||
memcopy16_up .proc
|
memcopy16_up .proc
|
||||||
; -- copy memory UP from (P8ZP_SCRATCH_W1) to (P8ZP_SCRATCH_W2) of length X/Y (16-bit, X=lo, Y=hi)
|
; -- copy memory UP from (P8ZP_SCRATCH_W1) to (P8ZP_SCRATCH_W2) of length X/Y (16-bit, X=lo, Y=hi)
|
||||||
|
@ -996,21 +410,6 @@ _arg_s1 .word 0
|
||||||
_arg_s2 .word 0
|
_arg_s2 .word 0
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
strcmp_stack .proc
|
|
||||||
; -- compare strings, both on stack.
|
|
||||||
; Returns -1,0,1 in A, depeding on the ordering. Clobbers Y.
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
ldy P8ESTACK_HI,x
|
|
||||||
sta P8ZP_SCRATCH_W2
|
|
||||||
sty P8ZP_SCRATCH_W2+1
|
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
ldy P8ESTACK_HI,x
|
|
||||||
jmp strcmp_mem
|
|
||||||
.pend
|
|
||||||
|
|
||||||
|
|
||||||
strcmp_mem .proc
|
strcmp_mem .proc
|
||||||
; -- compares strings in s1 (AY) and s2 (P8ZP_SCRATCH_W2).
|
; -- compares strings in s1 (AY) and s2 (P8ZP_SCRATCH_W2).
|
||||||
; Returns -1,0,1 in A, depeding on the ordering. Clobbers Y.
|
; Returns -1,0,1 in A, depeding on the ordering. Clobbers Y.
|
||||||
|
@ -1041,16 +440,6 @@ _return_minusone
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
sign_extend_stack_byte .proc
|
|
||||||
; -- sign extend the (signed) byte on the stack to full 16 bits
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
ora #$7f
|
|
||||||
bmi +
|
|
||||||
lda #0
|
|
||||||
+ sta P8ESTACK_HI+1,x
|
|
||||||
rts
|
|
||||||
.pend
|
|
||||||
|
|
||||||
strlen .proc
|
strlen .proc
|
||||||
; -- returns the number of bytes in the string in AY, in Y.
|
; -- returns the number of bytes in the string in AY, in Y.
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
|
|
|
@ -282,7 +282,6 @@ _done rts
|
||||||
|
|
||||||
str = P8ZP_SCRATCH_W1
|
str = P8ZP_SCRATCH_W1
|
||||||
|
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
sta str
|
sta str
|
||||||
sty str+1
|
sty str+1
|
||||||
lda cx16.r0
|
lda cx16.r0
|
||||||
|
@ -294,7 +293,6 @@ str = P8ZP_SCRATCH_W1
|
||||||
jsr _match
|
jsr _match
|
||||||
lda #0
|
lda #0
|
||||||
rol a
|
rol a
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
; utility debug code to print the X (evalstack) and SP (cpu stack) registers.
|
; utility debug code to print the SP (cpu stack pointer) register.
|
||||||
|
|
||||||
%import textio
|
%import textio
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ test_stack {
|
||||||
|
|
||||||
asmsub test() {
|
asmsub test() {
|
||||||
%asm {{
|
%asm {{
|
||||||
stx _saveX
|
|
||||||
lda #13
|
lda #13
|
||||||
jsr txt.chrout
|
jsr txt.chrout
|
||||||
lda #'-'
|
lda #'-'
|
||||||
|
@ -17,14 +16,6 @@ test_stack {
|
||||||
bne -
|
bne -
|
||||||
lda #13
|
lda #13
|
||||||
jsr txt.chrout
|
jsr txt.chrout
|
||||||
lda #'x'
|
|
||||||
jsr txt.chrout
|
|
||||||
lda #'='
|
|
||||||
jsr txt.chrout
|
|
||||||
lda _saveX
|
|
||||||
jsr txt.print_ub
|
|
||||||
lda #' '
|
|
||||||
jsr txt.chrout
|
|
||||||
lda #'s'
|
lda #'s'
|
||||||
jsr txt.chrout
|
jsr txt.chrout
|
||||||
lda #'p'
|
lda #'p'
|
||||||
|
@ -43,9 +34,7 @@ test_stack {
|
||||||
bne -
|
bne -
|
||||||
lda #13
|
lda #13
|
||||||
jsr txt.chrout
|
jsr txt.chrout
|
||||||
ldx _saveX
|
|
||||||
rts
|
rts
|
||||||
_saveX .byte 0
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package prog8
|
||||||
import kotlinx.cli.*
|
import kotlinx.cli.*
|
||||||
import prog8.ast.base.AstException
|
import prog8.ast.base.AstException
|
||||||
import prog8.code.core.CbmPrgLauncherType
|
import prog8.code.core.CbmPrgLauncherType
|
||||||
import prog8.code.core.toHex
|
|
||||||
import prog8.code.target.*
|
import prog8.code.target.*
|
||||||
import prog8.code.target.virtual.VirtualMachineDefinition
|
import prog8.code.target.virtual.VirtualMachineDefinition
|
||||||
import prog8.compiler.CompilationResult
|
import prog8.compiler.CompilationResult
|
||||||
|
@ -39,16 +38,13 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||||
val cli = ArgParser("prog8compiler", prefixStyle = ArgParser.OptionPrefixStyle.JVM)
|
val cli = ArgParser("prog8compiler", prefixStyle = ArgParser.OptionPrefixStyle.JVM)
|
||||||
val asmListfile by cli.option(ArgType.Boolean, fullName = "asmlist", description = "make the assembler produce a listing file as well")
|
val asmListfile by cli.option(ArgType.Boolean, fullName = "asmlist", description = "make the assembler produce a listing file as well")
|
||||||
val symbolDefs by cli.option(ArgType.String, fullName = "D", description = "define assembly symbol(s) with -D SYMBOL=VALUE").multiple()
|
val symbolDefs by cli.option(ArgType.String, fullName = "D", description = "define assembly symbol(s) with -D SYMBOL=VALUE").multiple()
|
||||||
val evalStackAddrString by cli.option(ArgType.String, fullName = "esa", description = "override the eval-stack base address (must be page aligned)")
|
|
||||||
val startEmulator1 by cli.option(ArgType.Boolean, fullName = "emu", description = "auto-start emulator after successful compilation")
|
val startEmulator1 by cli.option(ArgType.Boolean, fullName = "emu", description = "auto-start emulator after successful compilation")
|
||||||
val startEmulator2 by cli.option(ArgType.Boolean, fullName = "emu2", description = "auto-start alternative emulator after successful compilation")
|
val startEmulator2 by cli.option(ArgType.Boolean, fullName = "emu2", description = "auto-start alternative emulator after successful compilation")
|
||||||
val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental/alternative codegen")
|
val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental/alternative codegen")
|
||||||
val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code")
|
val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code")
|
||||||
val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations")
|
val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations")
|
||||||
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
|
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
|
||||||
val optimizeFloatExpressions by cli.option(ArgType.Boolean, fullName = "optfloatx", description = "optimize float expressions (warning: can increase program size)")
|
|
||||||
val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results")
|
val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results")
|
||||||
val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation")
|
|
||||||
val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator)
|
val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator)
|
||||||
val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.NAME}', '${C128Target.NAME}', '${Cx16Target.NAME}', '${AtariTarget.NAME}', '${VMTarget.NAME}') (required)")
|
val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.NAME}', '${C128Target.NAME}', '${Cx16Target.NAME}', '${AtariTarget.NAME}', '${VMTarget.NAME}') (required)")
|
||||||
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM")
|
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM")
|
||||||
|
@ -101,25 +97,6 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||||
return runVm(moduleFiles.first())
|
return runVm(moduleFiles.first())
|
||||||
}
|
}
|
||||||
|
|
||||||
var evalStackAddr: UInt? = null
|
|
||||||
if(evalStackAddrString!=null) {
|
|
||||||
try {
|
|
||||||
evalStackAddr = if (evalStackAddrString!!.startsWith("0x"))
|
|
||||||
evalStackAddrString!!.substring(2).toUInt(16)
|
|
||||||
else if (evalStackAddrString!!.startsWith("$"))
|
|
||||||
evalStackAddrString!!.substring(1).toUInt(16)
|
|
||||||
else
|
|
||||||
evalStackAddrString!!.toUInt()
|
|
||||||
} catch(nx: NumberFormatException) {
|
|
||||||
System.err.println("invalid address for evalstack: $evalStackAddrString")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if(evalStackAddr !in 256u..65536u-512u || (evalStackAddr and 255u != 0u)) {
|
|
||||||
System.err.println("invalid address for evalstack: ${evalStackAddr.toHex()}")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val processedSymbols = processSymbolDefs(symbolDefs) ?: return false
|
val processedSymbols = processSymbolDefs(symbolDefs) ?: return false
|
||||||
|
|
||||||
if(watchMode==true) {
|
if(watchMode==true) {
|
||||||
|
@ -134,15 +111,12 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||||
val compilerArgs = CompilerArguments(
|
val compilerArgs = CompilerArguments(
|
||||||
filepath,
|
filepath,
|
||||||
dontOptimize != true,
|
dontOptimize != true,
|
||||||
optimizeFloatExpressions == true,
|
|
||||||
dontWriteAssembly != true,
|
dontWriteAssembly != true,
|
||||||
slowCodegenWarnings == true,
|
|
||||||
quietAssembler == true,
|
quietAssembler == true,
|
||||||
asmListfile == true,
|
asmListfile == true,
|
||||||
experimentalCodegen == true,
|
experimentalCodegen == true,
|
||||||
varsHighBank,
|
varsHighBank,
|
||||||
compilationTarget!!,
|
compilationTarget!!,
|
||||||
evalStackAddr,
|
|
||||||
splitWordArrays == true,
|
splitWordArrays == true,
|
||||||
processedSymbols,
|
processedSymbols,
|
||||||
srcdirs,
|
srcdirs,
|
||||||
|
@ -203,15 +177,12 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||||
val compilerArgs = CompilerArguments(
|
val compilerArgs = CompilerArguments(
|
||||||
filepath,
|
filepath,
|
||||||
dontOptimize != true,
|
dontOptimize != true,
|
||||||
optimizeFloatExpressions == true,
|
|
||||||
dontWriteAssembly != true,
|
dontWriteAssembly != true,
|
||||||
slowCodegenWarnings == true,
|
|
||||||
quietAssembler == true,
|
quietAssembler == true,
|
||||||
asmListfile == true,
|
asmListfile == true,
|
||||||
experimentalCodegen == true,
|
experimentalCodegen == true,
|
||||||
varsHighBank,
|
varsHighBank,
|
||||||
compilationTarget!!,
|
compilationTarget!!,
|
||||||
evalStackAddr,
|
|
||||||
splitWordArrays == true,
|
splitWordArrays == true,
|
||||||
processedSymbols,
|
processedSymbols,
|
||||||
srcdirs,
|
srcdirs,
|
||||||
|
|
|
@ -6,10 +6,10 @@ package prog8.buildversion
|
||||||
const val MAVEN_GROUP = "prog8"
|
const val MAVEN_GROUP = "prog8"
|
||||||
const val MAVEN_NAME = "compiler"
|
const val MAVEN_NAME = "compiler"
|
||||||
const val VERSION = "9.2-SNAPSHOT"
|
const val VERSION = "9.2-SNAPSHOT"
|
||||||
const val GIT_REVISION = 3964
|
const val GIT_REVISION = 3980
|
||||||
const val GIT_SHA = "aaa30e4a583fa7c8da61998cf7cbb2a60b52afb0"
|
const val GIT_SHA = "9f247901d484ca36d047cdcf77f5b905ba772f82"
|
||||||
const val GIT_DATE = "2023-07-16T21:16:18Z"
|
const val GIT_DATE = "2023-07-16T21:45:04Z"
|
||||||
const val GIT_BRANCH = "master"
|
const val GIT_BRANCH = "remove_evalstack"
|
||||||
const val BUILD_DATE = "2023-07-16T21:16:23Z"
|
const val BUILD_DATE = "2023-07-17T23:11:43Z"
|
||||||
const val BUILD_UNIX_TIME = 1689542183583L
|
const val BUILD_UNIX_TIME = 1689635503506L
|
||||||
const val DIRTY = 1
|
const val DIRTY = 1
|
||||||
|
|
|
@ -29,15 +29,12 @@ class CompilationResult(val compilerAst: Program, // deprecated, use codegenAs
|
||||||
|
|
||||||
class CompilerArguments(val filepath: Path,
|
class CompilerArguments(val filepath: Path,
|
||||||
val optimize: Boolean,
|
val optimize: Boolean,
|
||||||
val optimizeFloatExpressions: Boolean,
|
|
||||||
val writeAssembly: Boolean,
|
val writeAssembly: Boolean,
|
||||||
val slowCodegenWarnings: Boolean,
|
|
||||||
val quietAssembler: Boolean,
|
val quietAssembler: Boolean,
|
||||||
val asmListfile: Boolean,
|
val asmListfile: Boolean,
|
||||||
val experimentalCodegen: Boolean,
|
val experimentalCodegen: Boolean,
|
||||||
val varsHighBank: Int?,
|
val varsHighBank: Int?,
|
||||||
val compilationTarget: String,
|
val compilationTarget: String,
|
||||||
val evalStackBaseAddress: UInt?,
|
|
||||||
val splitWordArrays: Boolean,
|
val splitWordArrays: Boolean,
|
||||||
val symbolDefs: Map<String, String>,
|
val symbolDefs: Map<String, String>,
|
||||||
val sourceDirs: List<String> = emptyList(),
|
val sourceDirs: List<String> = emptyList(),
|
||||||
|
@ -49,8 +46,6 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||||
lateinit var program: Program
|
lateinit var program: Program
|
||||||
lateinit var importedFiles: List<Path>
|
lateinit var importedFiles: List<Path>
|
||||||
|
|
||||||
val optimizeFloatExpr = if(args.optimize) args.optimizeFloatExpressions else false
|
|
||||||
|
|
||||||
val compTarget =
|
val compTarget =
|
||||||
when(args.compilationTarget) {
|
when(args.compilationTarget) {
|
||||||
C64Target.NAME -> C64Target()
|
C64Target.NAME -> C64Target()
|
||||||
|
@ -70,14 +65,11 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||||
compilationOptions = options
|
compilationOptions = options
|
||||||
|
|
||||||
with(compilationOptions) {
|
with(compilationOptions) {
|
||||||
slowCodegenWarnings = args.slowCodegenWarnings
|
|
||||||
optimize = args.optimize
|
optimize = args.optimize
|
||||||
optimizeFloatExpressions = optimizeFloatExpr
|
|
||||||
asmQuiet = args.quietAssembler
|
asmQuiet = args.quietAssembler
|
||||||
asmListfile = args.asmListfile
|
asmListfile = args.asmListfile
|
||||||
experimentalCodegen = args.experimentalCodegen
|
experimentalCodegen = args.experimentalCodegen
|
||||||
varsHighBank = args.varsHighBank
|
varsHighBank = args.varsHighBank
|
||||||
evalStackBaseAddress = args.evalStackBaseAddress
|
|
||||||
splitWordArrays = args.splitWordArrays
|
splitWordArrays = args.splitWordArrays
|
||||||
outputDir = args.outputDir.normalize()
|
outputDir = args.outputDir.normalize()
|
||||||
symbolDefs = args.symbolDefs
|
symbolDefs = args.symbolDefs
|
||||||
|
@ -85,10 +77,6 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||||
program = programresult
|
program = programresult
|
||||||
importedFiles = imported
|
importedFiles = imported
|
||||||
|
|
||||||
if(compilationOptions.evalStackBaseAddress!=null) {
|
|
||||||
compTarget.machine.overrideEvalStack(compilationOptions.evalStackBaseAddress!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
processAst(program, args.errors, compilationOptions)
|
processAst(program, args.errors, compilationOptions)
|
||||||
if (compilationOptions.optimize) {
|
if (compilationOptions.optimize) {
|
||||||
// println("*********** COMPILER AST RIGHT BEFORE OPTIMIZING *************")
|
// println("*********** COMPILER AST RIGHT BEFORE OPTIMIZING *************")
|
||||||
|
@ -367,12 +355,11 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
|
||||||
while (true) {
|
while (true) {
|
||||||
// keep optimizing expressions and statements until no more steps remain
|
// keep optimizing expressions and statements until no more steps remain
|
||||||
val optsDone1 = program.simplifyExpressions(errors, compTarget)
|
val optsDone1 = program.simplifyExpressions(errors, compTarget)
|
||||||
val optsDone2 = program.splitBinaryExpressions(compilerOptions)
|
val optsDone2 = program.optimizeStatements(errors, functions, compilerOptions)
|
||||||
val optsDone3 = program.optimizeStatements(errors, functions, compilerOptions)
|
val optsDone3 = program.inlineSubroutines(compilerOptions)
|
||||||
val optsDone4 = program.inlineSubroutines(compilerOptions)
|
|
||||||
program.constantFold(errors, compTarget) // because simplified statements and expressions can result in more constants that can be folded away
|
program.constantFold(errors, compTarget) // because simplified statements and expressions can result in more constants that can be folded away
|
||||||
errors.report()
|
errors.report()
|
||||||
if (optsDone1 + optsDone2 + optsDone3 + optsDone4 == 0)
|
if (optsDone1 + optsDone2 + optsDone3 == 0)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
val remover2 = UnusedCodeRemover(program, errors, compTarget)
|
val remover2 = UnusedCodeRemover(program, errors, compTarget)
|
||||||
|
|
|
@ -27,7 +27,7 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
|
||||||
boolRemover.visit(this)
|
boolRemover.visit(this)
|
||||||
boolRemover.applyModifications()
|
boolRemover.applyModifications()
|
||||||
|
|
||||||
val fixer = BeforeAsmAstChanger(this, compilerOptions, errors)
|
val fixer = BeforeAsmAstChanger(this, compilerOptions)
|
||||||
fixer.visit(this)
|
fixer.visit(this)
|
||||||
while (errors.noErrors() && fixer.applyModifications() > 0) {
|
while (errors.noErrors() && fixer.applyModifications() > 0) {
|
||||||
fixer.visit(this)
|
fixer.visit(this)
|
||||||
|
@ -108,9 +108,6 @@ internal fun Program.checkIdentifiers(errors: IErrorReporter, options: Compilati
|
||||||
checker2.visit(this)
|
checker2.visit(this)
|
||||||
|
|
||||||
if(errors.noErrors()) {
|
if(errors.noErrors()) {
|
||||||
val transforms = AstOnetimeTransforms(this, options)
|
|
||||||
transforms.visit(this)
|
|
||||||
transforms.applyModifications()
|
|
||||||
val lit2decl = LiteralsToAutoVars(this, options.compTarget, errors)
|
val lit2decl = LiteralsToAutoVars(this, options.compTarget, errors)
|
||||||
lit2decl.visit(this)
|
lit2decl.visit(this)
|
||||||
if(errors.noErrors())
|
if(errors.noErrors())
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
package prog8.compiler.astprocessing
|
|
||||||
|
|
||||||
import prog8.ast.Node
|
|
||||||
import prog8.ast.Program
|
|
||||||
import prog8.ast.expressions.*
|
|
||||||
import prog8.ast.statements.AssignTarget
|
|
||||||
import prog8.ast.statements.Assignment
|
|
||||||
import prog8.ast.statements.DirectMemoryWrite
|
|
||||||
import prog8.ast.statements.VarDecl
|
|
||||||
import prog8.ast.walk.AstWalker
|
|
||||||
import prog8.ast.walk.IAstModification
|
|
||||||
import prog8.code.core.CompilationOptions
|
|
||||||
import prog8.code.core.DataType
|
|
||||||
import prog8.code.target.VMTarget
|
|
||||||
|
|
||||||
|
|
||||||
internal class AstOnetimeTransforms(private val program: Program, private val options: CompilationOptions) : AstWalker() {
|
|
||||||
|
|
||||||
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
|
||||||
if(parent !is VarDecl) {
|
|
||||||
if(options.compTarget.name == VMTarget.NAME)
|
|
||||||
return noModifications // vm codegen deals correctly with all cases
|
|
||||||
// Don't replace the initializer value in a vardecl - this will be moved to a separate
|
|
||||||
// assignment statement soon in after(VarDecl)
|
|
||||||
return replacePointerVarIndexWithMemreadOrMemwrite(arrayIndexedExpression, parent)
|
|
||||||
}
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun replacePointerVarIndexWithMemreadOrMemwrite(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
|
||||||
// note: The CodeDesugarer already does something similar, but that is meant ONLY to take
|
|
||||||
// into account the case where the index value is a word type.
|
|
||||||
// The replacement here is to fix missing cases in the 6502 codegen. (VM codegen doesn't use this workaround)
|
|
||||||
// TODO make the 6502 codegen better so this workaround can be removed
|
|
||||||
val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl(program)
|
|
||||||
if(arrayVar!=null && arrayVar.datatype == DataType.UWORD) {
|
|
||||||
if(parent is AssignTarget) {
|
|
||||||
val assignment = parent.parent as? Assignment
|
|
||||||
if(assignment?.value is NumericLiteral || assignment?.value is IdentifierReference) {
|
|
||||||
// the codegen contains correct optimized code ONLY for a constant assignment, or direct variable assignment.
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
// Other cases aren't covered correctly by the 6502 codegen, and there are a LOT of cases.
|
|
||||||
// So rewrite assignment target pointervar[index] into @(pointervar+index)
|
|
||||||
// (the 6502 codegen covers all cases correctly for a direct memory assignment).
|
|
||||||
val indexer = arrayIndexedExpression.indexer
|
|
||||||
val add: Expression =
|
|
||||||
if(indexer.indexExpr.constValue(program)?.number==0.0)
|
|
||||||
arrayIndexedExpression.arrayvar.copy()
|
|
||||||
else
|
|
||||||
BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", indexer.indexExpr, arrayIndexedExpression.position)
|
|
||||||
val memwrite = DirectMemoryWrite(add, arrayIndexedExpression.position)
|
|
||||||
val newtarget = AssignTarget(null, null, memwrite, arrayIndexedExpression.position)
|
|
||||||
return listOf(IAstModification.ReplaceNode(parent, newtarget, parent.parent))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,6 @@ import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.code.target.C64Target
|
import prog8.code.target.C64Target
|
||||||
import prog8.code.target.Cx16Target
|
|
||||||
import prog8.code.target.VMTarget
|
|
||||||
|
|
||||||
|
|
||||||
class AstPreprocessor(val program: Program,
|
class AstPreprocessor(val program: Program,
|
||||||
|
@ -25,15 +23,10 @@ class AstPreprocessor(val program: Program,
|
||||||
relocateCx16VirtualRegisters(program, 0x0004u)
|
relocateCx16VirtualRegisters(program, 0x0004u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(options.compTarget.name !in setOf(Cx16Target.NAME, VMTarget.NAME)) {
|
|
||||||
relocateCx16VirtualRegisters(program, options.compTarget.machine.ESTACK_HI)
|
|
||||||
}
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun relocateCx16VirtualRegisters(program: Program, baseAddress: UInt) {
|
private fun relocateCx16VirtualRegisters(program: Program, baseAddress: UInt) {
|
||||||
// reset the address of the virtual registers to be inside the evaluation stack.
|
|
||||||
// (we don't do this on CommanderX16 itself as the registers have a fixed location in Zeropage there)
|
|
||||||
val cx16block = program.allBlocks.single { it.name == "cx16" }
|
val cx16block = program.allBlocks.single { it.name == "cx16" }
|
||||||
val memVars = cx16block.statements
|
val memVars = cx16block.statements
|
||||||
.filterIsInstance<VarDecl>()
|
.filterIsInstance<VarDecl>()
|
||||||
|
|
|
@ -9,14 +9,10 @@ import prog8.ast.getTempVar
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.ast.walk.IAstVisitor
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.code.target.VMTarget
|
import prog8.code.target.VMTarget
|
||||||
|
|
||||||
internal class BeforeAsmAstChanger(val program: Program,
|
internal class BeforeAsmAstChanger(val program: Program, private val options: CompilationOptions) : AstWalker() {
|
||||||
private val options: CompilationOptions,
|
|
||||||
private val errors: IErrorReporter
|
|
||||||
) : AstWalker() {
|
|
||||||
|
|
||||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||||
throw InternalCompilerException("break should have been replaced by goto $breakStmt")
|
throw InternalCompilerException("break should have been replaced by goto $breakStmt")
|
||||||
|
@ -56,9 +52,6 @@ internal class BeforeAsmAstChanger(val program: Program,
|
||||||
&& !assignment.target.isIOAddress(options.compTarget.machine)) {
|
&& !assignment.target.isIOAddress(options.compTarget.machine)) {
|
||||||
val binExpr = assignment.value as? BinaryExpression
|
val binExpr = assignment.value as? BinaryExpression
|
||||||
|
|
||||||
if(binExpr!=null && binExpr.inferType(program) istype DataType.FLOAT && !options.optimizeFloatExpressions)
|
|
||||||
return noModifications
|
|
||||||
|
|
||||||
if (binExpr != null && binExpr.operator !in ComparisonOperators) {
|
if (binExpr != null && binExpr.operator !in ComparisonOperators) {
|
||||||
if (binExpr.left !is BinaryExpression) {
|
if (binExpr.left !is BinaryExpression) {
|
||||||
if (binExpr.right.referencesIdentifier(assignment.target.identifier!!.nameInSource)) {
|
if (binExpr.right.referencesIdentifier(assignment.target.identifier!!.nameInSource)) {
|
||||||
|
@ -222,12 +215,6 @@ internal class BeforeAsmAstChanger(val program: Program,
|
||||||
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
||||||
|
|
||||||
if(options.compTarget.name!=VMTarget.NAME) { // don't apply this optimization/check for Vm target
|
if(options.compTarget.name!=VMTarget.NAME) { // don't apply this optimization/check for Vm target
|
||||||
val containingStatement = getContainingStatement(arrayIndexedExpression)
|
|
||||||
if(getComplexArrayIndexedExpressions(containingStatement).size > 1) {
|
|
||||||
errors.err("it's not possible to use more than one complex array indexing expression in a single statement; break it up via a temporary variable for instance", containingStatement.position)
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
val index = arrayIndexedExpression.indexer.indexExpr
|
val index = arrayIndexedExpression.indexer.indexExpr
|
||||||
if (index !is NumericLiteral && index !is IdentifierReference) {
|
if (index !is NumericLiteral && index !is IdentifierReference) {
|
||||||
// replace complex indexing expression with a temp variable to hold the computed index first
|
// replace complex indexing expression with a temp variable to hold the computed index first
|
||||||
|
@ -238,42 +225,6 @@ internal class BeforeAsmAstChanger(val program: Program,
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getComplexArrayIndexedExpressions(stmt: Statement): List<ArrayIndexedExpression> {
|
|
||||||
|
|
||||||
class Searcher : IAstVisitor {
|
|
||||||
val complexArrayIndexedExpressions = mutableListOf<ArrayIndexedExpression>()
|
|
||||||
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
|
|
||||||
val ix = arrayIndexedExpression.indexer.indexExpr
|
|
||||||
if(ix !is NumericLiteral && ix !is IdentifierReference)
|
|
||||||
complexArrayIndexedExpressions.add(arrayIndexedExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visit(branch: ConditionalBranch) {}
|
|
||||||
|
|
||||||
override fun visit(forLoop: ForLoop) {}
|
|
||||||
|
|
||||||
override fun visit(ifElse: IfElse) {
|
|
||||||
ifElse.condition.accept(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visit(untilLoop: UntilLoop) {
|
|
||||||
untilLoop.condition.accept(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val searcher = Searcher()
|
|
||||||
stmt.accept(searcher)
|
|
||||||
return searcher.complexArrayIndexedExpressions
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getContainingStatement(expression: Expression): Statement {
|
|
||||||
var node: Node = expression
|
|
||||||
while(node !is Statement)
|
|
||||||
node = node.parent
|
|
||||||
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getAutoIndexerVarFor(expr: ArrayIndexedExpression): MutableList<IAstModification> {
|
private fun getAutoIndexerVarFor(expr: ArrayIndexedExpression): MutableList<IAstModification> {
|
||||||
val modifications = mutableListOf<IAstModification>()
|
val modifications = mutableListOf<IAstModification>()
|
||||||
val statement = expr.containingStatement
|
val statement = expr.containingStatement
|
||||||
|
|
|
@ -11,7 +11,7 @@ import prog8tests.helpers.compileText
|
||||||
|
|
||||||
class TestAstChecks: FunSpec({
|
class TestAstChecks: FunSpec({
|
||||||
|
|
||||||
test("conditional expression w/float works even without tempvar to split it") {
|
test("conditional expression w/float works") {
|
||||||
val text = """
|
val text = """
|
||||||
%import floats
|
%import floats
|
||||||
main {
|
main {
|
||||||
|
|
|
@ -26,15 +26,12 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
|
||||||
val args = CompilerArguments(
|
val args = CompilerArguments(
|
||||||
filepath,
|
filepath,
|
||||||
optimize,
|
optimize,
|
||||||
optimizeFloatExpressions = true,
|
|
||||||
writeAssembly = true,
|
writeAssembly = true,
|
||||||
slowCodegenWarnings = false,
|
|
||||||
quietAssembler = true,
|
quietAssembler = true,
|
||||||
asmListfile = false,
|
asmListfile = false,
|
||||||
experimentalCodegen = false,
|
experimentalCodegen = false,
|
||||||
varsHighBank = null,
|
varsHighBank = null,
|
||||||
compilationTarget = target.name,
|
compilationTarget = target.name,
|
||||||
evalStackBaseAddress = null,
|
|
||||||
splitWordArrays = false,
|
splitWordArrays = false,
|
||||||
symbolDefs = emptyMap(),
|
symbolDefs = emptyMap(),
|
||||||
outputDir = outputDir
|
outputDir = outputDir
|
||||||
|
|
|
@ -43,15 +43,12 @@ class TestCompilerOptionSourcedirs: FunSpec({
|
||||||
val args = CompilerArguments(
|
val args = CompilerArguments(
|
||||||
filepath = filePath,
|
filepath = filePath,
|
||||||
optimize = false,
|
optimize = false,
|
||||||
optimizeFloatExpressions = false,
|
|
||||||
writeAssembly = true,
|
writeAssembly = true,
|
||||||
slowCodegenWarnings = false,
|
|
||||||
quietAssembler = true,
|
quietAssembler = true,
|
||||||
asmListfile = false,
|
asmListfile = false,
|
||||||
experimentalCodegen = false,
|
experimentalCodegen = false,
|
||||||
varsHighBank = null,
|
varsHighBank = null,
|
||||||
compilationTarget = Cx16Target.NAME,
|
compilationTarget = Cx16Target.NAME,
|
||||||
evalStackBaseAddress = null,
|
|
||||||
splitWordArrays = false,
|
splitWordArrays = false,
|
||||||
symbolDefs = emptyMap(),
|
symbolDefs = emptyMap(),
|
||||||
sourceDirs,
|
sourceDirs,
|
||||||
|
|
|
@ -120,36 +120,31 @@ class TestOptimization: FunSpec({
|
||||||
// load_location = 12345
|
// load_location = 12345
|
||||||
// word llw
|
// word llw
|
||||||
// llw = 12345
|
// llw = 12345
|
||||||
// cx16.r0 = load_location
|
// cx16.r0 = load_location + 10000
|
||||||
// cx16.r0 += 10000
|
// cx16.r2 = load_location + 10000
|
||||||
// cx16.r2 = load_location
|
// cx16.r4 = load_location + 22
|
||||||
// cx16.r2 += 10000
|
// cx16.r5s = llw - 1899
|
||||||
// cx16.r4 = load_location
|
// cx16.r7s = llw + 99
|
||||||
// cx16.r4 += 22
|
|
||||||
// cx16.r5s = llw
|
|
||||||
// cx16.r5s -= 1899
|
|
||||||
// cx16.r7s = llw
|
|
||||||
// cx16.r7s += 99
|
|
||||||
val stmts = result.compilerAst.entrypoint.statements
|
val stmts = result.compilerAst.entrypoint.statements
|
||||||
stmts.size shouldBe 14
|
stmts.size shouldBe 9
|
||||||
|
|
||||||
val addR0value = (stmts[5] as Assignment).value
|
val addR0value = (stmts[4] as Assignment).value
|
||||||
val binexpr0 = addR0value as BinaryExpression
|
val binexpr0 = addR0value as BinaryExpression
|
||||||
binexpr0.operator shouldBe "+"
|
binexpr0.operator shouldBe "+"
|
||||||
binexpr0.right shouldBe NumericLiteral(DataType.UWORD, 10000.0, Position.DUMMY)
|
binexpr0.right shouldBe NumericLiteral(DataType.UWORD, 10000.0, Position.DUMMY)
|
||||||
val addR2value = (stmts[7] as Assignment).value
|
val addR2value = (stmts[5] as Assignment).value
|
||||||
val binexpr2 = addR2value as BinaryExpression
|
val binexpr2 = addR2value as BinaryExpression
|
||||||
binexpr2.operator shouldBe "+"
|
binexpr2.operator shouldBe "+"
|
||||||
binexpr2.right shouldBe NumericLiteral(DataType.UWORD, 10000.0, Position.DUMMY)
|
binexpr2.right shouldBe NumericLiteral(DataType.UWORD, 10000.0, Position.DUMMY)
|
||||||
val addR4value = (stmts[9] as Assignment).value
|
val addR4value = (stmts[6] as Assignment).value
|
||||||
val binexpr4 = addR4value as BinaryExpression
|
val binexpr4 = addR4value as BinaryExpression
|
||||||
binexpr4.operator shouldBe "+"
|
binexpr4.operator shouldBe "+"
|
||||||
binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 22.0, Position.DUMMY)
|
binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 22.0, Position.DUMMY)
|
||||||
val subR5value = (stmts[11] as Assignment).value
|
val subR5value = (stmts[7] as Assignment).value
|
||||||
val binexpr5 = subR5value as BinaryExpression
|
val binexpr5 = subR5value as BinaryExpression
|
||||||
binexpr5.operator shouldBe "-"
|
binexpr5.operator shouldBe "-"
|
||||||
binexpr5.right shouldBe NumericLiteral(DataType.UWORD, 1899.0, Position.DUMMY)
|
binexpr5.right shouldBe NumericLiteral(DataType.UWORD, 1899.0, Position.DUMMY)
|
||||||
val subR7value = (stmts[13] as Assignment).value
|
val subR7value = (stmts[8] as Assignment).value
|
||||||
val binexpr7 = subR7value as BinaryExpression
|
val binexpr7 = subR7value as BinaryExpression
|
||||||
binexpr7.operator shouldBe "+"
|
binexpr7.operator shouldBe "+"
|
||||||
binexpr7.right shouldBe NumericLiteral(DataType.UWORD, 99.0, Position.DUMMY)
|
binexpr7.right shouldBe NumericLiteral(DataType.UWORD, 99.0, Position.DUMMY)
|
||||||
|
@ -171,44 +166,34 @@ class TestOptimization: FunSpec({
|
||||||
// expected:
|
// expected:
|
||||||
// word llw
|
// word llw
|
||||||
// llw = 300
|
// llw = 300
|
||||||
// cx16.r0s = llw
|
// cx16.r0s = llw * 180
|
||||||
// cx16.r0s *= 180
|
// cx16.r1s = llw * 180
|
||||||
// cx16.r1s = llw
|
// cx16.r2s = llw / 90
|
||||||
// cx16.r1s *= 180
|
// cx16.r3s = llw * 5
|
||||||
// cx16.r2s = llw
|
// cx16.r4s = llw * 90 / 5
|
||||||
// cx16.r2s /= 90
|
|
||||||
// cx16.r3s = llw
|
|
||||||
// cx16.r3s *= 5
|
|
||||||
// cx16.r4s = llw
|
|
||||||
// cx16.r4s *= 90
|
|
||||||
// cx16.r4s /= 5
|
|
||||||
val stmts = result.compilerAst.entrypoint.statements
|
val stmts = result.compilerAst.entrypoint.statements
|
||||||
stmts.size shouldBe 13
|
stmts.size shouldBe 7
|
||||||
|
|
||||||
val mulR0Value = (stmts[3] as Assignment).value
|
val mulR0Value = (stmts[2] as Assignment).value
|
||||||
val binexpr0 = mulR0Value as BinaryExpression
|
val binexpr0 = mulR0Value as BinaryExpression
|
||||||
binexpr0.operator shouldBe "*"
|
binexpr0.operator shouldBe "*"
|
||||||
binexpr0.right shouldBe NumericLiteral(DataType.UWORD, 180.0, Position.DUMMY)
|
binexpr0.right shouldBe NumericLiteral(DataType.UWORD, 180.0, Position.DUMMY)
|
||||||
val mulR1Value = (stmts[5] as Assignment).value
|
val mulR1Value = (stmts[3] as Assignment).value
|
||||||
val binexpr1 = mulR1Value as BinaryExpression
|
val binexpr1 = mulR1Value as BinaryExpression
|
||||||
binexpr1.operator shouldBe "*"
|
binexpr1.operator shouldBe "*"
|
||||||
binexpr1.right shouldBe NumericLiteral(DataType.UWORD, 180.0, Position.DUMMY)
|
binexpr1.right shouldBe NumericLiteral(DataType.UWORD, 180.0, Position.DUMMY)
|
||||||
val divR2Value = (stmts[7] as Assignment).value
|
val divR2Value = (stmts[4] as Assignment).value
|
||||||
val binexpr2 = divR2Value as BinaryExpression
|
val binexpr2 = divR2Value as BinaryExpression
|
||||||
binexpr2.operator shouldBe "/"
|
binexpr2.operator shouldBe "/"
|
||||||
binexpr2.right shouldBe NumericLiteral(DataType.UWORD, 90.0, Position.DUMMY)
|
binexpr2.right shouldBe NumericLiteral(DataType.UWORD, 90.0, Position.DUMMY)
|
||||||
val mulR3Value = (stmts[9] as Assignment).value
|
val mulR3Value = (stmts[5] as Assignment).value
|
||||||
val binexpr3 = mulR3Value as BinaryExpression
|
val binexpr3 = mulR3Value as BinaryExpression
|
||||||
binexpr3.operator shouldBe "*"
|
binexpr3.operator shouldBe "*"
|
||||||
binexpr3.right shouldBe NumericLiteral(DataType.UWORD, 5.0, Position.DUMMY)
|
binexpr3.right shouldBe NumericLiteral(DataType.UWORD, 5.0, Position.DUMMY)
|
||||||
val mulR4Value = (stmts[11] as Assignment).value
|
val mulR4Value = (stmts[6] as Assignment).value
|
||||||
val binexpr4 = mulR4Value as BinaryExpression
|
val binexpr4 = mulR4Value as BinaryExpression
|
||||||
binexpr4.operator shouldBe "*"
|
binexpr4.operator shouldBe "/"
|
||||||
binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 90.0, Position.DUMMY)
|
binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 5.0, Position.DUMMY)
|
||||||
val divR4Value = (stmts[12] as Assignment).value
|
|
||||||
val binexpr4b = divR4Value as BinaryExpression
|
|
||||||
binexpr4b.operator shouldBe "/"
|
|
||||||
binexpr4b.right shouldBe NumericLiteral(DataType.UWORD, 5.0, Position.DUMMY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("constantfolded and silently typecasted for initializervalues") {
|
test("constantfolded and silently typecasted for initializervalues") {
|
||||||
|
@ -377,14 +362,12 @@ class TestOptimization: FunSpec({
|
||||||
uword z4
|
uword z4
|
||||||
z4 = 0
|
z4 = 0
|
||||||
ubyte z5
|
ubyte z5
|
||||||
z5 = z1
|
z5 = z1 + 5
|
||||||
z5 += 5
|
|
||||||
ubyte z6
|
ubyte z6
|
||||||
z6 = z1
|
z6 = z1 - 5
|
||||||
z6 -= 5
|
|
||||||
*/
|
*/
|
||||||
val statements = result.compilerAst.entrypoint.statements
|
val statements = result.compilerAst.entrypoint.statements
|
||||||
statements.size shouldBe 14
|
statements.size shouldBe 12
|
||||||
val z1decl = statements[0] as VarDecl
|
val z1decl = statements[0] as VarDecl
|
||||||
val z1init = statements[1] as Assignment
|
val z1init = statements[1] as Assignment
|
||||||
val z2decl = statements[2] as VarDecl
|
val z2decl = statements[2] as VarDecl
|
||||||
|
@ -395,10 +378,8 @@ class TestOptimization: FunSpec({
|
||||||
val z4init = statements[7] as Assignment
|
val z4init = statements[7] as Assignment
|
||||||
val z5decl = statements[8] as VarDecl
|
val z5decl = statements[8] as VarDecl
|
||||||
val z5init = statements[9] as Assignment
|
val z5init = statements[9] as Assignment
|
||||||
val z5plus = statements[10] as Assignment
|
val z6decl = statements[10] as VarDecl
|
||||||
val z6decl = statements[11] as VarDecl
|
val z6init = statements[11] as Assignment
|
||||||
val z6init = statements[12] as Assignment
|
|
||||||
val z6plus = statements[13] as Assignment
|
|
||||||
|
|
||||||
z1decl.name shouldBe "z1"
|
z1decl.name shouldBe "z1"
|
||||||
z1init.value shouldBe NumericLiteral(DataType.UBYTE, 10.0, Position.DUMMY)
|
z1init.value shouldBe NumericLiteral(DataType.UBYTE, 10.0, Position.DUMMY)
|
||||||
|
@ -409,15 +390,11 @@ class TestOptimization: FunSpec({
|
||||||
z4decl.name shouldBe "z4"
|
z4decl.name shouldBe "z4"
|
||||||
z4init.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
|
z4init.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
|
||||||
z5decl.name shouldBe "z5"
|
z5decl.name shouldBe "z5"
|
||||||
(z5init.value as? IdentifierReference)?.nameInSource shouldBe listOf("z1")
|
(z5init.value as BinaryExpression).operator shouldBe "+"
|
||||||
z5plus.isAugmentable shouldBe true
|
(z5init.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY)
|
||||||
(z5plus.value as BinaryExpression).operator shouldBe "+"
|
|
||||||
(z5plus.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY)
|
|
||||||
z6decl.name shouldBe "z6"
|
z6decl.name shouldBe "z6"
|
||||||
(z6init.value as? IdentifierReference)?.nameInSource shouldBe listOf("z1")
|
(z6init.value as BinaryExpression).operator shouldBe "-"
|
||||||
z6plus.isAugmentable shouldBe true
|
(z6init.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY)
|
||||||
(z6plus.value as BinaryExpression).operator shouldBe "-"
|
|
||||||
(z6plus.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("force_output option should work with optimizing memwrite assignment") {
|
test("force_output option should work with optimizing memwrite assignment") {
|
||||||
|
@ -435,7 +412,7 @@ class TestOptimization: FunSpec({
|
||||||
|
|
||||||
val result = compileText(C64Target(), optimize=true, src, writeAssembly=false)!!
|
val result = compileText(C64Target(), optimize=true, src, writeAssembly=false)!!
|
||||||
val stmts = result.compilerAst.entrypoint.statements
|
val stmts = result.compilerAst.entrypoint.statements
|
||||||
stmts.size shouldBe 6
|
stmts.size shouldBe 5
|
||||||
val assign=stmts.last() as Assignment
|
val assign=stmts.last() as Assignment
|
||||||
(assign.target.memoryAddress?.addressExpression as IdentifierReference).nameInSource shouldBe listOf("aa")
|
(assign.target.memoryAddress?.addressExpression as IdentifierReference).nameInSource shouldBe listOf("aa")
|
||||||
}
|
}
|
||||||
|
@ -452,7 +429,7 @@ class TestOptimization: FunSpec({
|
||||||
"""
|
"""
|
||||||
val result = compileText(C64Target(), optimize=true, src, writeAssembly=false)!!
|
val result = compileText(C64Target(), optimize=true, src, writeAssembly=false)!!
|
||||||
val stmts = result.compilerAst.entrypoint.statements
|
val stmts = result.compilerAst.entrypoint.statements
|
||||||
stmts.size shouldBe 6
|
stmts.size shouldBe 5
|
||||||
val assign=stmts.last() as Assignment
|
val assign=stmts.last() as Assignment
|
||||||
(assign.target.memoryAddress?.addressExpression as IdentifierReference).nameInSource shouldBe listOf("aa")
|
(assign.target.memoryAddress?.addressExpression as IdentifierReference).nameInSource shouldBe listOf("aa")
|
||||||
}
|
}
|
||||||
|
@ -548,9 +525,9 @@ class TestOptimization: FunSpec({
|
||||||
xx += 6
|
xx += 6
|
||||||
*/
|
*/
|
||||||
val stmts = result.compilerAst.entrypoint.statements
|
val stmts = result.compilerAst.entrypoint.statements
|
||||||
stmts.size shouldBe 8
|
stmts.size shouldBe 7
|
||||||
stmts.filterIsInstance<VarDecl>().size shouldBe 3
|
stmts.filterIsInstance<VarDecl>().size shouldBe 3
|
||||||
stmts.filterIsInstance<Assignment>().size shouldBe 5
|
stmts.filterIsInstance<Assignment>().size shouldBe 4
|
||||||
}
|
}
|
||||||
|
|
||||||
test("only substitue assignments with 0 after a =0 initializer if it is the same variable") {
|
test("only substitue assignments with 0 after a =0 initializer if it is the same variable") {
|
||||||
|
|
|
@ -95,19 +95,16 @@ main {
|
||||||
ubyte ub3
|
ubyte ub3
|
||||||
ub3 = 1
|
ub3 = 1
|
||||||
ubyte @shared bvalue
|
ubyte @shared bvalue
|
||||||
bvalue = ub1
|
bvalue = ub1 ^ ub2 ^ ub3 ^ true
|
||||||
bvalue ^= ub2
|
|
||||||
bvalue ^= ub3
|
|
||||||
bvalue ^= 1
|
|
||||||
bvalue = (((ub1^ub2)^ub3)^(ftrue(99)!=0))
|
bvalue = (((ub1^ub2)^ub3)^(ftrue(99)!=0))
|
||||||
bvalue = ((ub1&ub2)&(ftrue(99)!=0))
|
bvalue = ((ub1&ub2)&(ftrue(99)!=0))
|
||||||
return
|
return
|
||||||
*/
|
*/
|
||||||
stmts.size shouldBe 14
|
stmts.size shouldBe 11
|
||||||
val assignValue1 = (stmts[7] as Assignment).value as IdentifierReference
|
val assignValue1 = (stmts[7] as Assignment).value as BinaryExpression
|
||||||
val assignValue2 = (stmts[11] as Assignment).value as BinaryExpression
|
val assignValue2 = (stmts[8] as Assignment).value as BinaryExpression
|
||||||
val assignValue3 = (stmts[12] as Assignment).value as BinaryExpression
|
val assignValue3 = (stmts[9] as Assignment).value as BinaryExpression
|
||||||
assignValue1.nameInSource shouldBe listOf("ub1")
|
assignValue1.operator shouldBe "^"
|
||||||
assignValue2.operator shouldBe "^"
|
assignValue2.operator shouldBe "^"
|
||||||
assignValue3.operator shouldBe "&"
|
assignValue3.operator shouldBe "&"
|
||||||
val right2 = assignValue2.right as BinaryExpression
|
val right2 = assignValue2.right as BinaryExpression
|
||||||
|
|
|
@ -17,22 +17,18 @@ internal fun compileFile(
|
||||||
outputDir: Path = prog8tests.helpers.outputDir,
|
outputDir: Path = prog8tests.helpers.outputDir,
|
||||||
errors: IErrorReporter? = null,
|
errors: IErrorReporter? = null,
|
||||||
writeAssembly: Boolean = true,
|
writeAssembly: Boolean = true,
|
||||||
optFloatExpr: Boolean = true,
|
|
||||||
) : CompilationResult? {
|
) : CompilationResult? {
|
||||||
val filepath = fileDir.resolve(fileName)
|
val filepath = fileDir.resolve(fileName)
|
||||||
assumeReadableFile(filepath)
|
assumeReadableFile(filepath)
|
||||||
val args = CompilerArguments(
|
val args = CompilerArguments(
|
||||||
filepath,
|
filepath,
|
||||||
optimize,
|
optimize,
|
||||||
optimizeFloatExpressions = optFloatExpr,
|
|
||||||
writeAssembly = writeAssembly,
|
writeAssembly = writeAssembly,
|
||||||
slowCodegenWarnings = false,
|
|
||||||
quietAssembler = true,
|
quietAssembler = true,
|
||||||
asmListfile = false,
|
asmListfile = false,
|
||||||
experimentalCodegen = false,
|
experimentalCodegen = false,
|
||||||
varsHighBank = null,
|
varsHighBank = null,
|
||||||
platform.name,
|
platform.name,
|
||||||
evalStackBaseAddress = null,
|
|
||||||
symbolDefs = emptyMap(),
|
symbolDefs = emptyMap(),
|
||||||
outputDir = outputDir,
|
outputDir = outputDir,
|
||||||
errors = errors ?: ErrorReporterForTests(),
|
errors = errors ?: ErrorReporterForTests(),
|
||||||
|
@ -52,11 +48,10 @@ internal fun compileText(
|
||||||
sourceText: String,
|
sourceText: String,
|
||||||
errors: IErrorReporter? = null,
|
errors: IErrorReporter? = null,
|
||||||
writeAssembly: Boolean = true,
|
writeAssembly: Boolean = true,
|
||||||
optFloatExpr: Boolean = true,
|
|
||||||
) : CompilationResult? {
|
) : CompilationResult? {
|
||||||
val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8")
|
val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8")
|
||||||
// we don't assumeNotExists(filePath) - should be ok to just overwrite it
|
// we don't assumeNotExists(filePath) - should be ok to just overwrite it
|
||||||
filePath.toFile().writeText(sourceText)
|
filePath.toFile().writeText(sourceText)
|
||||||
return compileFile(platform, optimize, filePath.parent, filePath.name,
|
return compileFile(platform, optimize, filePath.parent, filePath.name,
|
||||||
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr)
|
errors=errors, writeAssembly=writeAssembly)
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,10 +151,6 @@ One or more .p8 module files
|
||||||
Note that it is possible to use the watch mode with multiple modules as well, but it will
|
Note that it is possible to use the watch mode with multiple modules as well, but it will
|
||||||
recompile everything in that list even if only one of the files got updated.
|
recompile everything in that list even if only one of the files got updated.
|
||||||
|
|
||||||
``-slowwarn``
|
|
||||||
Shows debug warnings about slow or problematic assembly code generation.
|
|
||||||
Ideally, the compiler should use as few stack based evaluations as possible.
|
|
||||||
|
|
||||||
``-quietasm``
|
``-quietasm``
|
||||||
Don't print assembler output results.
|
Don't print assembler output results.
|
||||||
|
|
||||||
|
@ -176,12 +172,6 @@ One or more .p8 module files
|
||||||
Add this user-defined symbol directly to the beginning of the generated assembly file.
|
Add this user-defined symbol directly to the beginning of the generated assembly file.
|
||||||
Can be repeated to define multiple symbols.
|
Can be repeated to define multiple symbols.
|
||||||
|
|
||||||
``-esa <address>``
|
|
||||||
Override the base address of the evaluation stack. Has to be page-aligned.
|
|
||||||
You can specify an integer or hexadecimal address.
|
|
||||||
When not compiling for the Commander X16 target, the location of the 16 virtual registers cx16.r0..r15
|
|
||||||
is changed accordingly (to keep them in the same memory space as the evaluation stack).
|
|
||||||
|
|
||||||
``-varshigh <rambank>``
|
``-varshigh <rambank>``
|
||||||
Places the non-zeropage variables in a separate high memory area, instead of inside the program itself.
|
Places the non-zeropage variables in a separate high memory area, instead of inside the program itself.
|
||||||
This results in an increase of the amount of system ram available for the program
|
This results in an increase of the amount of system ram available for the program
|
||||||
|
|
|
@ -945,15 +945,12 @@ syscall (callnr), syscall1 (callnr, arg), syscall2 (callnr, arg1, arg2), syscall
|
||||||
specific memory locations. So these builtin function calls are not useful yet except for
|
specific memory locations. So these builtin function calls are not useful yet except for
|
||||||
experimentation in new code generation targets.
|
experimentation in new code generation targets.
|
||||||
|
|
||||||
rsave, rsavex
|
rsave
|
||||||
Saves all registers including status (or only X) on the stack
|
Saves all registers including status (or only X) on the stack
|
||||||
It's not needed to rsave()/rsavex() before an asm subroutine that clobbers the X register
|
|
||||||
(which is used by prog8 as the internal evaluation stack pointer);
|
|
||||||
the compiler will take care of this situation automatically.
|
|
||||||
Note: the 16 bit 'virtual' registers of the Commander X16 are *not* saved,
|
Note: the 16 bit 'virtual' registers of the Commander X16 are *not* saved,
|
||||||
but you can use ``cx16.save_virtual_registers()`` for that.
|
but you can use ``cx16.save_virtual_registers()`` for that.
|
||||||
|
|
||||||
rrestore, rrestorex
|
rrestore
|
||||||
Restore all registers including status (or only X) back from the cpu hardware stack
|
Restore all registers including status (or only X) back from the cpu hardware stack
|
||||||
Note: the 16 bit 'virtual' registers of the Commander X16 are *not* restored,
|
Note: the 16 bit 'virtual' registers of the Commander X16 are *not* restored,
|
||||||
but you can use ``cx16.restore_virtual_registers()`` for that.
|
but you can use ``cx16.restore_virtual_registers()`` for that.
|
||||||
|
|
|
@ -56,35 +56,31 @@ Both systems have ways to alter the memory map and/or to switch memory banks, bu
|
||||||
Footnotes for the Commander X16
|
Footnotes for the Commander X16
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
*Golden Ram $0400 - $07FF*
|
*Golden Ram $0400 - $07FF*
|
||||||
*reserved:* $0700 - $07FF (expression evaluation stack)
|
*free to use.*
|
||||||
|
|
||||||
*free to use:* $0400 - $06FF
|
|
||||||
|
|
||||||
*Zero Page $0000 - $00FF*
|
*Zero Page $0000 - $00FF*
|
||||||
$00 and $01 are hardwired as Rom and Ram banking registers.
|
$00 and $01 are hardwired as Rom and Ram banking registers.
|
||||||
|
|
||||||
$02 - $21 are the 16 virtual cx16 registers R0-R15.
|
$02 - $21 are the 16 virtual cx16 registers R0-R15.
|
||||||
|
|
||||||
$22 - $7F are free to use, and Prog8 utilizes this to put variables in automatically.
|
$22 - $7F are used by Prog8 to put variables in.
|
||||||
|
|
||||||
The top half of the ZP ($80-$FF) is reserved for use by the Kernal and Basic in normal operation.
|
The top half of the ZP ($80-$FF) is reserved for use by the Kernal and Basic in normal operation.
|
||||||
Zero page use by Prog8 can be manipulated with the ``%zeropage`` directive, various options
|
Zero page use by Prog8 can be manipulated with the ``%zeropage`` directive, various options
|
||||||
may free up more locations for use by Prog8.
|
may free up more locations for use by Prog8 or to reserve them for other things.
|
||||||
|
|
||||||
|
|
||||||
Footnotes for the Commodore 64
|
Footnotes for the Commodore 64
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
*RAM $C000-$CFFF*
|
*RAM $C000-$CFFF*
|
||||||
*reserved:* $CF00 - $CFFF (expression evaluation stack)
|
*free to use:* $C000 - $CFDF
|
||||||
*this includes:* $CF00 - $CF20 for the 16 virtual cx16 registers R0-R15
|
*reserved:* $CFE0 - $CFFF for the 16 virtual cx16 registers R0-R15
|
||||||
|
|
||||||
*free to use:* $C000 - $CEFF
|
|
||||||
|
|
||||||
*Zero Page $0000 - $00FF*
|
*Zero Page $0000 - $00FF*
|
||||||
Consider the full zero page to be reserved for use by the Kernal and Basic in normal operation.
|
Consider the full zero page to be reserved for use by the Kernal and Basic in normal operation.
|
||||||
Zero page use by Prog8 can be manipulated with the ``%zeropage`` directive, various options
|
Zero page use by Prog8 can be manipulated with the ``%zeropage`` directive, various options
|
||||||
may free up more locations for use by Prog8.
|
may free up more locations for use by Prog8 or to reserve them for other things.
|
||||||
|
|
||||||
|
|
||||||
Zero page usage by the Prog8 compiler
|
Zero page usage by the Prog8 compiler
|
||||||
|
@ -127,8 +123,6 @@ Directly Usable Registers
|
||||||
|
|
||||||
The hardware CPU registers are not directly accessible from regular Prog8 code.
|
The hardware CPU registers are not directly accessible from regular Prog8 code.
|
||||||
If you need to mess with them, you'll have to use inline assembly.
|
If you need to mess with them, you'll have to use inline assembly.
|
||||||
Be extra wary of the ``X`` register because it is used as an evaluation stack pointer and
|
|
||||||
changing its value you will destroy the evaluation stack and likely crash the program.
|
|
||||||
|
|
||||||
The status register (P) carry flag and interrupt disable flag can be written via a couple of special
|
The status register (P) carry flag and interrupt disable flag can be written via a couple of special
|
||||||
builtin functions (``set_carry()``, ``clear_carry()``, ``set_irqd()``, ``clear_irqd()``),
|
builtin functions (``set_carry()``, ``clear_carry()``, ``set_irqd()``, ``clear_irqd()``),
|
||||||
|
|
|
@ -44,28 +44,6 @@ All elements in scoped names such as ``main.routine.var1`` are prefixed so this
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
Software stack for expression evaluation
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
Prog8 uses a software stack to evaluate complex expressions that it can't calculate in-place or
|
|
||||||
directly into the target variable, register, or memory location.
|
|
||||||
|
|
||||||
'software stack' means: seperated and not using the processor's hardware stack.
|
|
||||||
|
|
||||||
The software stack is implemented as follows:
|
|
||||||
|
|
||||||
- 2*128 bytes = 1 page of memory allocated for this, exact locations vary per machine target.
|
|
||||||
For the C64 this page is at $cf00-$cfff.
|
|
||||||
For the Commander X16 it is at $0700-$07ff (top of the "golden ram" area).
|
|
||||||
This default location can be overridden using the `-esa` command line option.
|
|
||||||
- these are the high and low bytes of the values on the stack (it's a 'split 16 bit word stack')
|
|
||||||
- for byte values just the lsb page is used, for word values both pages
|
|
||||||
- float values (5 bytes) are chopped up into 2 words and 1 byte on this stack.
|
|
||||||
- the X register is permanently allocated to be the stack pointer in the software stack.
|
|
||||||
- you can use the X register as long as you're not using the software stack.
|
|
||||||
But you *must* make sure it is saved and restored after the code that modifies it,
|
|
||||||
otherwise the evaluation stack gets corrupted.
|
|
||||||
|
|
||||||
Subroutine Calling Convention
|
Subroutine Calling Convention
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
@ -94,8 +72,7 @@ regular subroutines
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
- subroutine parameters are just variables scoped to the subroutine.
|
- subroutine parameters are just variables scoped to the subroutine.
|
||||||
- the arguments passed in a call are evaluated (using the eval-stack if needed) and then
|
- the arguments passed in a call are evaluated and then copied into those variables.
|
||||||
copied into those variables.
|
|
||||||
Using variables for this sometimes can seem inefficient but it's required to allow subroutines to work locally
|
Using variables for this sometimes can seem inefficient but it's required to allow subroutines to work locally
|
||||||
with their parameters and allow them to modify them as required, without changing the
|
with their parameters and allow them to modify them as required, without changing the
|
||||||
variables used in the call's arguments. If you want to get rid of this overhead you'll
|
variables used in the call's arguments. If you want to get rid of this overhead you'll
|
||||||
|
@ -118,40 +95,6 @@ doing something with that returnvalue. This can be on purpose if you're simply n
|
||||||
Use the ``void`` keyword in front of the subroutine call to get rid of the warning in that case.
|
Use the ``void`` keyword in front of the subroutine call to get rid of the warning in that case.
|
||||||
|
|
||||||
|
|
||||||
The 6502 CPU's X-register: off-limits
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
Prog8 uses the cpu's X-register as a pointer in its internal expression evaluation stack.
|
|
||||||
When only writing code in Prog8, this is taken care of behind the scenes for you by the compiler.
|
|
||||||
However when you are including or linking with assembly routines or Kernal/ROM calls that *do*
|
|
||||||
use the X register (either clobbering it internally, or using it as a parameter, or return value register),
|
|
||||||
those calls will destroy Prog8's stack pointer and this will result in invalid calculations.
|
|
||||||
|
|
||||||
You should avoid using the X register in your assembly code, or take preparations.
|
|
||||||
If you make sure that the value of the X register is preserved before calling a routine
|
|
||||||
that uses it, and restored when the routine is done, you'll be ok.
|
|
||||||
|
|
||||||
Routines that return a value in the X register can be called from Prog8 but the return value is
|
|
||||||
inaccessible unless you write a short piece of inline assembly code to deal with it yourself, such as::
|
|
||||||
|
|
||||||
ubyte returnvalue
|
|
||||||
|
|
||||||
%asm {{
|
|
||||||
stx P8ZP_SCRATCH_REG ; use 'phx/plx' if using 65c02 cpu
|
|
||||||
ldx #10
|
|
||||||
jsr routine_using_x
|
|
||||||
stx returnvalue
|
|
||||||
ldx P8ZP_SCRATCH_REG
|
|
||||||
}}
|
|
||||||
; now use 'returnvalue' variable
|
|
||||||
|
|
||||||
Prog8 also provides some help to deal with this:
|
|
||||||
|
|
||||||
- you should use a ``clobbers(X)`` specification for asmsub routines that modify the X register; the compiler will preserve it for you automatically when such a routine is called
|
|
||||||
- the ``rsavex()`` and ``rrestorex()`` builtin functions can preserve and restore the X register
|
|
||||||
- the ``rsave()`` and ``rrestore()`` builtin functions can preserve and restore *all* registers (but this is very slow and overkill if you only need to save X)
|
|
||||||
|
|
||||||
|
|
||||||
Compiler Internals
|
Compiler Internals
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -48,16 +48,6 @@ Libraries:
|
||||||
- c64: make the graphics.BITMAP_ADDRESS configurable (VIC banking)
|
- c64: make the graphics.BITMAP_ADDRESS configurable (VIC banking)
|
||||||
|
|
||||||
|
|
||||||
Expressions: (see remove_evalstack branch):
|
|
||||||
|
|
||||||
- Once the evalstack-free expression codegen is in place, the Eval Stack can be removed from the compiler.
|
|
||||||
Machinedefinition, .p8 and .asm library files, all routines operationg on estack, and everything saving/restoring the X register related to this stack.
|
|
||||||
- Or rewrite expression tree evaluation such that it doesn't use an eval stack but flatten the tree into linear code
|
|
||||||
that, for instance, uses a fixed number of predetermined value 'variables'?
|
|
||||||
The VM IL solves this already (by using unlimited registers) but that still lacks a translation to 6502.
|
|
||||||
- this removes the need for the BinExprSplitter? (which is problematic and very limited now)
|
|
||||||
and perhaps the assignment splitting in BeforeAsmAstChanger too
|
|
||||||
|
|
||||||
Optimizations:
|
Optimizations:
|
||||||
|
|
||||||
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
|
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
|
||||||
|
|
|
@ -63,9 +63,8 @@ main {
|
||||||
cx16.GRAPH_put_next_char(c)
|
cx16.GRAPH_put_next_char(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_number_gfx(ubyte num @ A) clobbers(A,Y) {
|
asmsub print_number_gfx(ubyte num @ A) clobbers(A,X,Y) {
|
||||||
%asm {{
|
%asm {{
|
||||||
phx
|
|
||||||
jsr conv.ubyte2decimal
|
jsr conv.ubyte2decimal
|
||||||
phx
|
phx
|
||||||
pha
|
pha
|
||||||
|
@ -81,9 +80,7 @@ main {
|
||||||
beq _ones
|
beq _ones
|
||||||
jsr cx16.GRAPH_put_char
|
jsr cx16.GRAPH_put_char
|
||||||
_ones pla
|
_ones pla
|
||||||
jsr cx16.GRAPH_put_char
|
jmp cx16.GRAPH_put_char
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,24 @@
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
|
||||||
; The documentation for custom PS2 key handlers can be found here:
|
; The documentation for custom key handlers can be found here:
|
||||||
; https://github.com/X16Community/x16-docs/blob/master/X16%20Reference%20-%2002%20-%20Editor.md#custom-keyboard-scancode-handler
|
; https://github.com/X16Community/x16-docs/blob/master/X16%20Reference%20-%2002%20-%20Editor.md#custom-keyboard-keynum-code-handler
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
|
bool stop_program = false
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
txt.print("custom key handler test - press keys! esc to quit!\n")
|
txt.print("custom key handler test - press keys! esc to quit!\n")
|
||||||
|
|
||||||
sys.set_irqd()
|
sys.set_irqd()
|
||||||
uword old_keyhdl = cx16.KEYHDL
|
uword old_keyhdl = cx16.KEYHDL
|
||||||
cx16.KEYHDL = &keyboard_scancode_handler
|
cx16.KEYHDL = &keyboard_handler
|
||||||
sys.clear_irqd()
|
sys.clear_irqd()
|
||||||
|
|
||||||
while handle_keyboard_event() {
|
while not stop_program {
|
||||||
|
; wait
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.set_irqd()
|
sys.set_irqd()
|
||||||
|
@ -24,55 +27,23 @@ main {
|
||||||
sys.clear_irqd()
|
sys.clear_irqd()
|
||||||
}
|
}
|
||||||
|
|
||||||
; Keyboard handler communication variables.
|
sub keyboard_handler(ubyte keynum) -> ubyte {
|
||||||
; these need to be in block scope instead of in a subroutine,
|
; NOTE: this handler routine expects the keynum in A and return value in A
|
||||||
; so that they won't get overwritten with initialization values every time.
|
; which is thankfully how prog8 translates this subroutine's calling convention.
|
||||||
; The assembly keyboard handler will set these, prog8 will read them.
|
; NOTE: it may be better to store the keynum somewhere else and let the main program
|
||||||
bool @shared keyhdl_event ; is there a keyboard event to handle?
|
; loop figure out what to do with it, rather than putting it all in the handler routine
|
||||||
ubyte @shared keyhdl_scancode
|
txt.print_ubhex(keynum, true)
|
||||||
|
|
||||||
sub handle_keyboard_event() -> bool {
|
|
||||||
; Potentially handle keyboard event.
|
|
||||||
; Note that we do this from the program's main loop instead of
|
|
||||||
; the actual keyboard handler routine itself.
|
|
||||||
; The reason for this is documented below in the handler assembly routine.
|
|
||||||
if not keyhdl_event
|
|
||||||
return true
|
|
||||||
keyhdl_event = false
|
|
||||||
txt.print_ubhex(keyhdl_scancode, true)
|
|
||||||
txt.spc()
|
txt.spc()
|
||||||
if keyhdl_scancode & $80
|
if keynum & $80
|
||||||
txt.chrout('u')
|
txt.chrout('u')
|
||||||
else
|
else
|
||||||
txt.chrout('d')
|
txt.chrout('d')
|
||||||
txt.nl()
|
txt.nl()
|
||||||
return keyhdl_scancode!=$6e ; escape breaks the loop
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub keyboard_scancode_handler() {
|
if keynum==$6e {
|
||||||
; NOTE that the keyboard handler is an asm subroutine.
|
; escape stops the program
|
||||||
; Unfortunately is it not possible to use prog8 code or calls here,
|
main.stop_program = true
|
||||||
; because the X register gets overwritten here by the kernal.
|
}
|
||||||
; Pog8 uses the X register internally (for the software eval stack).
|
return 0 ; By returning 0 (in A) we will eat this key event. Return the original keynum value to pass it through.
|
||||||
; So it is unsafe to call prog8 code from here because the evaluation stack pointer
|
|
||||||
; will be invalid which produces undefined results.
|
|
||||||
; So, instead, we store the various keyboard event bytes and signal
|
|
||||||
; the main prog8 program that a keyboard event has occurred.
|
|
||||||
; It then processes it independently from the assembly code here.
|
|
||||||
;
|
|
||||||
; Unfortunately this also means you cannot decide easily from that prog8 code
|
|
||||||
; if the keyboard press should be consumed/ignored or put into the keyboard queue
|
|
||||||
; (this is controlled by returning 0 or 1 in register A here)
|
|
||||||
|
|
||||||
%asm {{
|
|
||||||
pha
|
|
||||||
sta p8_keyhdl_scancode
|
|
||||||
lda #1
|
|
||||||
sta p8_keyhdl_event
|
|
||||||
pla
|
|
||||||
|
|
||||||
lda #0 ; By setting A=0 we will eat this key event. leave A unchanged to pass it through.
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
txt.print("calculating mandelbrot fractal...\n\n")
|
txt.print("calculating mandelbrot fractal...\n\n")
|
||||||
|
cbm.SETTIM(0,0,0)
|
||||||
|
|
||||||
ubyte pixelx
|
ubyte pixelx
|
||||||
ubyte pixely
|
ubyte pixely
|
||||||
|
@ -37,5 +38,10 @@ main {
|
||||||
}
|
}
|
||||||
txt.nl()
|
txt.nl()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float duration = (cbm.RDTIM16() as float) / 60
|
||||||
|
txt.print("\nfinished in ")
|
||||||
|
floats.print_f(duration)
|
||||||
|
txt.print(" seconds!\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,11 +33,8 @@ class RequestParser : Take {
|
||||||
val args = CompilerArguments(
|
val args = CompilerArguments(
|
||||||
Path(a),
|
Path(a),
|
||||||
optimize = true,
|
optimize = true,
|
||||||
optimizeFloatExpressions = false,
|
|
||||||
writeAssembly = true,
|
writeAssembly = true,
|
||||||
slowCodegenWarnings = true,
|
|
||||||
compilationTarget = "c64",
|
compilationTarget = "c64",
|
||||||
evalStackBaseAddress = null,
|
|
||||||
symbolDefs = emptyMap(),
|
symbolDefs = emptyMap(),
|
||||||
quietAssembler = false,
|
quietAssembler = false,
|
||||||
asmListfile = false,
|
asmListfile = false,
|
||||||
|
|
|
@ -88,7 +88,6 @@ class IRFileReader {
|
||||||
val zpReserved = mutableListOf<UIntRange>()
|
val zpReserved = mutableListOf<UIntRange>()
|
||||||
var loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
var loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
||||||
var optimize = true
|
var optimize = true
|
||||||
var evalStackBaseAddress: UInt? = null
|
|
||||||
var outputDir = Path("")
|
var outputDir = Path("")
|
||||||
|
|
||||||
if(text.isNotBlank()) {
|
if(text.isNotBlank()) {
|
||||||
|
@ -109,7 +108,6 @@ class IRFileReader {
|
||||||
"launcher" -> launcher = CbmPrgLauncherType.valueOf(value)
|
"launcher" -> launcher = CbmPrgLauncherType.valueOf(value)
|
||||||
"zeropage" -> zeropage = ZeropageType.valueOf(value)
|
"zeropage" -> zeropage = ZeropageType.valueOf(value)
|
||||||
"loadAddress" -> loadAddress = parseIRValue(value).toUInt()
|
"loadAddress" -> loadAddress = parseIRValue(value).toUInt()
|
||||||
"evalStackBaseAddress" -> evalStackBaseAddress = if(value=="") null else parseIRValue(value).toUInt()
|
|
||||||
"zpReserved" -> {
|
"zpReserved" -> {
|
||||||
val (zpstart, zpend) = value.split(',')
|
val (zpstart, zpend) = value.split(',')
|
||||||
zpReserved.add(UIntRange(zpstart.toUInt(), zpend.toUInt()))
|
zpReserved.add(UIntRange(zpstart.toUInt(), zpend.toUInt()))
|
||||||
|
@ -130,7 +128,6 @@ class IRFileReader {
|
||||||
false,
|
false,
|
||||||
target,
|
target,
|
||||||
loadAddress,
|
loadAddress,
|
||||||
evalStackBaseAddress = evalStackBaseAddress,
|
|
||||||
outputDir = outputDir,
|
outputDir = outputDir,
|
||||||
optimize = optimize
|
optimize = optimize
|
||||||
)
|
)
|
||||||
|
|
|
@ -110,7 +110,6 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||||
is IRInlineAsmChunk -> writeInlineAsm(chunk)
|
is IRInlineAsmChunk -> writeInlineAsm(chunk)
|
||||||
is IRInlineBinaryChunk -> writeInlineBytes(chunk)
|
is IRInlineBinaryChunk -> writeInlineBytes(chunk)
|
||||||
is IRCodeChunk -> writeCodeChunk(chunk)
|
is IRCodeChunk -> writeCodeChunk(chunk)
|
||||||
else -> throw InternalCompilerException("invalid chunk")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xml.writeEndElement()
|
xml.writeEndElement()
|
||||||
|
@ -171,7 +170,6 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||||
}
|
}
|
||||||
xml.writeCharacters("loadAddress=${irProgram.options.loadAddress.toHex()}\n")
|
xml.writeCharacters("loadAddress=${irProgram.options.loadAddress.toHex()}\n")
|
||||||
xml.writeCharacters("optimize=${irProgram.options.optimize}\n")
|
xml.writeCharacters("optimize=${irProgram.options.optimize}\n")
|
||||||
xml.writeCharacters("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress?.toHex() ?: ""}\n")
|
|
||||||
xml.writeCharacters("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n")
|
xml.writeCharacters("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n")
|
||||||
// other options not yet useful here?
|
// other options not yet useful here?
|
||||||
xml.writeEndElement()
|
xml.writeEndElement()
|
||||||
|
|
|
@ -168,7 +168,6 @@ class IRProgram(val name: String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is IRInlineBinaryChunk -> { }
|
is IRInlineBinaryChunk -> { }
|
||||||
else -> throw AssemblyError("invalid chunk")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,6 @@ output=PRG
|
||||||
launcher=BASIC
|
launcher=BASIC
|
||||||
zeropage=KERNALSAFE
|
zeropage=KERNALSAFE
|
||||||
loadAddress=$0000
|
loadAddress=$0000
|
||||||
evalStackBaseAddress=
|
|
||||||
</OPTIONS>
|
</OPTIONS>
|
||||||
|
|
||||||
<ASMSYMBOLS>
|
<ASMSYMBOLS>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package prog8.vm
|
package prog8.vm
|
||||||
|
|
||||||
import prog8.code.core.AssemblyError
|
|
||||||
import prog8.intermediate.FunctionCallArgs
|
import prog8.intermediate.FunctionCallArgs
|
||||||
import prog8.intermediate.IRDataType
|
import prog8.intermediate.IRDataType
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
@ -484,7 +483,6 @@ object SysCalls {
|
||||||
val result = floor(radians/2.0/PI*256.0)
|
val result = floor(radians/2.0/PI*256.0)
|
||||||
returnValue(callspec.returns!!, result, vm)
|
returnValue(callspec.returns!!, result, vm)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("missing syscall ${call.name}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ class VmProgramLoader {
|
||||||
|
|
||||||
subroutines.forEach {
|
subroutines.forEach {
|
||||||
it.value.chunks.forEach { chunk ->
|
it.value.chunks.forEach { chunk ->
|
||||||
chunk.instructions.withIndex().forEach { (index, ins) ->
|
chunk.instructions.withIndex().forEach { (_, ins) ->
|
||||||
if(ins.opcode==Opcode.CALL) {
|
if(ins.opcode==Opcode.CALL) {
|
||||||
val fcallspec = ins.fcallArgs!!
|
val fcallspec = ins.fcallArgs!!
|
||||||
val argsWithAddresses = fcallspec.arguments.map { arg ->
|
val argsWithAddresses = fcallspec.arguments.map { arg ->
|
||||||
|
|
Loading…
Reference in New Issue
Block a user