mirror of
https://github.com/irmen/prog8.git
synced 2025-02-13 18:31:04 +00:00
optimize codegen for x += array[index] (and others)
This commit is contained in:
parent
68d5983a14
commit
3b4b37f16b
@ -1115,6 +1115,21 @@ $repeatLabel""")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun signExtendAXlsb(valueDt: BaseDataType) {
|
||||
// sign extend signed byte in A to full word in AX
|
||||
when(valueDt) {
|
||||
BaseDataType.UBYTE -> out(" ldx #0")
|
||||
BaseDataType.BYTE -> out("""
|
||||
ldx #0
|
||||
cmp #$80
|
||||
bcc +
|
||||
dex
|
||||
+
|
||||
""")
|
||||
else -> throw AssemblyError("need byte type")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun signExtendVariableLsb(asmvar: String, valueDt: BaseDataType) {
|
||||
// sign extend signed byte in a var to a full word in that variable
|
||||
when(valueDt) {
|
||||
|
@ -68,18 +68,18 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
when {
|
||||
target.datatype.isByteOrBool -> {
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(target.asmVarname, target.datatype, operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(target.asmVarname, target.datatype, operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype.isSigned, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype.isSigned, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(target.asmVarname, target.datatype, operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(target.asmVarname, target.datatype, operator, value.array!!)
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteWithLiteralval(target.asmVarname, target.datatype, operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteWithLiteralval(target.asmVarname, target.datatype, operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteWithVariable(target.asmVarname, target.datatype.isSigned, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteWithVariable(target.asmVarname, target.datatype.isSigned, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteWithValue(target.asmVarname, target.datatype, operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteWithValue(target.asmVarname, target.datatype, operator, value.array!!)
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
if(value.expression is PtTypeCast) {
|
||||
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
|
||||
inplacemodificationByteVariableWithValue(target.asmVarname, target.datatype, operator, value.expression)
|
||||
inplacemodificationByteWithValue(target.asmVarname, target.datatype, operator, value.expression)
|
||||
} else {
|
||||
inplacemodificationByteVariableWithValue(target.asmVarname, target.datatype, operator, value.expression!!)
|
||||
inplacemodificationByteWithValue(target.asmVarname, target.datatype, operator, value.expression!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,18 +131,18 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
is PtNumber -> {
|
||||
val addr = (memory.address as PtNumber).number.toInt()
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(addr.toHex(), false, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(addr.toHex(), false, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.array!!)
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteWithLiteralval(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteWithLiteralval(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteWithVariable(addr.toHex(), false, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteWithVariable(addr.toHex(), false, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.array!!)
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
if(value.expression is PtTypeCast) {
|
||||
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
|
||||
inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.expression)
|
||||
inplacemodificationByteWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.expression)
|
||||
} else {
|
||||
inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.expression!!)
|
||||
inplacemodificationByteWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.expression!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,21 +192,21 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
SourceStorageKind.MEMORY -> {
|
||||
asmgen.out(" sta P8ZP_SCRATCH_B1")
|
||||
inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), operator, value.memory!!)
|
||||
inplacemodificationByteWithValue("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), operator, value.memory!!)
|
||||
asmgen.out(" ldx P8ZP_SCRATCH_B1")
|
||||
}
|
||||
SourceStorageKind.ARRAY -> {
|
||||
asmgen.out(" sta P8ZP_SCRATCH_B1")
|
||||
inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), operator, value.array!!)
|
||||
inplacemodificationByteWithValue("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), operator, value.array!!)
|
||||
asmgen.out(" ldx P8ZP_SCRATCH_B1")
|
||||
}
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
val tempVar = asmgen.getTempVarName(BaseDataType.UBYTE)
|
||||
asmgen.out(" sta $tempVar")
|
||||
if(value.expression is PtTypeCast)
|
||||
inplacemodificationByteVariableWithValue(tempVar, DataType.forDt(BaseDataType.UBYTE), operator, value.expression)
|
||||
inplacemodificationByteWithValue(tempVar, DataType.forDt(BaseDataType.UBYTE), operator, value.expression)
|
||||
else
|
||||
inplacemodificationByteVariableWithValue(tempVar, DataType.forDt(BaseDataType.UBYTE), operator, value.expression!!)
|
||||
inplacemodificationByteWithValue(tempVar, DataType.forDt(BaseDataType.UBYTE), operator, value.expression!!)
|
||||
asmgen.out(" ldx $tempVar")
|
||||
}
|
||||
}
|
||||
@ -239,18 +239,18 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
when {
|
||||
target.datatype.isByteOrBool -> {
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(targetVarName, target.datatype, operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(targetVarName, target.datatype, operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype.isSigned, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype.isSigned, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(targetVarName, target.datatype, operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(targetVarName, target.datatype, operator, value.array!!)
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteWithLiteralval(targetVarName, target.datatype, operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteWithLiteralval(targetVarName, target.datatype, operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteWithVariable(targetVarName, target.datatype.isSigned, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteWithVariable(targetVarName, target.datatype.isSigned, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteWithValue(targetVarName, target.datatype, operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteWithValue(targetVarName, target.datatype, operator, value.array!!)
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
if(value.expression is PtTypeCast) {
|
||||
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
|
||||
inplacemodificationByteVariableWithValue(targetVarName, target.datatype, operator, value.expression)
|
||||
inplacemodificationByteWithValue(targetVarName, target.datatype, operator, value.expression)
|
||||
} else {
|
||||
inplacemodificationByteVariableWithValue(targetVarName, target.datatype, operator, value.expression!!)
|
||||
inplacemodificationByteWithValue(targetVarName, target.datatype, operator, value.expression!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -336,14 +336,14 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
|
||||
SourceStorageKind.MEMORY -> {
|
||||
asmgen.out(" sta P8ZP_SCRATCH_B1")
|
||||
inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", target.datatype, operator, value.memory!!)
|
||||
inplacemodificationByteWithValue("P8ZP_SCRATCH_B1", target.datatype, operator, value.memory!!)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||
asmgen.out(" lda P8ZP_SCRATCH_B1")
|
||||
}
|
||||
|
||||
SourceStorageKind.ARRAY -> {
|
||||
asmgen.out(" sta P8ZP_SCRATCH_B1")
|
||||
inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", target.datatype, operator, value.array!!)
|
||||
inplacemodificationByteWithValue("P8ZP_SCRATCH_B1", target.datatype, operator, value.array!!)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||
asmgen.out(" lda P8ZP_SCRATCH_B1")
|
||||
}
|
||||
@ -352,9 +352,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
val tempVar = asmgen.getTempVarName(BaseDataType.UBYTE)
|
||||
asmgen.out(" sta $tempVar")
|
||||
if(value.expression is PtTypeCast)
|
||||
inplacemodificationByteVariableWithValue(tempVar, target.datatype, operator, value.expression)
|
||||
inplacemodificationByteWithValue(tempVar, target.datatype, operator, value.expression)
|
||||
else
|
||||
inplacemodificationByteVariableWithValue(tempVar, target.datatype, operator, value.expression!!)
|
||||
inplacemodificationByteWithValue(tempVar, target.datatype, operator, value.expression!!)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||
asmgen.out(" lda $tempVar")
|
||||
}
|
||||
@ -1057,7 +1057,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun inplacemodificationByteVariableWithValue(name: String, dt: DataType, operator: String, value: PtExpression) {
|
||||
private fun inplacemodificationByteWithValue(name: String, dt: DataType, operator: String, value: PtExpression) {
|
||||
require(dt.isByteOrBool)
|
||||
if(!value.isSimple()) {
|
||||
// attempt short-circuit (McCarthy) evaluation
|
||||
@ -1102,13 +1102,27 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
|
||||
if(value is PtArrayIndexer && value.isSimple()) {
|
||||
// use the already existing optimized codegen for regular assignments x += array[index]
|
||||
val binexpr = PtBinaryExpression(operator, dt, value.position)
|
||||
binexpr.add(PtIdentifier(name, dt, value.position))
|
||||
val arrayValue = PtArrayIndexer(value.type, value.position)
|
||||
arrayValue.add(value.variable)
|
||||
arrayValue.add(value.index)
|
||||
binexpr.add(arrayValue)
|
||||
binexpr.parent = value
|
||||
assignmentAsmGen.assignExpressionToRegister(binexpr, RegisterOrPair.A, dt.isSigned)
|
||||
asmgen.out(" sta $name")
|
||||
return
|
||||
}
|
||||
|
||||
// normal evaluation
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned)
|
||||
inplacemodificationRegisterAwithVariableWithSwappedOperands(operator, name, dt.isSigned)
|
||||
asmgen.out(" sta $name")
|
||||
}
|
||||
|
||||
private fun inplacemodificationByteVariableWithVariable(name: String, signed: Boolean, operator: String, otherName: String) {
|
||||
private fun inplacemodificationByteWithVariable(name: String, signed: Boolean, operator: String, otherName: String) {
|
||||
// note: no logical and/or shortcut here, not worth it due to simple right operand
|
||||
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
||||
@ -1314,6 +1328,7 @@ $shortcutLabel:""")
|
||||
when (operator) {
|
||||
"-" -> {
|
||||
// A = variable - A
|
||||
// TODO optimize codegen to avoid temporary
|
||||
val tmpVar = if(variable!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG"
|
||||
asmgen.out(" sta $tmpVar | lda $variable | sec | sbc $tmpVar")
|
||||
}
|
||||
@ -1465,7 +1480,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
|
||||
private fun inplacemodificationByteVariableWithLiteralval(name: String, dt: DataType, operator: String, value: Int) {
|
||||
private fun inplacemodificationByteWithLiteralval(name: String, dt: DataType, operator: String, value: Int) {
|
||||
// note: this contains special optimized cases because we know the exact value. Don't replace this with another routine.
|
||||
// note: no logical and/or shortcut here, not worth it due to simple right operand
|
||||
require(dt.isByteOrBool)
|
||||
@ -2634,16 +2649,16 @@ $shortcutLabel:""")
|
||||
|
||||
private fun inplacemodificationWordWithValue(name: String, dt: DataType, operator: String, value: PtExpression, block: PtBlock?) {
|
||||
require(dt.isWord)
|
||||
fun multiplyVarByWordInAY() {
|
||||
fun multiplyVarByWordInAX() {
|
||||
if(block?.options?.veraFxMuls==true)
|
||||
// cx16 verafx hardware muls
|
||||
asmgen.out("""
|
||||
sta cx16.r1
|
||||
sty cx16.r1+1
|
||||
stx cx16.r1+1
|
||||
lda $name
|
||||
ldy $name+1
|
||||
ldx $name+1
|
||||
sta cx16.r0
|
||||
sty cx16.r0+1
|
||||
stx cx16.r0+1
|
||||
jsr verafx.muls
|
||||
sta $name
|
||||
sty $name+1
|
||||
@ -2651,7 +2666,7 @@ $shortcutLabel:""")
|
||||
else
|
||||
asmgen.out("""
|
||||
sta prog8_math.multiply_words.multiplier
|
||||
sty prog8_math.multiply_words.multiplier+1
|
||||
stx prog8_math.multiply_words.multiplier+1
|
||||
lda $name
|
||||
ldy $name+1
|
||||
jsr prog8_math.multiply_words
|
||||
@ -2753,8 +2768,8 @@ $shortcutLabel:""")
|
||||
// value is (u) byte value, sign extend that and proceed with regular 16 bit operation
|
||||
// TODO use an optimized word * byte multiplication routine?
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||
asmgen.signExtendAYlsb(valueDt.base)
|
||||
multiplyVarByWordInAY()
|
||||
asmgen.signExtendAXlsb(valueDt.base)
|
||||
multiplyVarByWordInAX()
|
||||
}
|
||||
"/" -> {
|
||||
// value is (u) byte value, sign extend that and proceed with regular 16 bit operation
|
||||
@ -2852,6 +2867,66 @@ $shortcutLabel:""")
|
||||
}
|
||||
valueDt.isWord -> {
|
||||
// the value is a proper 16-bit word, so use both bytes of it.
|
||||
|
||||
if(value is PtArrayIndexer && value.isSimple()) {
|
||||
// note: use AX as much as possible, to free Y for array indexing
|
||||
when (operator) {
|
||||
// note: use AX as much as possible, to free Y for array indexing
|
||||
"+" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AX)
|
||||
asmgen.out(" clc | adc $name | sta $name | txa | adc $name+1 | sta $name+1")
|
||||
return
|
||||
}
|
||||
"-" -> {
|
||||
if(value.index.type.isByte) {
|
||||
// it's an array indexed by a byte so we can use sbc array,y
|
||||
val arrayname = value.variable.name
|
||||
asmgen.loadScaledArrayIndexIntoRegister(value, CpuRegister.Y)
|
||||
if(value.splitWords) {
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
sec
|
||||
sbc ${arrayname}_lsb,y
|
||||
sta $name
|
||||
lda $name+1
|
||||
sbc ${arrayname}_msb,y
|
||||
sta $name+1""")
|
||||
} else {
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
sec
|
||||
sbc $arrayname,y
|
||||
sta $name
|
||||
lda $name+1
|
||||
sbc $arrayname+1,y
|
||||
sta $name+1""")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
"*" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AX)
|
||||
multiplyVarByWordInAX()
|
||||
return
|
||||
}
|
||||
"&" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AX)
|
||||
asmgen.out(" and $name | sta $name | txa | and $name+1 | sta $name+1")
|
||||
return
|
||||
}
|
||||
"|" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AX)
|
||||
asmgen.out(" ora $name | sta $name | txa | ora $name+1 | sta $name+1")
|
||||
return
|
||||
}
|
||||
"^" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AX)
|
||||
asmgen.out(" eor $name | sta $name | txa | eor $name+1 | sta $name+1")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
|
||||
@ -2860,11 +2935,11 @@ $shortcutLabel:""")
|
||||
"-" -> {
|
||||
val tmpWord = if(name!="P8ZP_SCRATCH_W1") "P8ZP_SCRATCH_W1" else "P8ZP_SCRATCH_W2"
|
||||
asmgen.assignExpressionToVariable(value, tmpWord, valueDt)
|
||||
asmgen.out(" lda $name | sec | sbc $tmpWord | sta $name | lda $name+1 | sbc $tmpWord+1 | sta $name+1")
|
||||
asmgen.out(" lda $name | sec | sbc $tmpWord | sta $name | lda $name+1 | sbc $tmpWord+1 | sta $name+1")
|
||||
}
|
||||
"*" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
|
||||
multiplyVarByWordInAY()
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AX)
|
||||
multiplyVarByWordInAX()
|
||||
}
|
||||
"/" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
|
||||
@ -2893,37 +2968,7 @@ $shortcutLabel:""")
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
|
||||
asmgen.out(" eor $name | sta $name | tya | eor $name+1 | sta $name+1")
|
||||
}
|
||||
"==" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
|
||||
asmgen.out("""
|
||||
cmp $name
|
||||
bne +
|
||||
cpy $name+1
|
||||
bne +
|
||||
lda #1
|
||||
bne ++
|
||||
+ lda #0
|
||||
+ sta $name
|
||||
lda #0
|
||||
sta $name+1""")
|
||||
}
|
||||
"!=" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY)
|
||||
asmgen.out("""
|
||||
cmp $name
|
||||
bne +
|
||||
cpy $name+1
|
||||
bne +
|
||||
lda #0
|
||||
beq ++
|
||||
+ lda #1
|
||||
+ sta $name
|
||||
lda #0
|
||||
sta $name+1""")
|
||||
}
|
||||
// pretty uncommon, who's going to assign a comparison boolean expression to a word var?:
|
||||
"<", "<=", ">", ">=" -> TODO("word-value-to-var comparisons")
|
||||
else -> throw AssemblyError("invalid operator for in-place modification $operator")
|
||||
else -> throw AssemblyError("invalid operator for in-place word modification $operator")
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("can only use integer datatypes here")
|
||||
|
@ -1,10 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- optimize word addition word += mul40[indexbyte] to use adc with register indexed instructions
|
||||
- same with other operators (sbc, and, or, eor)
|
||||
- how is tye codegen for byte values here?
|
||||
|
||||
- add paypal donation button as well?
|
||||
- announce prog8 on the 6502.org site?
|
||||
|
||||
@ -56,7 +52,7 @@ IR/VM
|
||||
- fix TODO("IR rol/ror on split words array")
|
||||
- fix "<< in array" / ">> in array"
|
||||
- implement fast code paths for TODO("inplace split....
|
||||
- sometimes source lines get missing in the output p8ir, for example the first assignment is gone in:
|
||||
- sometimes source lines end up missing in the output p8ir, for example the first assignment is gone in:
|
||||
sub start() {
|
||||
cx16.r0L = cx16.r1 as ubyte
|
||||
cx16.r0sL = cx16.r1s as byte
|
||||
|
235
examples/test.p8
235
examples/test.p8
@ -1,201 +1,58 @@
|
||||
%import textio
|
||||
%import math
|
||||
%import monogfx
|
||||
%import gfx_lores
|
||||
%option no_sysinit
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte bb, index
|
||||
uword ww
|
||||
index=2
|
||||
|
||||
math.rndseed(1234,8877)
|
||||
cbm.SETTIM(0,0,0)
|
||||
kernal()
|
||||
txt.print_uw(cbm.RDTIM16())
|
||||
ww = 1234
|
||||
cx16.r0=10000
|
||||
|
||||
sys.wait(200)
|
||||
cx16.r0 -= ww
|
||||
txt.print_uw(cx16.r0) ; 7532
|
||||
txt.nl()
|
||||
cx16.r0 += ww
|
||||
txt.print_uw(cx16.r0) ; 10000
|
||||
txt.nl()
|
||||
cx16.r0 &= ww
|
||||
txt.print_uw(cx16.r0) ; 10000
|
||||
txt.nl()
|
||||
|
||||
math.rndseed(1234,8877)
|
||||
cbm.SETTIM(0,0,0)
|
||||
custom_256()
|
||||
txt.print_uw(cbm.RDTIM16())
|
||||
; bb += tabb[index]
|
||||
; bb -= index
|
||||
; bb -= tabb[index]
|
||||
; bb &= tabb[index]
|
||||
; bb |= tabb[index]
|
||||
; bb ^= tabb[index]
|
||||
; bb *= tabb[index]
|
||||
;
|
||||
; cx16.r0L = bb + tabb[index]
|
||||
; cx16.r1L = bb - index
|
||||
; cx16.r2L = bb - tabb[index]
|
||||
; cx16.r3L = bb & tabb[index]
|
||||
; cx16.r4L = bb | tabb[index]
|
||||
; cx16.r5L = bb ^ tabb[index]
|
||||
; cx16.r6L = bb * tabb[index]
|
||||
|
||||
sys.wait(200)
|
||||
; ww += tabw[index]
|
||||
; ww -= tabw[index]
|
||||
; ww &= tabw[index]
|
||||
; ww |= tabw[index]
|
||||
; ww ^= tabw[index]
|
||||
; ww *= tabw[index]
|
||||
;
|
||||
; cx16.r0 = ww + tabw[index]
|
||||
; cx16.r1 = ww - cx16.r0
|
||||
; cx16.r2 = ww - tabw[index]
|
||||
; cx16.r3 = ww & tabw[index]
|
||||
; cx16.r4 = ww | tabw[index]
|
||||
; cx16.r5 = ww ^ tabw[index]
|
||||
; cx16.r6 = ww * tabw[index]
|
||||
|
||||
|
||||
math.rndseed(1234,8877)
|
||||
cbm.SETTIM(0,0,0)
|
||||
custom_mono()
|
||||
txt.print_uw(cbm.RDTIM16())
|
||||
|
||||
repeat {
|
||||
}
|
||||
ubyte[] tabb = [11,22,33,44,55,66]
|
||||
uword[] tabw = [111,222,333,444,555,666]
|
||||
}
|
||||
|
||||
sub kernal() {
|
||||
cx16.set_screen_mode(128)
|
||||
cx16.GRAPH_set_colors(2,1,0)
|
||||
cx16.GRAPH_clear()
|
||||
repeat 1000 {
|
||||
cx16.r0 = math.rndw() % 320
|
||||
cx16.r1 = math.rnd() % 240
|
||||
cx16.r2 = math.rndw() % 320
|
||||
cx16.r3 = math.rnd() % 240
|
||||
cx16.GRAPH_draw_line(cx16.r0, cx16.r1, cx16.r2, cx16.r3)
|
||||
}
|
||||
cx16.set_screen_mode(0)
|
||||
}
|
||||
|
||||
sub custom_mono() {
|
||||
monogfx.lores()
|
||||
repeat 1000 {
|
||||
cx16.r0 = math.rndw() % 320
|
||||
cx16.r1L = math.rnd() % 240
|
||||
cx16.r2 = math.rndw() % 320
|
||||
cx16.r3L = math.rnd() % 240
|
||||
line(cx16.r0, cx16.r1L, cx16.r2, cx16.r3L)
|
||||
}
|
||||
monogfx.textmode()
|
||||
}
|
||||
|
||||
sub custom_256() {
|
||||
gfx_lores.graphics_mode()
|
||||
repeat 1000 {
|
||||
cx16.r0 = math.rndw() % 320
|
||||
cx16.r1L = math.rnd() % 240
|
||||
cx16.r2 = math.rndw() % 320
|
||||
cx16.r3L = math.rnd() % 240
|
||||
gfx_lores.line(cx16.r0, cx16.r1L, cx16.r2, cx16.r3L, 2)
|
||||
}
|
||||
gfx_lores.text_mode()
|
||||
}
|
||||
|
||||
sub line(uword @zp x1, ubyte @zp y1, uword @zp x2, ubyte @zp y2) {
|
||||
; Bresenham algorithm.
|
||||
; This code special-cases various quadrant loops to allow simple ++ and -- operations.
|
||||
if y1>y2 {
|
||||
; make sure dy is always positive to have only 4 instead of 8 special cases
|
||||
cx16.r0 = x1
|
||||
x1 = x2
|
||||
x2 = cx16.r0
|
||||
cx16.r0L = y1
|
||||
y1 = y2
|
||||
y2 = cx16.r0L
|
||||
}
|
||||
word @zp dx = (x2 as word)-x1
|
||||
ubyte @zp dy = y2-y1
|
||||
|
||||
if dx==0 {
|
||||
monogfx.vertical_line(x1, y1, abs(dy) as uword +1, true)
|
||||
return
|
||||
}
|
||||
if dy==0 {
|
||||
if x1>x2
|
||||
x1=x2
|
||||
monogfx.horizontal_line(x1, y1, abs(dx) as uword +1, true)
|
||||
return
|
||||
}
|
||||
|
||||
cx16.r1L = 1 ;; true ; 'positive_ix'
|
||||
if dx < 0 {
|
||||
dx = -dx
|
||||
cx16.r1L = 0 ;; false
|
||||
}
|
||||
word @zp dx2 = dx*2
|
||||
word @zp dy2 = dy*2
|
||||
word @zp d = 0
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_H = 0
|
||||
if dx >= dy {
|
||||
if cx16.r1L!=0 {
|
||||
repeat {
|
||||
plot()
|
||||
if x1==x2
|
||||
return
|
||||
x1++
|
||||
d += dy2
|
||||
if d > dx {
|
||||
y1++
|
||||
d -= dx2
|
||||
}
|
||||
}
|
||||
} else {
|
||||
repeat {
|
||||
plot()
|
||||
if x1==x2
|
||||
return
|
||||
x1--
|
||||
d += dy2
|
||||
if d > dx {
|
||||
y1++
|
||||
d -= dx2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if cx16.r1L!=0 {
|
||||
repeat {
|
||||
plot()
|
||||
if y1==y2
|
||||
return
|
||||
y1++
|
||||
d += dx2
|
||||
if d > dy {
|
||||
x1++
|
||||
d -= dy2
|
||||
}
|
||||
}
|
||||
} else {
|
||||
repeat {
|
||||
plot()
|
||||
if y1==y2
|
||||
return
|
||||
y1++
|
||||
d += dx2
|
||||
if d > dy {
|
||||
x1--
|
||||
d -= dy2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asmsub plot() {
|
||||
%asm {{
|
||||
lda p8v_x1+1
|
||||
lsr a
|
||||
lda p8v_x1
|
||||
ror a
|
||||
lsr a
|
||||
lsr a
|
||||
|
||||
clc
|
||||
ldy p8v_y1
|
||||
adc times40_lo,y
|
||||
sta cx16.VERA_ADDR_L
|
||||
lda times40_mid,y
|
||||
adc #0
|
||||
sta cx16.VERA_ADDR_M
|
||||
|
||||
lda p8v_x1
|
||||
and #7
|
||||
tax
|
||||
lda maskbits,x
|
||||
tsb cx16.VERA_DATA0
|
||||
rts
|
||||
|
||||
maskbits .byte 128,64,32,16,8,4,2,1
|
||||
; multiplication by 40 lookup table
|
||||
times40 := 40*range(240)
|
||||
|
||||
times40_lo .byte <times40
|
||||
times40_mid .byte >times40
|
||||
|
||||
; !notreached!
|
||||
}}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user