fixed rol(),rol2(),ror(),ror2()

This commit is contained in:
Irmen de Jong 2024-01-16 20:41:53 +01:00
parent 9e33b8b8da
commit 504d1440cc
11 changed files with 988 additions and 124 deletions

View File

@ -471,7 +471,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
DataType.UBYTE -> {
when (what) {
is PtArrayIndexer -> {
if(!what.index.isSimple()) asmgen.out(" php") // save Carry
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
if(!what.index.isSimple()) asmgen.out(" plp")
val varname = asmgen.asmVariableName(what.variable)
asmgen.out(" ror ${varname},x")
}
@ -482,15 +484,19 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
} else {
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address)
if(ptrAndIndex!=null) {
asmgen.out(" php")
asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.A)
asmgen.saveRegisterStack(CpuRegister.A, true)
asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
asmgen.restoreRegisterStack(CpuRegister.X, false)
asmgen.out("""
plp
+ ror ${'$'}ffff,x ; modified""")
} else {
if(!what.address.isSimple()) asmgen.out(" php") // save Carry
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
if(!what.address.isSimple()) asmgen.out(" plp")
asmgen.out("""
sta (+) + 1
sty (+) + 2
@ -508,7 +514,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
DataType.UWORD -> {
when (what) {
is PtArrayIndexer -> {
if(!what.index.isSimple()) asmgen.out(" php") // save Carry
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
if(!what.index.isSimple()) asmgen.out(" plp")
val varname = asmgen.asmVariableName(what.variable)
if(what.splitWords)
asmgen.out(" ror ${varname}_msb,x | ror ${varname}_lsb,x")
@ -579,7 +587,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
DataType.UBYTE -> {
when (what) {
is PtArrayIndexer -> {
if(!what.index.isSimple()) asmgen.out(" php") // save Carry
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
if(!what.index.isSimple()) asmgen.out(" plp")
val varname = asmgen.asmVariableName(what.variable)
asmgen.out(" rol ${varname},x")
}
@ -590,15 +600,19 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
} else {
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address)
if(ptrAndIndex!=null) {
asmgen.out(" php")
asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.A)
asmgen.saveRegisterStack(CpuRegister.A, true)
asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
asmgen.restoreRegisterStack(CpuRegister.X, false)
asmgen.out("""
plp
+ rol ${'$'}ffff,x ; modified""")
} else {
if(!what.address.isSimple()) asmgen.out(" php") // save Carry
asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY)
if(!what.address.isSimple()) asmgen.out(" plp")
asmgen.out("""
sta (+) + 1
sty (+) + 2
@ -616,7 +630,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
DataType.UWORD -> {
when (what) {
is PtArrayIndexer -> {
if(!what.index.isSimple()) asmgen.out(" php") // save Carry
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
if(!what.index.isSimple()) asmgen.out(" plp")
val varname = asmgen.asmVariableName(what.variable)
if(what.splitWords)
asmgen.out(" rol ${varname}_lsb,x | rol ${varname}_msb,x")

View File

@ -50,25 +50,26 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
assignment: PtAugmentedAssign
): IRCodeChunks {
val value = assignment.value
val vmDt = irType(value.type)
val targetDt = irType(assignment.target.type)
val signed = assignment.target.type in SignedDatatypes
return when(assignment.operator) {
"+=" -> expressionEval.operatorPlusInplace(address, null, vmDt, value)
"-=" -> expressionEval.operatorMinusInplace(address, null, vmDt, value)
"*=" -> expressionEval.operatorMultiplyInplace(address, null, vmDt, value)
"/=" -> expressionEval.operatorDivideInplace(address, null, vmDt, value.type in SignedDatatypes, value)
"|=" -> expressionEval.operatorOrInplace(address, null, vmDt, value)
"&=" -> expressionEval.operatorAndInplace(address, null, vmDt, value)
"^=" -> expressionEval.operatorXorInplace(address, null, vmDt, value)
"<<=" -> expressionEval.operatorShiftLeftInplace(address, null, vmDt, value)
">>=" -> expressionEval.operatorShiftRightInplace(address, null, vmDt, value.type in SignedDatatypes, value)
"%=" -> expressionEval.operatorModuloInplace(address, null, vmDt, value)
"==" -> expressionEval.operatorEqualsInplace(address, null, vmDt, value)
"!=" -> expressionEval.operatorNotEqualsInplace(address, null, vmDt, value)
"<" -> expressionEval.operatorLessInplace(address, null, vmDt, value.type in SignedDatatypes, value)
">" -> expressionEval.operatorGreaterInplace(address, null, vmDt, value.type in SignedDatatypes, value)
"<=" -> expressionEval.operatorLessEqualInplace(address, null, vmDt, value.type in SignedDatatypes, value)
">=" -> expressionEval.operatorGreaterEqualInplace(address, null, vmDt, value.type in SignedDatatypes, value)
in PrefixOperators -> inplacePrefix(assignment.operator, vmDt, address, null)
"+=" -> expressionEval.operatorPlusInplace(address, null, targetDt, value)
"-=" -> expressionEval.operatorMinusInplace(address, null, targetDt, value)
"*=" -> expressionEval.operatorMultiplyInplace(address, null, targetDt, value)
"/=" -> expressionEval.operatorDivideInplace(address, null, targetDt, signed, value)
"|=" -> expressionEval.operatorOrInplace(address, null, targetDt, value)
"&=" -> expressionEval.operatorAndInplace(address, null, targetDt, value)
"^=" -> expressionEval.operatorXorInplace(address, null, targetDt, value)
"<<=" -> expressionEval.operatorShiftLeftInplace(address, null, targetDt, value)
">>=" -> expressionEval.operatorShiftRightInplace(address, null, targetDt, signed, value)
"%=" -> expressionEval.operatorModuloInplace(address, null, targetDt, value)
"==" -> expressionEval.operatorEqualsInplace(address, null, targetDt, value)
"!=" -> expressionEval.operatorNotEqualsInplace(address, null, targetDt, value)
"<" -> expressionEval.operatorLessInplace(address, null, targetDt, signed, value)
">" -> expressionEval.operatorGreaterInplace(address, null, targetDt, signed, value)
"<=" -> expressionEval.operatorLessEqualInplace(address, null, targetDt, signed, value)
">=" -> expressionEval.operatorGreaterEqualInplace(address, null, targetDt, signed, value)
in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, address, null)
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
}
@ -76,26 +77,27 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
private fun assignVarAugmented(symbol: String, assignment: PtAugmentedAssign): IRCodeChunks {
val value = assignment.value
val signed = assignment.target.type in SignedDatatypes
val targetDt = irType(assignment.target.type)
return when (assignment.operator) {
return when(assignment.operator) {
"+=" -> expressionEval.operatorPlusInplace(null, symbol, targetDt, value)
"-=" -> expressionEval.operatorMinusInplace(null, symbol, targetDt, value)
"*=" -> expressionEval.operatorMultiplyInplace(null, symbol, targetDt, value)
"/=" -> expressionEval.operatorDivideInplace(null, symbol, targetDt, value.type in SignedDatatypes, value)
"/=" -> expressionEval.operatorDivideInplace(null, symbol, targetDt, signed, value)
"|=" -> expressionEval.operatorOrInplace(null, symbol, targetDt, value)
"or=" -> expressionEval.operatorLogicalOrInplace(null, symbol, targetDt, value)
"&=" -> expressionEval.operatorAndInplace(null, symbol, targetDt, value)
"and=" -> expressionEval.operatorLogicalAndInplace(null, symbol, targetDt, value)
"^=", "xor=" -> expressionEval.operatorXorInplace(null, symbol, targetDt, value)
"<<=" -> expressionEval.operatorShiftLeftInplace(null, symbol, targetDt, value)
">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, targetDt, value.type in SignedDatatypes, value)
">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, targetDt, signed, value)
"%=" -> expressionEval.operatorModuloInplace(null, symbol, targetDt, value)
"==" -> expressionEval.operatorEqualsInplace(null, symbol, targetDt, value)
"!=" -> expressionEval.operatorNotEqualsInplace(null, symbol, targetDt, value)
"<" -> expressionEval.operatorLessInplace(null, symbol, targetDt, value.type in SignedDatatypes, value)
">" -> expressionEval.operatorGreaterInplace(null, symbol, targetDt, value.type in SignedDatatypes, value)
"<=" -> expressionEval.operatorLessEqualInplace(null, symbol, targetDt, value.type in SignedDatatypes, value)
">=" -> expressionEval.operatorGreaterEqualInplace(null, symbol, targetDt, value.type in SignedDatatypes, value)
"<" -> expressionEval.operatorLessInplace(null, symbol, targetDt, signed, value)
">" -> expressionEval.operatorGreaterInplace(null, symbol, targetDt, signed, value)
"<=" -> expressionEval.operatorLessEqualInplace(null, symbol, targetDt, signed, value)
">=" -> expressionEval.operatorGreaterEqualInplace(null, symbol, targetDt, signed, value)
in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, null, symbol)
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
}
@ -104,11 +106,11 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
val value: PtExpression
if(origAssign.operator in PrefixOperators) {
value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position)
value = PtPrefix(origAssign.operator, origAssign.target.type, origAssign.value.position)
value.add(origAssign.value)
} else {
require(origAssign.operator.endsWith('='))
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.target.type, origAssign.value.position)
val left: PtExpression = origAssign.target.children.single() as PtExpression
value.add(left)
value.add(origAssign.value)

View File

@ -623,22 +623,28 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val tr = exprGen.translateExpression(call.args.single())
addToResult(result, tr, tr.resultReg, -1)
val resultReg = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = resultReg, reg2 = tr.resultReg)
}
addInstr(result, IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = resultReg, reg2 = tr.resultReg), null)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall): ExpressionCodeResult {
// TODO optimize this to use the other ROL/ROR instructions too to always load into a temp reg
val vmDt = irType(call.args[0].type)
val result = mutableListOf<IRCodeChunkBase>()
val saveCarry = opcode in OpcodesThatDependOnCarry && !call.args[0].isSimple()
if(saveCarry)
addInstr(result, IRInstruction(Opcode.PUSHST), null) // save Carry
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(opcode, vmDt, reg1 = tr.resultReg)
}
if(saveCarry)
addInstr(result, IRInstruction(Opcode.POPST), null)
addInstr(result, IRInstruction(opcode, vmDt, reg1 = tr.resultReg), null)
if(saveCarry)
addInstr(result, IRInstruction(Opcode.PUSHST), null) // save Carry
result += assignRegisterTo(call.args[0], tr.resultReg)
if(saveCarry)
addInstr(result, IRInstruction(Opcode.POPST), null)
return ExpressionCodeResult(result, vmDt, -1, -1)
}

