mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 08:29:25 +00:00
implemented bit shifting for non-const amounts
This commit is contained in:
parent
9d98746501
commit
bfc8a26381
@ -663,6 +663,33 @@ greatereq_w .proc
|
||||
.pend
|
||||
|
||||
|
||||
shiftleft_b .proc
|
||||
inx
|
||||
ldy c64.ESTACK_LO,x
|
||||
bne +
|
||||
rts
|
||||
+ lda c64.ESTACK_LO+1,x
|
||||
- asl a
|
||||
dey
|
||||
bne -
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
shiftright_b .proc
|
||||
inx
|
||||
ldy c64.ESTACK_LO,x
|
||||
bne +
|
||||
rts
|
||||
+ lda c64.ESTACK_LO+1,x
|
||||
- lsr a
|
||||
dey
|
||||
bne -
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
orig_stackpointer .byte 0 ; stores the Stack pointer register at program start
|
||||
|
||||
func_exit .proc
|
||||
|
@ -1 +1 @@
|
||||
3.2
|
||||
3.3-SNAPSHOT
|
||||
|
@ -771,12 +771,6 @@ internal class AstChecker(private val program: Program,
|
||||
if(leftDt !in IntegerDatatypes || rightDt !in IntegerDatatypes)
|
||||
errors.err("bitwise operator can only be used on integer operands", expr.right.position)
|
||||
}
|
||||
"<<", ">>" -> {
|
||||
// for now, bit-shifts can only shift by a constant number TODO remove this restriction
|
||||
val constRight = expr.right.constValue(program)
|
||||
if(constRight==null)
|
||||
errors.err("bit-shift can only be done by a constant number (for now)", expr.right.position)
|
||||
}
|
||||
}
|
||||
|
||||
if(leftDt !in NumericDatatypes)
|
||||
|
@ -336,8 +336,8 @@ open class Assignment(var target: AssignTarget, var value: Expression, override
|
||||
get() {
|
||||
val binExpr = value as? BinaryExpression
|
||||
if(binExpr!=null) {
|
||||
if(binExpr.right !is BinaryExpression && binExpr.left isSameAs target)
|
||||
return true // A = A <operator> v
|
||||
if(binExpr.left isSameAs target)
|
||||
return true // A = A <operator> Something
|
||||
|
||||
if(binExpr.operator in associativeOperators) {
|
||||
if (binExpr.left !is BinaryExpression && binExpr.right isSameAs target)
|
||||
|
@ -38,19 +38,18 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
|
||||
private fun inplaceBinary(target: AssignTarget, binExpr: BinaryExpression, assign: Assignment) {
|
||||
|
||||
if (binExpr.right !is BinaryExpression && binExpr.left isSameAs target) {
|
||||
// A = A <operator> 5
|
||||
if (binExpr.left isSameAs target) {
|
||||
// A = A <operator> Something
|
||||
return inplaceModification(target, binExpr.operator, binExpr.right, assign)
|
||||
}
|
||||
|
||||
if (binExpr.operator in associativeOperators) {
|
||||
val leftBinExpr = binExpr.left as? BinaryExpression
|
||||
if (leftBinExpr != null && binExpr.right isSameAs target) {
|
||||
if (binExpr.right isSameAs target) {
|
||||
// A = 5 <operator> A
|
||||
return inplaceModification(target, binExpr.operator, binExpr.left, assign)
|
||||
}
|
||||
|
||||
val leftBinExpr = binExpr.left as? BinaryExpression
|
||||
if (leftBinExpr?.operator == binExpr.operator) {
|
||||
// TODO better optimize the chained asm to avoid intermediate stores/loads?
|
||||
when {
|
||||
@ -128,8 +127,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
when {
|
||||
valueLv != null -> inplaceModification_word_litval_to_variable(name, operator, valueLv.toInt())
|
||||
ident != null -> inplaceModification_word_variable_to_variable(name, operator, ident)
|
||||
valueLv != null -> inplaceModification_word_litval_to_variable(name, dt, operator, valueLv.toInt())
|
||||
ident != null -> inplaceModification_word_variable_to_variable(name, dt, operator, ident)
|
||||
// TODO more specialized code for types such as memory read etc.
|
||||
// value is DirectMemoryRead -> {
|
||||
// println("warning: slow stack evaluation used (8): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
||||
@ -145,9 +144,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// }
|
||||
value is TypecastExpression -> {
|
||||
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
|
||||
inplaceModification_word_value_to_variable(name, operator, value)
|
||||
inplaceModification_word_value_to_variable(name, dt, operator, value)
|
||||
}
|
||||
else -> inplaceModification_word_value_to_variable(name, operator, value)
|
||||
else -> inplaceModification_word_value_to_variable(name, dt, operator, value)
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
@ -226,7 +225,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
val childDt = value.expression.inferType(program).typeOrElse(DataType.STRUCT)
|
||||
if (value.type.equalsSize(childDt) || value.type.largerThan(childDt)) {
|
||||
// this typecast is redundant here; the rest of the code knows how to deal with the uncasted value.
|
||||
println("***(test) removing redundant typecast ${value.position} $childDt") // TODO
|
||||
inplaceModification(target, operator, value.expression, origAssign)
|
||||
return true
|
||||
}
|
||||
@ -269,9 +267,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
ldx ${C64Zeropage.SCRATCH_REG_X}
|
||||
""")
|
||||
}
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> {
|
||||
TODO()
|
||||
TODO("div")
|
||||
// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
}
|
||||
"%" -> {
|
||||
@ -331,11 +329,11 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
ldx ${C64Zeropage.SCRATCH_REG_X}
|
||||
""")
|
||||
}
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> {
|
||||
if (value == 0.0)
|
||||
throw AssemblyError("division by zero")
|
||||
TODO()
|
||||
TODO("div")
|
||||
// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
}
|
||||
"%" -> {
|
||||
@ -370,16 +368,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
loadByteFromPointerIntoA()
|
||||
asmgen.out(" sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y")
|
||||
}
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("byte remainder")
|
||||
// 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")
|
||||
}
|
||||
"<<" -> TODO("byte asl")
|
||||
">>" -> TODO("byte lsr")
|
||||
"<<" -> TODO("ubyte asl")
|
||||
">>" -> TODO("ubyte lsr")
|
||||
"&" -> {
|
||||
loadByteFromPointerIntoA()
|
||||
asmgen.out(" and $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y")
|
||||
@ -418,16 +416,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
loadByteFromPointerIntoA()
|
||||
asmgen.out(" sec | sbc $otherName | sta (${C64Zeropage.SCRATCH_W1}),y")
|
||||
}
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("byte remainder")
|
||||
// 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")
|
||||
}
|
||||
"<<" -> TODO("byte asl")
|
||||
">>" -> TODO("byte lsr")
|
||||
"<<" -> TODO("ubyte asl")
|
||||
">>" -> TODO("ubyte lsr")
|
||||
"&" -> {
|
||||
loadByteFromPointerIntoA()
|
||||
asmgen.out(" and $otherName | sta (${C64Zeropage.SCRATCH_W1}),y")
|
||||
@ -464,8 +462,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
loadByteFromPointerInA()
|
||||
asmgen.out(" sec | sbc #$value | sta (${C64Zeropage.SCRATCH_W1}),y")
|
||||
}
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("byte remainder")
|
||||
// if(types==DataType.BYTE)
|
||||
@ -473,16 +471,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// asmgen.out(" jsr prog8_lib.remainder_ub")
|
||||
}
|
||||
"<<" -> {
|
||||
if (value > 1) {
|
||||
if (value > 0) {
|
||||
loadByteFromPointerInA()
|
||||
repeat(value.toInt()) { asmgen.out(" asl a") }
|
||||
repeat(value) { asmgen.out(" asl a") }
|
||||
asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y")
|
||||
}
|
||||
}
|
||||
">>" -> {
|
||||
if (value > 1) {
|
||||
if (value > 0) {
|
||||
loadByteFromPointerInA()
|
||||
repeat(value.toInt()) { asmgen.out(" lsr a") }
|
||||
repeat(value) { asmgen.out(" lsr a") }
|
||||
asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y")
|
||||
}
|
||||
}
|
||||
@ -502,7 +500,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
private fun inplaceModification_word_litval_to_variable(name: String, operator: String, value: Int) {
|
||||
private fun inplaceModification_word_litval_to_variable(name: String, dt: DataType, operator: String, value: Int) {
|
||||
when (operator) {
|
||||
// note: ** (power) operator requires floats.
|
||||
// TODO use the + and - optimizations in the expression asm code as well.
|
||||
@ -577,17 +575,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// asmgen.out(" jsr prog8_lib.remainder_ub")
|
||||
}
|
||||
"<<" -> {
|
||||
if (value > 1) {
|
||||
asmgen.out(" lda $name")
|
||||
TODO("word asl")
|
||||
asmgen.out(" sta $name")
|
||||
}
|
||||
repeat(value) { asmgen.out(" asl $name | rol $name+1") }
|
||||
}
|
||||
">>" -> {
|
||||
if (value > 1) {
|
||||
asmgen.out(" lda $name")
|
||||
TODO("word lsr")
|
||||
asmgen.out(" sta $name")
|
||||
if (value > 0) {
|
||||
if(dt==DataType.UWORD) {
|
||||
repeat(value) { asmgen.out(" lsr $name+1 | ror $name")}
|
||||
} else {
|
||||
repeat(value) { asmgen.out(" lda $name+1 | asl a | ror $name+1 | ror $name") }
|
||||
}
|
||||
}
|
||||
}
|
||||
"&" -> {
|
||||
@ -615,7 +611,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
private fun inplaceModification_word_variable_to_variable(name: String, operator: String, ident: IdentifierReference) {
|
||||
private fun inplaceModification_word_variable_to_variable(name: String, dt: DataType, operator: String, ident: IdentifierReference) {
|
||||
val otherName = asmgen.asmIdentifierName(ident)
|
||||
val valueDt = ident.targetVarDecl(program.namespace)!!.datatype
|
||||
when (valueDt) {
|
||||
@ -639,14 +635,39 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
bcs +
|
||||
dec $name+1
|
||||
+ """)
|
||||
"*" -> TODO()
|
||||
"/" -> TODO()
|
||||
"*" -> TODO("mul")
|
||||
"/" -> TODO("div")
|
||||
"%" -> TODO("word remainder")
|
||||
"<<" -> TODO()
|
||||
">>" -> TODO()
|
||||
"&" -> TODO()
|
||||
"^" -> TODO()
|
||||
"|" -> TODO()
|
||||
"<<" -> {
|
||||
asmgen.out("""
|
||||
ldy $otherName
|
||||
- asl $name
|
||||
rol $name+1
|
||||
dey
|
||||
bne -""")
|
||||
}
|
||||
">>" -> {
|
||||
if(dt==DataType.UWORD) {
|
||||
asmgen.out("""
|
||||
ldy $otherName
|
||||
- lsr $name+1
|
||||
ror $name
|
||||
dey
|
||||
bne -""")
|
||||
} else {
|
||||
asmgen.out("""
|
||||
ldy $otherName
|
||||
- lda $name+1
|
||||
asl a
|
||||
ror $name+1
|
||||
ror $name
|
||||
dey
|
||||
bne -""")
|
||||
}
|
||||
}
|
||||
"&" -> TODO("bitand")
|
||||
"^" -> TODO("bitxor")
|
||||
"|" -> TODO("bitor")
|
||||
else -> throw AssemblyError("invalid operator for in-place modification $operator")
|
||||
}
|
||||
}
|
||||
@ -656,16 +677,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// note: ** (power) operator requires floats.
|
||||
"+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name | lda $name+1 | adc $otherName+1 | sta $name+1")
|
||||
"-" -> asmgen.out(" lda $name | sec | sbc $otherName | sta $name | lda $name+1 | sbc $otherName+1 | sta $name+1")
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("word remainder")
|
||||
// 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")
|
||||
}
|
||||
"<<" -> TODO()
|
||||
">>" -> TODO()
|
||||
"<<", ">>" -> throw AssemblyError("shift by a word value not supported, max is a byte")
|
||||
"&" -> asmgen.out(" lda $name | and $otherName | sta $name | lda $name+1 | and $otherName+1 | sta $name+1")
|
||||
"^" -> asmgen.out(" lda $name | xor $otherName | sta $name | lda $name+1 | xor $otherName+1 | sta $name+1")
|
||||
"|" -> asmgen.out(" lda $name | ora $otherName | sta $name | lda $name+1 | ora $otherName+1 | sta $name+1")
|
||||
@ -678,7 +698,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
private fun inplaceModification_word_value_to_variable(name: String, operator: String, value: Expression) {
|
||||
private fun inplaceModification_word_value_to_variable(name: String, dt: DataType, operator: String, value: Expression) {
|
||||
// this should be the last resort for code generation for this,
|
||||
// because the value is evaluated onto the eval stack (=slow).
|
||||
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
||||
@ -706,14 +726,50 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
bcs +
|
||||
dec $name+1
|
||||
+ """)
|
||||
"*" -> TODO()
|
||||
"/" -> TODO()
|
||||
"*" -> TODO("mul")
|
||||
"/" -> TODO("div")
|
||||
"%" -> TODO("word remainder")
|
||||
"<<" -> TODO()
|
||||
">>" -> TODO()
|
||||
"&" -> TODO()
|
||||
"^" -> TODO()
|
||||
"|" -> TODO()
|
||||
"<<" -> {
|
||||
asmgen.translateExpression(value)
|
||||
asmgen.out("""
|
||||
inx
|
||||
ldy c64.ESTACK_LO,x
|
||||
beq +
|
||||
- asl $name
|
||||
rol $name+1
|
||||
dey
|
||||
bne -
|
||||
+""")
|
||||
}
|
||||
">>" -> {
|
||||
asmgen.translateExpression(value)
|
||||
if(dt==DataType.UWORD) {
|
||||
asmgen.out("""
|
||||
inx
|
||||
ldy c64.ESTACK_LO,x
|
||||
beq +
|
||||
- lsr $name+1
|
||||
ror $name
|
||||
dey
|
||||
bne -
|
||||
+""") }
|
||||
else {
|
||||
asmgen.out("""
|
||||
inx
|
||||
ldy c64.ESTACK_LO,x
|
||||
beq +
|
||||
- lda $name+1
|
||||
asl a
|
||||
ror $name+1
|
||||
ror $name
|
||||
dey
|
||||
bne -
|
||||
+""")
|
||||
}
|
||||
}
|
||||
"&" -> TODO("bitand")
|
||||
"^" -> TODO("bitxor")
|
||||
"|" -> TODO("bitor")
|
||||
else -> throw AssemblyError("invalid operator for in-place modification $operator")
|
||||
}
|
||||
}
|
||||
@ -723,16 +779,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// note: ** (power) operator requires floats.
|
||||
"+" -> asmgen.out(" lda $name | clc | adc $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | adc $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
|
||||
"-" -> asmgen.out(" lda $name | sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | sbc $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("word remainder")
|
||||
// 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")
|
||||
}
|
||||
"<<" -> TODO()
|
||||
">>" -> TODO()
|
||||
"<<", ">>" -> throw AssemblyError("shift by a word value not supported, max is a byte")
|
||||
"&" -> asmgen.out(" lda $name | and $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | and $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
|
||||
"^" -> asmgen.out(" lda $name | xor $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | xor $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
|
||||
"|" -> asmgen.out(" lda $name | ora $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | ora $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
|
||||
@ -756,16 +811,49 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// note: ** (power) operator requires floats.
|
||||
"+" -> asmgen.out(" lda $name | clc | adc $ESTACK_LO_PLUS1_HEX,x | sta $name")
|
||||
"-" -> asmgen.out(" lda $name | sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta $name")
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("byte remainder")
|
||||
// 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")
|
||||
}
|
||||
"<<" -> TODO()
|
||||
">>" -> TODO()
|
||||
"<<" -> {
|
||||
asmgen.translateExpression(value)
|
||||
asmgen.out("""
|
||||
inx
|
||||
ldy c64.ESTACK_LO,x
|
||||
beq +
|
||||
- asl $name
|
||||
dey
|
||||
bne -
|
||||
+""")
|
||||
}
|
||||
">>" -> {
|
||||
asmgen.translateExpression(value)
|
||||
if(dt==DataType.UBYTE) {
|
||||
asmgen.out("""
|
||||
inx
|
||||
ldy c64.ESTACK_LO,x
|
||||
beq +
|
||||
- lsr $name
|
||||
dey
|
||||
bne -
|
||||
+""")
|
||||
} else {
|
||||
asmgen.out("""
|
||||
inx
|
||||
ldy c64.ESTACK_LO,x
|
||||
beq +
|
||||
- lda $name
|
||||
asl a
|
||||
ror $name
|
||||
dey
|
||||
bne -
|
||||
+""")
|
||||
}
|
||||
}
|
||||
"&" -> asmgen.out(" lda $name | and $ESTACK_LO_PLUS1_HEX,x | sta $name")
|
||||
"^" -> asmgen.out(" lda $name | xor $ESTACK_LO_PLUS1_HEX,x | sta $name")
|
||||
"|" -> asmgen.out(" lda $name | ora $ESTACK_LO_PLUS1_HEX,x | sta $name")
|
||||
@ -780,16 +868,38 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// note: ** (power) operator requires floats.
|
||||
"+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name")
|
||||
"-" -> asmgen.out(" lda $name | sec | sbc $otherName | sta $name")
|
||||
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("byte remainder")
|
||||
// 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")
|
||||
}
|
||||
"<<" -> TODO()
|
||||
">>" -> TODO()
|
||||
"<<" -> {
|
||||
asmgen.out("""
|
||||
ldy $otherName
|
||||
- asl $name
|
||||
dey
|
||||
bne -""")
|
||||
}
|
||||
">>" -> {
|
||||
if(dt==DataType.UBYTE) {
|
||||
asmgen.out("""
|
||||
ldy $otherName
|
||||
- lsr $name
|
||||
dey
|
||||
bne -""")
|
||||
} else {
|
||||
asmgen.out("""
|
||||
ldy $otherName
|
||||
- lda $name
|
||||
asl a
|
||||
ror $name
|
||||
dey
|
||||
bne -""")
|
||||
}
|
||||
}
|
||||
"&" -> asmgen.out(" lda $name | and $otherName | sta $name")
|
||||
"^" -> asmgen.out(" lda $name | xor $otherName | sta $name")
|
||||
"|" -> asmgen.out(" lda $name | ora $otherName | sta $name")
|
||||
@ -828,17 +938,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// asmgen.out(" jsr prog8_lib.remainder_ub")
|
||||
}
|
||||
"<<" -> {
|
||||
if (value > 1) {
|
||||
asmgen.out(" lda $name")
|
||||
repeat(value.toInt()) { asmgen.out(" asl a") }
|
||||
asmgen.out(" sta $name")
|
||||
}
|
||||
repeat(value) { asmgen.out(" asl $name") }
|
||||
}
|
||||
">>" -> {
|
||||
if (value > 1) {
|
||||
asmgen.out(" lda $name")
|
||||
repeat(value.toInt()) { asmgen.out(" lsr a") }
|
||||
asmgen.out(" sta $name")
|
||||
if(value>0) {
|
||||
if (dt == DataType.UBYTE) {
|
||||
repeat(value) { asmgen.out(" lsr $name") }
|
||||
} else {
|
||||
repeat(value) { asmgen.out(" lda $name | asl a | ror $name") }
|
||||
}
|
||||
}
|
||||
}
|
||||
"&" -> asmgen.out(" lda $name | and #$value | sta $name")
|
||||
|
@ -207,79 +207,78 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
// see if we can apply some optimized routines
|
||||
when(expr.operator) {
|
||||
">>" -> {
|
||||
// bit-shifts are always by a constant number (for now)
|
||||
translateExpression(expr.left)
|
||||
val amount = expr.right.constValue(program)!!.number.toInt()
|
||||
when (leftDt) {
|
||||
DataType.UBYTE -> {
|
||||
if(amount<=2)
|
||||
repeat(amount) { asmgen.out(" lsr $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else {
|
||||
asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x")
|
||||
repeat(amount) { asmgen.out(" lsr a") }
|
||||
asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x")
|
||||
val amount = expr.right.constValue(program)?.number?.toInt()
|
||||
if(amount!=null) {
|
||||
when (leftDt) {
|
||||
DataType.UBYTE -> {
|
||||
if (amount <= 2)
|
||||
repeat(amount) { asmgen.out(" lsr $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else {
|
||||
asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x")
|
||||
repeat(amount) { asmgen.out(" lsr a") }
|
||||
asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x")
|
||||
}
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
if(amount<=2)
|
||||
repeat(amount) { asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | asl a | ror $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else {
|
||||
asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | sta ${C64MachineDefinition.C64Zeropage.SCRATCH_B1}")
|
||||
repeat(amount) { asmgen.out(" asl a | ror ${C64MachineDefinition.C64Zeropage.SCRATCH_B1} | lda ${C64MachineDefinition.C64Zeropage.SCRATCH_B1}") }
|
||||
asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x")
|
||||
DataType.BYTE -> {
|
||||
if (amount <= 2)
|
||||
repeat(amount) { asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | asl a | ror $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else {
|
||||
asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | sta ${C64MachineDefinition.C64Zeropage.SCRATCH_B1}")
|
||||
repeat(amount) { asmgen.out(" asl a | ror ${C64MachineDefinition.C64Zeropage.SCRATCH_B1} | lda ${C64MachineDefinition.C64Zeropage.SCRATCH_B1}") }
|
||||
asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x")
|
||||
}
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
var left = amount
|
||||
while(left>=7) {
|
||||
asmgen.out(" jsr math.shift_right_uw_7")
|
||||
left -= 7
|
||||
DataType.UWORD -> {
|
||||
var left = amount
|
||||
while (left >= 7) {
|
||||
asmgen.out(" jsr math.shift_right_uw_7")
|
||||
left -= 7
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" lsr $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_right_uw_$left")
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" lsr $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_right_uw_$left")
|
||||
}
|
||||
DataType.WORD -> {
|
||||
var left = amount
|
||||
while(left>=7) {
|
||||
asmgen.out(" jsr math.shift_right_w_7")
|
||||
left -= 7
|
||||
DataType.WORD -> {
|
||||
var left = amount
|
||||
while (left >= 7) {
|
||||
asmgen.out(" jsr math.shift_right_w_7")
|
||||
left -= 7
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" lda $ESTACK_HI_PLUS1_HEX,x | asl a | ror $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_right_w_$left")
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" lda $ESTACK_HI_PLUS1_HEX,x | asl a | ror $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_right_w_$left")
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
return
|
||||
}
|
||||
"<<" -> {
|
||||
// bit-shifts are always by a constant number (for now)
|
||||
translateExpression(expr.left)
|
||||
val amount = expr.right.constValue(program)!!.number.toInt()
|
||||
if (leftDt in ByteDatatypes) {
|
||||
if(amount<=2)
|
||||
repeat(amount) { asmgen.out(" asl $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else {
|
||||
asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x")
|
||||
repeat(amount) { asmgen.out(" asl a") }
|
||||
asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x")
|
||||
val amount = expr.right.constValue(program)?.number?.toInt()
|
||||
if(amount!=null) {
|
||||
if (leftDt in ByteDatatypes) {
|
||||
if (amount <= 2)
|
||||
repeat(amount) { asmgen.out(" asl $ESTACK_LO_PLUS1_HEX,x") }
|
||||
else {
|
||||
asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x")
|
||||
repeat(amount) { asmgen.out(" asl a") }
|
||||
asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x")
|
||||
}
|
||||
} else {
|
||||
var left = amount
|
||||
while (left >= 7) {
|
||||
asmgen.out(" jsr math.shift_left_w_7")
|
||||
left -= 7
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" asl $ESTACK_LO_PLUS1_HEX,x | rol $ESTACK_HI_PLUS1_HEX,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_left_w_$left")
|
||||
}
|
||||
}
|
||||
else {
|
||||
var left=amount
|
||||
while(left>=7) {
|
||||
asmgen.out(" jsr math.shift_left_w_7")
|
||||
left -= 7
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" asl $ESTACK_LO_PLUS1_HEX,x | rol $ESTACK_HI_PLUS1_HEX,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_left_w_$left")
|
||||
}
|
||||
return
|
||||
}
|
||||
"*" -> {
|
||||
val value = expr.right.constValue(program)
|
||||
@ -433,7 +432,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
inx
|
||||
sta $ESTACK_LO_PLUS1_HEX,x
|
||||
""")
|
||||
"<<", ">>" -> throw AssemblyError("bit-shifts not via stack")
|
||||
"<<" -> 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")
|
||||
|
@ -766,16 +766,6 @@ rndw()
|
||||
rndf()
|
||||
returns a pseudo-random float between 0.0 and 1.0
|
||||
|
||||
lsl(x)
|
||||
Shift the bits in x (byte or word) one position to the left.
|
||||
Bit 0 is set to 0 (and the highest bit is shifted into the status register's Carry flag)
|
||||
Modifies in-place, doesn't return a value (so can't be used in an expression).
|
||||
|
||||
lsr(x)
|
||||
Shift the bits in x (byte or word) one position to the right.
|
||||
The highest bit is set to 0 (and bit 0 is shifted into the status register's Carry flag)
|
||||
Modifies in-place, doesn't return a value (so can't be used in an expression).
|
||||
|
||||
rol(x)
|
||||
Rotate the bits in x (byte or word) one position to the left.
|
||||
This uses the CPU's rotate semantics: bit 0 will be set to the current value of the Carry flag,
|
||||
|
@ -5,7 +5,54 @@
|
||||
|
||||
main {
|
||||
|
||||
; todo make it possible to use cpu opcodes as varnames such as 'nop'
|
||||
|
||||
sub start() {
|
||||
|
||||
byte ub
|
||||
word uw
|
||||
ubyte x = 1
|
||||
ubyte z = 0
|
||||
|
||||
ubyte[] array = [1,2,3]
|
||||
|
||||
ubyte i
|
||||
ub = %00100001
|
||||
for i in 0 to 9 {
|
||||
c64scr.print_ubbin(ub as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
;ub <<= 1
|
||||
;ub <<= x
|
||||
ub <<= (z+1)
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
;ub = %11000110 ; -123
|
||||
ub = -123
|
||||
for i in 0 to 9 {
|
||||
c64scr.print_ubbin(ub as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
;ub >>= 1
|
||||
;ub >>= x
|
||||
ub >>= (z+1)
|
||||
}
|
||||
|
||||
uw = %0011100000000011
|
||||
for i in 0 to 17 {
|
||||
c64scr.print_uwbin(uw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
;uw <<= 1
|
||||
;uw <<= x
|
||||
uw <<= (z+1)
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
uw = -12345
|
||||
;uw = %1110000011000100
|
||||
for i in 0 to 17 {
|
||||
c64scr.print_uwbin(uw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
;uw >>= 1
|
||||
;uw >>= x
|
||||
uw >>= (z+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user