implemented bit shifting for non-const amounts

This commit is contained in:
Irmen de Jong 2020-08-22 15:09:54 +02:00
parent 9d98746501
commit bfc8a26381
8 changed files with 326 additions and 160 deletions

View File

@ -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

View File

@ -1 +1 @@
3.2
3.3-SNAPSHOT

View File

@ -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)

View File

@ -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)

View File

@ -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")

View File

@ -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")

View File

@ -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,

View File

@ -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)
}
}
}