View File

@ -0,0 +1,865 @@
%import textio
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
unsigned()
signed()
}
ubyte[2] ubarray
uword[2] uwarray
byte[2] barray
word[2] warray
sub value_and_carry(ubyte value) -> ubyte {
sys.set_carry()
return value
}
sub unsigned() {
txt.print("rol_ub\n")
test_rol_ub(%00000000, false, %00000000, false)
test_rol_ub(%00000000, true, %00000001, false)
test_rol_ub(%01000000, false, %10000000, false)
test_rol_ub(%01000000, true, %10000001, false)
test_rol_ub(%10000000, false, %00000000, true)
test_rol_ub(%10000000, true, %00000001, true)
txt.print("ror_ub\n")
test_ror_ub(%00000000, false, %00000000, false)
test_ror_ub(%00000000, true, %10000000, false)
test_ror_ub(%01000000, false, %00100000, false)
test_ror_ub(%01000000, true, %10100000, false)
test_ror_ub(%00000001, false, %00000000, true)
test_ror_ub(%00000001, true, %10000000, true)
txt.print("rol2_ub\n")
test_rol2_ub(%00000000, %00000000)
test_rol2_ub(%01000001, %10000010)
test_rol2_ub(%10000010, %00000101)
test_rol2_ub(%11111110, %11111101)
txt.print("ror2_ub\n")
test_ror2_ub(%00000000, %00000000)
test_ror2_ub(%01000001, %10100000)
test_ror2_ub(%10000010, %01000001)
test_ror2_ub(%11111110, %01111111)
txt.print("rol_uw\n")
test_rol_uw(%0000000010000000, false, %0000000100000000, false)
test_rol_uw(%0000000010000000, true, %0000000100000001, false)
test_rol_uw(%0100000010000000, false, %1000000100000000, false)
test_rol_uw(%0100000010000000, true, %1000000100000001, false)
test_rol_uw(%1000000010000000, false, %0000000100000000, true)
test_rol_uw(%1000000010000000, true, %0000000100000001, true)
txt.print("ror_uw\n")
test_ror_uw(%0000000100000000, false, %0000000010000000, false)
test_ror_uw(%0000000100000000, true, %1000000010000000, false)
test_ror_uw(%0100000100000000, false, %0010000010000000, false)
test_ror_uw(%0100000100000000, true, %1010000010000000, false)
test_ror_uw(%0000000100000001, false, %0000000010000000, true)
test_ror_uw(%0000000100000001, true, %1000000010000000, true)
txt.print("rol2_uw\n")
test_rol2_uw(%0000000010000000, %0000000100000000)
test_rol2_uw(%0100000110000000, %1000001100000000)
test_rol2_uw(%1000001010000000, %0000010100000001)
test_rol2_uw(%1111111010000000, %1111110100000001)
txt.print("ror2_uw\n")
test_ror2_uw(%0000000100000000, %0000000010000000)
test_ror2_uw(%0100000100000000, %0010000010000000)
test_ror2_uw(%1000001100000001, %1100000110000000)
test_ror2_uw(%1111111100000011, %1111111110000001)
txt.print("<< ub\n")
test_shiftl_ub(%00000000, %00000000, false)
test_shiftl_ub(%00000001, %00000010, false)
test_shiftl_ub(%01000000, %10000000, false)
test_shiftl_ub(%10000000, %00000000, true)
txt.print(">> ub\n")
test_shiftr_ub(%00000000, %00000000, false)
test_shiftr_ub(%00000001, %00000000, true)
test_shiftr_ub(%10000000, %01000000, false)
test_shiftr_ub(%10000001, %01000000, true)
txt.print("<< uw\n")
test_shiftl_uw(%0000000000000000, %0000000000000000, false)
test_shiftl_uw(%0000000000000001, %0000000000000010, false)
test_shiftl_uw(%0000000010000001, %0000000100000010, false)
test_shiftl_uw(%0100000010000000, %1000000100000000, false)
test_shiftl_uw(%1100000010000000, %1000000100000000, true)
test_shiftl_uw(%1000000000000000, %0000000000000000, true)
txt.print(">> uw\n")
test_shiftr_uw(%0000000000000000, %0000000000000000, false)
test_shiftr_uw(%0000000000000001, %0000000000000000, true)
test_shiftr_uw(%0000001100000010, %0000000110000001, false)
test_shiftr_uw(%0000001100000011, %0000000110000001, true)
test_shiftr_uw(%1000000000000010, %0100000000000001, false)
}
sub signed() {
txt.print("<< b\n")
test_shiftl_b(%00000000 as byte, %00000000 as byte, false)
test_shiftl_b(%00000001 as byte, %00000010 as byte, false)
test_shiftl_b(%01000000 as byte, %10000000 as byte, false)
test_shiftl_b(%10000000 as byte, %00000000 as byte, true)
txt.print(">> b\n")
test_shiftr_b(%00000000 as byte, %00000000 as byte, false)
test_shiftr_b(%00000001 as byte, %00000000 as byte, true)
test_shiftr_b(%10000000 as byte, %11000000 as byte, false)
test_shiftr_b(%10000010 as byte, %11000001 as byte, false)
test_shiftr_b(%10000001 as byte, %11000000 as byte, true)
txt.print("<< w\n")
test_shiftl_w(%0000000000000000 as word, %0000000000000000 as word, false)
test_shiftl_w(%0000000000000001 as word, %0000000000000010 as word, false)
test_shiftl_w(%0000000010000001 as word, %0000000100000010 as word, false)
test_shiftl_w(%0100000010000000 as word, %1000000100000000 as word, false)
test_shiftl_w(%1100000010000000 as word, %1000000100000000 as word, true)
test_shiftl_w(%1000000000000000 as word, %0000000000000000 as word, true)
txt.print(">> w\n")
test_shiftr_w(%0000000000000000 as word, %0000000000000000 as word, false)
test_shiftr_w(%0000000000000001 as word, %0000000000000000 as word, true)
test_shiftr_w(%0000001100000010 as word, %0000000110000001 as word, false)
test_shiftr_w(%0000001100000011 as word, %0000000110000001 as word, true)
test_shiftr_w(%1000000000000010 as word, %1100000000000001 as word, false)
test_shiftr_w(%1000000000000001 as word, %1100000000000000 as word, true)
}
sub test_rol2_ub(ubyte value, ubyte test) {
ubyte original = value
sys.set_carry()
rol2(value)
if value!=test {
txt.print("rol2_ub error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(value)
txt.print(" exp: ")
txt.print_ub(test)
txt.nl()
}
ubarray[1]=original
sys.set_carry()
rol2(ubarray[1])
if ubarray[1]!=test {
txt.print("rol2_ub array error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(ubarray[1])
txt.print(" exp: ")
txt.print_ub(test)
txt.nl()
}
@($8000)=original
sys.set_carry()
rol2(@($8000))
if @($8000)!=test {
txt.print("rol2_ub mem error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(@($8000))
txt.print(" exp: ")
txt.print_ub(test)
txt.nl()
}
}
sub test_ror2_ub(ubyte value, ubyte test) {
ubyte original = value
sys.set_carry()
ror2(value)
if value!=test {
txt.print("ror2_ub error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(value)
txt.print(" exp: ")
txt.print_ub(test)
txt.nl()
}
ubarray[1] = original
sys.set_carry()
ror2(ubarray[1])
if ubarray[1]!=test {
txt.print("ror2_ub array error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(ubarray[1])
txt.print(" exp: ")
txt.print_ub(test)
txt.nl()
}
@($8000) = original
sys.set_carry()
ror2(@($8000))
if @($8000)!=test {
txt.print("ror2_ub mem error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(@($8000))
txt.print(" exp: ")
txt.print_ub(test)
txt.nl()
}
}
sub test_rol_ub(ubyte value, bool carry, ubyte test, bool newcarry) {
bool carrycheck = false
ubyte original = value
if carry
sys.set_carry()
else
sys.clear_carry()
rol(value)
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry{
txt.print("rol_ub error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(carry)
txt.spc()
txt.print_ub(value)
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
ubarray[1] = original
carrycheck = false
if carry
sys.set_carry()
else
sys.clear_carry()
rol(ubarray[value_and_carry(1)])
if_cs
carrycheck=true
if ubarray[1]!=test or carrycheck!=newcarry{
txt.print("rol_ub array error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(carry)
txt.spc()
txt.print_ub(ubarray[1])
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
@($8001)=original
carrycheck = false
if carry
sys.set_carry()
else
sys.clear_carry()
rol(@($8000+value_and_carry(1)))
if_cs
carrycheck=true
if @($8001)!=test or carrycheck!=newcarry {
txt.print("rol_ub mem error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(carry)
txt.spc()
txt.print_ub(@($8001))
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
}
sub test_ror_ub(ubyte value, bool carry, ubyte test, bool newcarry) {
bool carrycheck = false
ubyte original = value
if carry
sys.set_carry()
else
sys.clear_carry()
ror(value)
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry{
txt.print("ror_ub error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(carry)
txt.spc()
txt.print_ub(value)
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
ubarray[1] = original
carrycheck = false
if carry
sys.set_carry()
else
sys.clear_carry()
ror(ubarray[value_and_carry(1)])
if_cs
carrycheck=true
if ubarray[1]!=test or carrycheck!=newcarry {
txt.print("ror_ub array error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(carry)
txt.spc()
txt.print_ub(ubarray[1])
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
@($8001) = original
carrycheck = false
if carry
sys.set_carry()
else
sys.clear_carry()
ror(@($8000+value_and_carry(1)))
if_cs
carrycheck=true
if @($8001)!=test or carrycheck!=newcarry {
txt.print("ror_ub mem error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(carry)
txt.spc()
txt.print_ub(@($8001))
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
}
sub test_rol2_uw(uword value, uword test) {
uword original = value
sys.set_carry()
rol2(value)
if value!=test {
txt.print("rol2_uw error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(value)
txt.print(" exp: ")
txt.print_uw(test)
txt.nl()
}
uwarray[1] = original
sys.set_carry()
rol2(uwarray[1])
if uwarray[1]!=test {
txt.print("rol2_uw array error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(uwarray[1])
txt.print(" exp: ")
txt.print_uw(test)
txt.nl()
}
}
sub test_ror2_uw(uword value, uword test) {
uword original = value
sys.set_carry()
ror2(value)
if value!=test {
txt.print("ror2_uw error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(value)
txt.print(" exp: ")
txt.print_uw(test)
txt.nl()
}
uwarray[1] = original
sys.set_carry()
ror2(uwarray[1])
if uwarray[1]!=test {
txt.print("ror2_uw array error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(uwarray[1])
txt.print(" exp: ")
txt.print_uw(test)
txt.nl()
}
}
sub test_rol_uw(uword value, bool carry, uword test, bool newcarry) {
bool carrycheck = false
uword original = value
if carry
sys.set_carry()
else
sys.clear_carry()
rol(value)
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry{
txt.print("rol_uw error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(carry)
txt.spc()
txt.print_uw(value)
txt.spc()
txt.print_uw(carrycheck)
txt.print(" exp: ")
txt.print_uw(test)
txt.spc()
txt.print_uw(carrycheck)
txt.nl()
}
uwarray[1] = original
carrycheck = false
if carry
sys.set_carry()
else
sys.clear_carry()
rol(uwarray[value_and_carry(1)])
if_cs
carrycheck=true
if uwarray[1]!=test or carrycheck!=newcarry{
txt.print("rol_uw array error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(carry)
txt.spc()
txt.print_uw(uwarray[1])
txt.spc()
txt.print_uw(carrycheck)
txt.print(" exp: ")
txt.print_uw(test)
txt.spc()
txt.print_uw(carrycheck)
txt.nl()
}
}
sub test_ror_uw(uword value, bool carry, uword test, bool newcarry) {
bool carrycheck = false
uword original = value
if carry
sys.set_carry()
else
sys.clear_carry()
ror(value)
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry{
txt.print("ror_uw error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(carry)
txt.spc()
txt.print_uw(value)
txt.spc()
txt.print_uw(carrycheck)
txt.print(" exp: ")
txt.print_uw(test)
txt.spc()
txt.print_uw(carrycheck)
txt.nl()
}
uwarray[1] = original
carrycheck = false
if carry
sys.set_carry()
else
sys.clear_carry()
ror(uwarray[value_and_carry(1)])
if_cs
carrycheck=true
if uwarray[1]!=test or carrycheck!=newcarry{
txt.print("ror_uw array error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(carry)
txt.spc()
txt.print_uw(uwarray[1])
txt.spc()
txt.print_uw(carrycheck)
txt.print(" exp: ")
txt.print_uw(test)
txt.spc()
txt.print_uw(carrycheck)
txt.nl()
}
}
sub test_shiftl_ub(ubyte value, ubyte test, bool newcarry) {
bool carrycheck = false
ubyte original = value
sys.set_carry()
value <<= 1
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry {
txt.print("<< ub error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(value)
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
ubarray[1] = original
sys.set_carry()
carrycheck = false
ubarray[1] <<= 1
if_cs
carrycheck=true
if ubarray[1]!=test or carrycheck!=newcarry {
txt.print("<< ub array error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(ubarray[1])
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
}
sub test_shiftr_ub(ubyte value, ubyte test, bool newcarry) {
bool carrycheck = false
ubyte original = value
sys.set_carry()
value >>= 1
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry {
txt.print(">> ub error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(value)
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
ubarray[1] = original
sys.set_carry()
carrycheck = false
ubarray[1] >>= 1
if_cs
carrycheck=true
if ubarray[1]!=test or carrycheck!=newcarry {
txt.print(">> ub array error ")
txt.print_ub(original)
txt.spc()
txt.print_ub(ubarray[1])
txt.spc()
txt.print_ub(carrycheck)
txt.print(" exp: ")
txt.print_ub(test)
txt.spc()
txt.print_ub(newcarry)
txt.nl()
}
}
sub test_shiftl_uw(uword value, uword test, bool newcarry) {
bool carrycheck = false
uword original = value
sys.set_carry()
value <<= 1
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry {
txt.print("<< uw error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(value)
txt.spc()
txt.print_uw(carrycheck)
txt.print(" exp: ")
txt.print_uw(test)
txt.spc()
txt.print_uw(carrycheck)
txt.nl()
}
uwarray[1] = original
sys.set_carry()
carrycheck = false
uwarray[1] <<= 1
if_cs
carrycheck=true
if uwarray[1]!=test or carrycheck!=newcarry {
txt.print("<< uw array error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(uwarray[1])
txt.spc()
txt.print_uw(carrycheck)
txt.print(" exp: ")
txt.print_uw(test)
txt.spc()
txt.print_uw(carrycheck)
txt.nl()
}
}
sub test_shiftr_uw(uword value, uword test, bool newcarry) {
bool carrycheck = false
uword original = value
sys.set_carry()
value >>= 1
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry {
txt.print(">> uw error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(value)
txt.spc()
txt.print_uw(carrycheck)
txt.print(" exp: ")
txt.print_uw(test)
txt.spc()
txt.print_uw(carrycheck)
txt.nl()
}
uwarray[1] = original
sys.set_carry()
carrycheck = false
uwarray[1] >>= 1
if_cs
carrycheck=true
if uwarray[1]!=test or carrycheck!=newcarry {
txt.print(">> uw array error ")
txt.print_uw(original)
txt.spc()
txt.print_uw(uwarray[1])
txt.spc()
txt.print_uw(carrycheck)
txt.print(" exp: ")
txt.print_uw(test)
txt.spc()
txt.print_uw(carrycheck)
txt.nl()
}
}
sub test_shiftl_b(byte value, byte test, bool newcarry) {
bool carrycheck = false
byte original = value
sys.set_carry()
value <<= 1
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry {
txt.print("<< b error ")
txt.print_b(original)
txt.spc()
txt.print_b(value)
txt.spc()
txt.print_b(carrycheck)
txt.print(" exp: ")
txt.print_b(test)
txt.spc()
txt.print_b(carrycheck)
txt.nl()
}
barray[1] = original
sys.set_carry()
carrycheck = false
barray[1] <<= 1
if_cs
carrycheck=true
if barray[1]!=test or carrycheck!=newcarry {
txt.print("<< b array error ")
txt.print_b(original)
txt.spc()
txt.print_b(barray[1])
txt.spc()
txt.print_b(carrycheck)
txt.print(" exp: ")
txt.print_b(test)
txt.spc()
txt.print_b(carrycheck)
txt.nl()
}
}
sub test_shiftr_b(byte value, byte test, bool newcarry) {
bool carrycheck = false
byte original = value
sys.set_carry()
value >>= 1
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry {
txt.print(">> b error ")
txt.print_b(original)
txt.spc()
txt.print_b(value)
txt.spc()
txt.print_b(carrycheck)
txt.print(" exp: ")
txt.print_b(test)
txt.spc()
txt.print_b(carrycheck)
txt.nl()
}
barray[1] = original
sys.set_carry()
carrycheck = false
barray[1] >>= 1
if_cs
carrycheck=true
if barray[1]!=test or carrycheck!=newcarry {
txt.print(">> b array error ")
txt.print_b(original)
txt.spc()
txt.print_b(barray[1])
txt.spc()
txt.print_b(carrycheck)
txt.print(" exp: ")
txt.print_b(test)
txt.spc()
txt.print_b(carrycheck)
txt.nl()
}
}
sub test_shiftl_w(word value, word test, bool newcarry) {
bool carrycheck = false
word original = value
sys.set_carry()
value <<= 1
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry {
txt.print("<< w error ")
txt.print_w(original)
txt.spc()
txt.print_w(value)
txt.spc()
txt.print_w(carrycheck)
txt.print(" exp: ")
txt.print_w(test)
txt.spc()
txt.print_w(carrycheck)
txt.nl()
}
warray[1] = original
sys.set_carry()
carrycheck = false
warray[1] <<= 1
if_cs
carrycheck=true
if warray[1]!=test or carrycheck!=newcarry {
txt.print("<< w array error ")
txt.print_w(original)
txt.spc()
txt.print_w(warray[1])
txt.spc()
txt.print_w(carrycheck)
txt.print(" exp: ")
txt.print_w(test)
txt.spc()
txt.print_w(carrycheck)
txt.nl()
}
}
sub test_shiftr_w(word value, word test, bool newcarry) {
bool carrycheck = false
word original = value
sys.set_carry()
value >>= 1
if_cs
carrycheck=true
if value!=test or carrycheck!=newcarry {
txt.print(">> w error ")
txt.print_w(original)
txt.spc()
txt.print_w(value)
txt.spc()
txt.print_w(carrycheck)
txt.print(" exp: ")
txt.print_w(test)
txt.spc()
txt.print_w(carrycheck)
txt.nl()
}
warray[1] = original
sys.set_carry()
carrycheck = false
warray[1] >>= 1
if_cs
carrycheck=true
if warray[1]!=test or carrycheck!=newcarry {
txt.print(">> w array error ")
txt.print_w(original)
txt.spc()
txt.print_w(warray[1])
txt.spc()
txt.print_w(carrycheck)
txt.print(" exp: ")
txt.print_w(test)
txt.spc()
txt.print_w(carrycheck)
txt.nl()
}
}
}

View File

@ -294,4 +294,22 @@ main {
((st[4] as Assignment).value as NumericLiteral).number shouldBe 0x9e00+2*30
((st[5] as Assignment).value as NumericLiteral).number shouldBe 0x9e00+2*30
}
test("address of a const uword pointer array expression") {
val src="""
main {
sub start() {
const uword buffer = ${'$'}2000
uword addr = &buffer[2]
const ubyte width = 100
ubyte @shared i
ubyte @shared j
uword addr2 = &buffer[i * width + j]
}
}"""
val result = compileText(Cx16Target(), true, src, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 9999
}
})

View File

@ -203,5 +203,19 @@ main {
}"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("address of a uword pointer array expression") {
val src="""
main {
sub start() {
set_state(12345, 1)
}
sub set_state(uword buffer, ubyte i) {
uword addr = &buffer[i]
addr++
}
}"""
compileText(C64Target(), false, src, writeAssembly = true) shouldNotBe null
}
})

View File

@ -1,9 +1,10 @@
TODO
====
funcRor()/funcRol(): save carry flag before calculating array index otherwise it gets clobbered
2 unit tests that are failing.
Mark had a compiler crash FatalAstException: invalid dt.
Mark had a compiler crash FatalAstException: invalid dt
IR: optimize funcRolRor()
...

View File

@ -4,93 +4,5 @@
main {
sub start() {
word @shared q = -12345
txt.print_w(q)
txt.nl()
txt.print_uwbin(q as uword, true)
txt.nl()
q >>=9
txt.print_w(q)
txt.nl()
txt.print_uwbin(q as uword, true)
txt.nl()
; mem()
; bytes()
; words()
}
sub mem() {
@($2000) = $7a
rol(@($2000))
txt.print_ubbin(@($2000), true)
txt.nl()
rol2(@($2000))
txt.print_ubbin(@($2000), true)
txt.nl()
ror(@($2000))
txt.print_ubbin(@($2000), true)
txt.nl()
ror2(@($2000))
txt.print_ubbin(@($2000), true)
txt.nl()
txt.nl()
}
sub bytes() {
ubyte[] wa = [$1a, $2b, $3c]
txt.print_ubbin(wa[2], true)
txt.nl()
rol(wa[2])
txt.print_ubbin(wa[2], true)
txt.nl()
rol2(wa[2])
txt.print_ubbin(wa[2], true)
txt.nl()
ror(wa[2])
txt.print_ubbin(wa[2], true)
txt.nl()
ror2(wa[2])
txt.print_ubbin(wa[2], true)
txt.nl()
txt.nl()
}
sub words() {
uword[] wa = [$11aa, $22bb, $33cc]
uword[] @split swa = [$11aa, $22bb, $33cc]
txt.print_uwbin(wa[2], true)
txt.nl()
rol(wa[2])
txt.print_uwbin(wa[2], true)
txt.nl()
rol2(wa[2])
txt.print_uwbin(wa[2], true)
txt.nl()
ror(wa[2])
txt.print_uwbin(wa[2], true)
txt.nl()
ror2(wa[2])
txt.print_uwbin(wa[2], true)
txt.nl()
txt.nl()
txt.print_uwbin(swa[2], true)
txt.nl()
rol(swa[2])
txt.print_uwbin(swa[2], true)
txt.nl()
rol2(swa[2])
txt.print_uwbin(swa[2], true)
txt.nl()
ror(swa[2])
txt.print_uwbin(swa[2], true)
txt.nl()
ror2(swa[2])
txt.print_uwbin(swa[2], true)
txt.nl()
txt.nl()
}
}

View File

@ -5,4 +5,4 @@ org.gradle.daemon=true
kotlin.code.style=official
javaVersion=11
kotlinVersion=1.9.22
version=9.8-SNAPSHOT
version=10.0-SNAPSHOT

View File

@ -235,6 +235,8 @@ msig [b, w] reg1, reg2 - reg1 becomes the most significant by
concat [b, w] reg1, reg2, reg3 - reg1.w = 'concatenate' two registers: lsb/lsw of reg2 (as msb) and lsb/lsw of reg3 (as lsb) into word or int (int not yet implemented; requires 32bits regs)
push [b, w, f] reg1 - push value in reg1 on the stack
pop [b, w, f] reg1 - pop value from stack into reg1
pushst - push status register bits to stack
popst - pop status register bits from stack
*/
enum class Opcode {
@ -387,6 +389,8 @@ enum class Opcode {
SEC,
PUSH,
POP,
PUSHST,
POPST,
MSIG,
CONCAT,
BREAKPOINT
@ -699,6 +703,8 @@ val instructionFormats = mutableMapOf(
Opcode.MSIG to InstructionFormat.from("BW,>r1,<r2"),
Opcode.PUSH to InstructionFormat.from("BW,<r1 | F,<fr1"),
Opcode.POP to InstructionFormat.from("BW,>r1 | F,>fr1"),
Opcode.PUSHST to InstructionFormat.from("N"),
Opcode.POPST to InstructionFormat.from("N"),
Opcode.CONCAT to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.CLC to InstructionFormat.from("N"),
Opcode.SEC to InstructionFormat.from("N"),

View File

@ -286,6 +286,8 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.CONCAT -> InsCONCAT(ins)
Opcode.PUSH -> InsPUSH(ins)
Opcode.POP -> InsPOP(ins)
Opcode.PUSHST -> InsPUSHST()
Opcode.POPST -> InsPOPST()
Opcode.BREAKPOINT -> InsBREAKPOINT()
Opcode.CLC -> { statusCarry = false; nextPc() }
Opcode.SEC -> { statusCarry = true; nextPc() }
@ -360,6 +362,28 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc()
}
private fun InsPUSHST() {
var status: UByte = 0u
if(statusNegative)
status = status or 0b10000000u
if(statusZero)
status = status or 0b00000010u
if(statusCarry)
status = status or 0b00000001u
// TODO overflow not yet supported
valueStack.push(status)
nextPc()
}
private fun InsPOPST() {
val status = valueStack.pop().toInt()
statusNegative = status and 0b10000000 != 0
statusZero = status and 0b00000010 != 0
statusCarry = status and 0b00000001 != 0
// TODO overflow not yet supported
nextPc()
}
private fun InsSYSCALL(i: IRInstruction) {
// put the syscall's arguments that were prepared onto the stack
for(value in syscallParams) {