mirror of
https://github.com/irmen/prog8.git
synced 2026-04-26 20:17:57 +00:00
added bcd.addtol()/subfroml() for in-place long calculations
fix long overflow messages, IR register type error
This commit is contained in:
@@ -264,6 +264,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
|
||||
if (target.dt.isByte) inplaceByteAdd(target, value)
|
||||
else if (target.dt.isWord) inplaceWordAdd(target, value)
|
||||
else if (target.dt.isFloat) inplaceFloatAddOrMul(target, "FADD", value)
|
||||
else if (target.dt.isLong) inplaceLongAdd(target, value)
|
||||
else throw AssemblyError("weird dt ${target.dt} ${target.position}")
|
||||
}
|
||||
}
|
||||
@@ -275,6 +276,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
|
||||
if (target.dt.isByte) inplaceByteSub(target, value)
|
||||
else if (target.dt.isWord) inplaceWordSub(target, value)
|
||||
else if (target.dt.isFloat) inplaceFloatSubOrDiv(target, "FSUB", value)
|
||||
else if (target.dt.isLong) inplaceLongSub(target, value)
|
||||
else throw AssemblyError("weird dt ${target.position}")
|
||||
}
|
||||
}
|
||||
@@ -282,12 +284,14 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
|
||||
if(target.dt.isByte) TODO("inplaceByteMul(target, value) ${target.position}")
|
||||
else if(target.dt.isWord) inplaceWordMul(target, value)
|
||||
else if(target.dt.isFloat) inplaceFloatAddOrMul(target, "FMULT", value)
|
||||
else if(target.dt.isLong) TODO("inplace long mul ${target.position}")
|
||||
else throw AssemblyError("weird dt ${target.position}")
|
||||
}
|
||||
"/" -> {
|
||||
if(target.dt.isByte) TODO("inplaceByteDiv(target, value) ${target.position}")
|
||||
else if(target.dt.isWord) inplaceWordDiv(target, value)
|
||||
else if(target.dt.isFloat) inplaceFloatSubOrDiv(target, "FDIV", value)
|
||||
else if(target.dt.isLong) TODO("inplace long div ${target.position}")
|
||||
else throw AssemblyError("weird dt ${target.position}")
|
||||
}
|
||||
"%" -> TODO("inplace ptr %")
|
||||
@@ -943,6 +947,24 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
|
||||
}
|
||||
}
|
||||
|
||||
private fun inplaceLongAdd(target: PtrTarget, value: AsmAssignSource) {
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALNUMBER -> TODO("inplace long add with ${value.number} ${target.position}")
|
||||
SourceStorageKind.VARIABLE -> TODO("inplace long add with ${value.asmVarname} ${target.position}")
|
||||
SourceStorageKind.EXPRESSION -> TODO("inplace long add with ${value.expression} ${target.position}")
|
||||
else -> TODO("inplace long add with ${value.kind} ${target.position}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun inplaceLongSub(target: PtrTarget, value: AsmAssignSource) {
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALNUMBER -> TODO("inplace long sub with ${value.number} ${target.position}")
|
||||
SourceStorageKind.VARIABLE -> TODO("inplace long sub with ${value.asmVarname} ${target.position}")
|
||||
SourceStorageKind.EXPRESSION -> TODO("inplace long sub with ${value.expression} ${target.position}")
|
||||
else -> TODO("inplace long sub with ${value.kind} ${target.position}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun inplaceWordAdd(target: PtrTarget, value: AsmAssignSource) {
|
||||
val (zpPtrVar, offset) = deref(target.pointer)
|
||||
when(value.kind) {
|
||||
|
||||
@@ -1312,11 +1312,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
} else {
|
||||
val shiftTr = expressionEval.translateExpression(operand)
|
||||
addToResult(result, shiftTr, shiftTr.resultReg, -1)
|
||||
var shiftReg = shiftTr.resultReg
|
||||
if(vmDt==IRDataType.WORD && shiftTr.dt==IRDataType.BYTE) {
|
||||
shiftReg = codeGen.registers.next(IRDataType.WORD)
|
||||
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=shiftReg, reg2=shiftTr.resultReg), null)
|
||||
}
|
||||
val shiftReg = shiftTr.resultReg
|
||||
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
|
||||
val ins = if(constAddress!=null)
|
||||
IRInstruction(opc, vmDt, reg1 = shiftReg, address = constAddress)
|
||||
@@ -1374,11 +1370,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
} else {
|
||||
val shiftTr = expressionEval.translateExpression(operand)
|
||||
addToResult(result, shiftTr, shiftTr.resultReg, -1)
|
||||
var shiftReg = shiftTr.resultReg
|
||||
if(vmDt==IRDataType.WORD && shiftTr.dt==IRDataType.BYTE) {
|
||||
shiftReg = codeGen.registers.next(IRDataType.WORD)
|
||||
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=shiftReg, reg2=shiftTr.resultReg), null)
|
||||
}
|
||||
val shiftReg = shiftTr.resultReg
|
||||
addInstr(result, if(constAddress!=null)
|
||||
IRInstruction(Opcode.LSLNM, vmDt, reg1=shiftReg, address = constAddress)
|
||||
else
|
||||
|
||||
@@ -38,6 +38,36 @@ bcd {
|
||||
return a
|
||||
}
|
||||
|
||||
sub addtol(^^long a, long b) {
|
||||
; -- inplace long BCD addition (avoids copying long values by value)
|
||||
setbcd()
|
||||
;; NOT YET IMPLEMENTED IN PROG8: a^^ += b, so inline asm
|
||||
%asm {{
|
||||
lda p8v_a
|
||||
ldy p8v_a+1
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
ldy #0
|
||||
clc
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
adc p8v_b
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
adc p8v_b+1
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
adc p8v_b+2
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
adc p8v_b+3
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
}}
|
||||
clearbcd()
|
||||
}
|
||||
|
||||
sub subb(byte a, byte b) -> byte {
|
||||
setbcd()
|
||||
a -= b
|
||||
@@ -66,7 +96,39 @@ bcd {
|
||||
return a
|
||||
}
|
||||
|
||||
sub subfroml(^^long a, long b) {
|
||||
; -- inplace long BCD subtraction (avoids copying long values by value)
|
||||
setbcd()
|
||||
;; NOT YET IMPLEMENTED IN PROG8: a^^ -= b, so inline asm
|
||||
%asm {{
|
||||
lda p8v_a
|
||||
ldy p8v_a+1
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
ldy #0
|
||||
sec
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sbc p8v_b
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sbc p8v_b+1
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sbc p8v_b+2
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sbc p8v_b+3
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
}}
|
||||
clearbcd()
|
||||
}
|
||||
|
||||
|
||||
inline asmsub setbcd() {
|
||||
; be safe and 6502 compatible and prohibit interrupts during BCD mode
|
||||
%asm {{
|
||||
php
|
||||
sei
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
bcd {
|
||||
; virtual machine does not support BCD
|
||||
}
|
||||
@@ -2092,6 +2092,12 @@ internal class AstChecker(private val program: Program,
|
||||
super.visit(memread)
|
||||
}
|
||||
|
||||
override fun visit(numLiteral: NumericLiteral) {
|
||||
super.visit(numLiteral)
|
||||
if(numLiteral.type== BaseDataType.LONG) // other smaller types have already been validated
|
||||
checkValueTypeAndRange(DataType.forDt(numLiteral.type), numLiteral)
|
||||
}
|
||||
|
||||
private fun allowedMemoryAccessAddressExpression(addressExpression: Expression, program: Program): Boolean {
|
||||
val dt = addressExpression.inferType(program)
|
||||
if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub?.isByteOrBool==true))
|
||||
@@ -2351,7 +2357,7 @@ internal class AstChecker(private val program: Program,
|
||||
if(value.type==BaseDataType.FLOAT)
|
||||
err("integer value expected instead of float; possible loss of precision")
|
||||
val number=value.number
|
||||
if (number < -2147483647 || number > 2147483647)
|
||||
if (number < -2147483647.0 || number > 2147483647.0)
|
||||
return err("value '$number' out of range for long")
|
||||
}
|
||||
targetDt.isArray -> {
|
||||
@@ -2463,7 +2469,7 @@ internal class AstChecker(private val program: Program,
|
||||
val sourceIsBitwiseOperatorExpression = (sourceValue as? BinaryExpression)?.operator in BitwiseOperators
|
||||
if(sourceDatatype.isWord && targetDatatype.isByte)
|
||||
errors.err("cannot assign word to byte, maybe use msb() or lsb()", position)
|
||||
else if(sourceDatatype.isFloat&& targetDatatype.isInteger)
|
||||
else if(sourceDatatype.isFloat && targetDatatype.isInteger)
|
||||
errors.err("cannot assign float to ${targetDatatype}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position)
|
||||
else if(targetDatatype.isUnsignedWord && (sourceDatatype.isPassByRef || sourceDatatype.isPointer)) {
|
||||
// this is allowed: a pass-by-reference or pointer datatype into an uword (untyped pointer value).
|
||||
|
||||
@@ -332,12 +332,12 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
|
||||
fun makeLiteral(literalTextWithGrouping: String, radix: Int): Pair<Double, BaseDataType> {
|
||||
val literalText = literalTextWithGrouping.replace("_", "")
|
||||
val integer: Int
|
||||
val integer: Long
|
||||
var datatype = BaseDataType.UBYTE
|
||||
when (radix) {
|
||||
10 -> {
|
||||
integer = try {
|
||||
literalText.toInt()
|
||||
literalText.toLong()
|
||||
} catch(x: NumberFormatException) {
|
||||
throw SyntaxError("invalid decimal literal ${x.message}", ctx.toPosition())
|
||||
}
|
||||
@@ -356,7 +356,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
else if(literalText.length>8)
|
||||
datatype = BaseDataType.UWORD
|
||||
try {
|
||||
integer = literalText.toInt(2)
|
||||
integer = literalText.toLong(2)
|
||||
} catch(x: NumberFormatException) {
|
||||
throw SyntaxError("invalid binary literal ${x.message}", ctx.toPosition())
|
||||
}
|
||||
@@ -367,7 +367,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
else if(literalText.length>2)
|
||||
datatype = BaseDataType.UWORD
|
||||
try {
|
||||
integer = literalText.lowercase().toLong(16).toInt()
|
||||
integer = literalText.lowercase().toLong(16)
|
||||
} catch(x: NumberFormatException) {
|
||||
throw SyntaxError("invalid hexadecimal literal ${x.message}", ctx.toPosition())
|
||||
}
|
||||
|
||||
@@ -650,7 +650,7 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed
|
||||
BaseDataType.BYTE -> require(number in -128.0..127.0)
|
||||
BaseDataType.UWORD -> require(number in 0.0..65535.0)
|
||||
BaseDataType.WORD -> require(number in -32768.0..32767.0)
|
||||
BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0)
|
||||
BaseDataType.LONG -> { /*no hard requirement, the range will be checked later to give a proper error message instead of a crash */ }
|
||||
BaseDataType.BOOL -> require(number==0.0 || number==1.0)
|
||||
BaseDataType.POINTER -> throw FatalAstException("pointer literals should not be created, should have been UWORD $position")
|
||||
else -> require(type.isNumericOrBool) {
|
||||
@@ -699,8 +699,7 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed
|
||||
in -128..127 -> NumericLiteral(BaseDataType.BYTE, dvalue, position)
|
||||
in 0..65535 -> NumericLiteral(BaseDataType.UWORD, dvalue, position)
|
||||
in -32768..32767 -> NumericLiteral(BaseDataType.WORD, dvalue, position)
|
||||
in -2147483647..2147483647 -> NumericLiteral(BaseDataType.LONG, dvalue, position)
|
||||
else -> throw FatalAstException("integer overflow: $dvalue")
|
||||
else -> NumericLiteral(BaseDataType.LONG, dvalue, position)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- add bcd.addto()/subto() routines for in-place addition and subtraction
|
||||
- fix lv1 |= -1 being lv1 = 65535 (wrong optimization value)
|
||||
|
||||
- optimizedBitwiseExpr(): use R14:R15 instead to save copying/stack manipulation?
|
||||
|
||||
@@ -12,6 +12,8 @@ TODO
|
||||
|
||||
- (not needed anymore if everything is saved on the stack?:) can the compiler give a warning if you use R0/R1 (or whatever the temp storage is) in expressions and/or statements together with long integers? (because R0/R1 are likely to be clobbered as temporary storage)
|
||||
|
||||
- implement inplaceLongAdd/Sub in PointerAssignmentGen
|
||||
|
||||
|
||||
STRUCTS and TYPED POINTERS
|
||||
--------------------------
|
||||
@@ -30,6 +32,7 @@ STRUCTS and TYPED POINTERS
|
||||
|
||||
Future Things and Ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- make $8000000 a valid long integer (-2147483648) this is more involved than you think
|
||||
- fix the line, cols in Position, sometimes they count from 0 sometimes from 1, should both always be 1-based (is this the reason some source lines end up missing in the IR file?)
|
||||
- handle Alias in a general way in LiteralsToAutoVarsAndRecombineIdentifiers instead of replacing it scattered over multiple functions
|
||||
- After long variable type is completed: make all constants long by default (remove type name altogether), reduce to target type implictly if the actual value fits.
|
||||
|
||||
+25
-11
@@ -1,24 +1,38 @@
|
||||
%import bcd
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
;;%option no_sysinit
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
long @shared lv1 = $1234567
|
||||
long @shared lv1 = $12345678
|
||||
uword @shared w = $1234
|
||||
|
||||
txt.print_uwhex(msw(lv1<<1), true)
|
||||
txt.print_uwhex(lsw(lv1<<1), true)
|
||||
lv1 = bcd.addl(lv1, $11110000)
|
||||
bcd.addtol(&lv1, $11110000)
|
||||
w = bcd.adduw(w, $1111)
|
||||
|
||||
txt.print_ulhex(lv1, true)
|
||||
txt.nl()
|
||||
txt.print_uwhex(w, true)
|
||||
txt.nl()
|
||||
|
||||
; TODO support long+1 / -1 expressions....
|
||||
;lv1 |= -1 ; TODO fix value
|
||||
|
||||
cx16.r4 = msw(lv1<<1)
|
||||
cx16.r5 = lsw(lv1<<1)
|
||||
txt.print_uwhex(cx16.r4, true)
|
||||
txt.print_uwhex(cx16.r5, true)
|
||||
txt.nl()
|
||||
|
||||
txt.print_ubhex((lv1<<1) as ubyte, true)
|
||||
txt.nl()
|
||||
; txt.print_uwhex(msw(lv1<<1), true)
|
||||
; txt.print_uwhex(lsw(lv1<<1), true)
|
||||
; txt.nl()
|
||||
;
|
||||
; ; TODO support long+1 / -1 expressions....
|
||||
;
|
||||
; cx16.r4 = msw(lv1<<1)
|
||||
; cx16.r5 = lsw(lv1<<1)
|
||||
; txt.print_uwhex(cx16.r4, true)
|
||||
; txt.print_uwhex(cx16.r5, true)
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print_ubhex((lv1<<1) as ubyte, true)
|
||||
; txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user