mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
fixes
This commit is contained in:
parent
f00d2f06c9
commit
0b86af0c4e
@ -913,6 +913,39 @@ asmsub print_ubhex (ubyte prefix @ Pc, ubyte value @ A) -> clobbers(A,X,Y) ->
|
||||
}
|
||||
|
||||
|
||||
asmsub print_ubbin (ubyte prefix @ Pc, ubyte value @ A) -> clobbers(A,X,Y) ->() {
|
||||
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||
%asm {{
|
||||
sta c64.SCRATCH_ZPB1
|
||||
bcc +
|
||||
lda #'%'
|
||||
jsr c64.CHROUT
|
||||
+ ldy #8
|
||||
- lda #'0'
|
||||
asl c64.SCRATCH_ZPB1
|
||||
bcc +
|
||||
lda #'1'
|
||||
+ jsr c64.CHROUT
|
||||
dey
|
||||
bne -
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
asmsub print_uwbin (ubyte prefix @ Pc, uword value @ AY) -> clobbers(A,X,Y) ->() {
|
||||
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||
%asm {{
|
||||
pha
|
||||
tya
|
||||
jsr print_ubbin
|
||||
pla
|
||||
clc
|
||||
jmp print_ubbin
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
asmsub print_uwhex (ubyte prefix @ Pc, uword value @ AY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
||||
; (if Carry is set, a radix prefix '$' is printed as well)
|
||||
|
@ -9,19 +9,6 @@
|
||||
|
||||
%asm {{
|
||||
|
||||
; 16-bit rotate right (as opposed to the 6502's usual 17-bit rotate with carry)
|
||||
; the word is placed in c64.SCRATCH_ZPWORD1
|
||||
ror2_word .proc
|
||||
lsr c64.SCRATCH_ZPWORD1+1
|
||||
ror c64.SCRATCH_ZPWORD1
|
||||
bcc +
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
ora #$80
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
+ rts
|
||||
.pend
|
||||
|
||||
|
||||
add_a_to_zpword .proc
|
||||
; -- add ubyte in A to the uword in c64.SCRATCH_ZPWORD1
|
||||
clc
|
||||
|
@ -382,8 +382,10 @@ interface INameScope {
|
||||
return null
|
||||
}
|
||||
|
||||
fun allLabelsAndVariables() = statements.asSequence().filter { it is Label || it is VarDecl }
|
||||
.associate {((it as? Label)?.name ?: (it as? VarDecl)?.name)!! to it }
|
||||
fun allLabelsAndVariables(): Map<String, IStatement> {
|
||||
val labelsAndVars = statements.filterIsInstance<Label>() + statements.filterIsInstance<VarDecl>()
|
||||
return labelsAndVars.associate { ((it as? Label)?.name ?: (it as? VarDecl)?.name)!! to it }
|
||||
}
|
||||
|
||||
fun lookup(scopedName: List<String>, statement: Node) : IStatement? {
|
||||
if(scopedName.size>1) {
|
||||
|
@ -433,16 +433,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
target.register != null -> RegisterExpr(target.register, target.position)
|
||||
target.identifier != null -> target.identifier
|
||||
target.arrayindexed != null -> target.arrayindexed
|
||||
target.memoryAddress != null -> target.memoryAddress!!
|
||||
// // @addr += 4 --> @addr = @addr +4
|
||||
// // TODO: make it so that it follows the others
|
||||
// val memRead = DirectMemoryRead(target.memoryAddress!!, target.position)
|
||||
// val expression = BinaryExpression(memRead, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
|
||||
// expression.linkParents(assignment.parent)
|
||||
// val assignment2 = Assignment(listOf(target), null, expression, assignment.position)
|
||||
// assignment2.linkParents(assignment.parent)
|
||||
// return assignment2
|
||||
// }
|
||||
target.memoryAddress != null -> DirectMemoryRead(target.memoryAddress!!.addressExpression, assignment.value.position)
|
||||
else -> throw FatalAstException("strange assignment")
|
||||
}
|
||||
|
||||
|
@ -162,9 +162,6 @@ class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
|
||||
printWarning("writing to the X register is dangerous, because it's used as an internal pointer", forLoop.position)
|
||||
} else if(forLoop.loopVar!=null) {
|
||||
val varName = forLoop.loopVar.nameInSource.last()
|
||||
if(forLoop.iterable is RangeExpr && forLoop.decltype!=null && forLoop.decltype !in setOf(DataType.UBYTE, DataType.UWORD)) {
|
||||
checkResult.add(SyntaxError("loop variables over a numeric range can only be ubyte or uword", forLoop.position)) // TODO allow signed range loopvars
|
||||
}
|
||||
if(forLoop.decltype!=null) {
|
||||
val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first())
|
||||
if(existing==null) {
|
||||
|
@ -194,9 +194,11 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
|
||||
fun optimizeWordConversion(index0: Int, ins0: Instruction, index1: Int, ins1: Instruction) {
|
||||
when (ins1.opcode) {
|
||||
Opcode.CAST_B_TO_W, Opcode.CAST_B_TO_UW -> TODO("cast byte to (u)word")
|
||||
Opcode.CAST_UB_TO_W, Opcode.CAST_UB_TO_UW -> TODO("cast ubyte to (u)word")
|
||||
Opcode.CAST_W_TO_B, Opcode.CAST_UW_TO_B -> TODO("cast (u)word to byte")
|
||||
Opcode.CAST_UW_TO_B, Opcode.CAST_W_TO_B -> {
|
||||
val ins = Instruction(Opcode.PUSH_BYTE, ins0.arg!!.cast(DataType.BYTE))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.CAST_W_TO_UB, Opcode.CAST_UW_TO_UB -> {
|
||||
val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, ins0.arg!!.integerValue() and 255))
|
||||
instructionsToReplace[index0] = ins
|
||||
@ -247,7 +249,16 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.CAST_B_TO_UW, Opcode.CAST_UB_TO_W -> TODO("cast byte to (u)word")
|
||||
Opcode.CAST_B_TO_UW -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, ins0.arg!!.cast(DataType.UWORD))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.CAST_UB_TO_W -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, ins0.arg!!.cast(DataType.WORD))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.CAST_B_TO_F, Opcode.CAST_UB_TO_F-> {
|
||||
val ins = Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, ins0.arg!!.integerValue().toDouble()))
|
||||
instructionsToReplace[index0] = ins
|
||||
@ -268,6 +279,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
|
||||
val typeConversionOpcodes = setOf(
|
||||
Opcode.MSB,
|
||||
Opcode.MKWORD,
|
||||
Opcode.CAST_UB_TO_B,
|
||||
Opcode.CAST_UB_TO_UW,
|
||||
Opcode.CAST_UB_TO_W,
|
||||
|
@ -181,7 +181,6 @@ enum class Opcode {
|
||||
POP_DEC_MEMORY, // decrement address from address
|
||||
|
||||
// comparisons
|
||||
// @todo the comparisons push the result back on the stack. Optimize this to work with just processor flags? This does mean you can no longer use a logical boolean result as a byte 0/1 value ?
|
||||
LESS_B,
|
||||
LESS_UB,
|
||||
LESS_W,
|
||||
@ -208,10 +207,10 @@ enum class Opcode {
|
||||
NOTEQUAL_BYTE,
|
||||
NOTEQUAL_WORD,
|
||||
NOTEQUAL_F,
|
||||
CMP_B, // sets processor status flags based on comparison, instead of actually storing a result value
|
||||
CMP_UB, // sets processor status flags based on comparison, instead of actually storing a result value
|
||||
CMP_W, // sets processor status flags based on comparison, instead of actually storing a result value
|
||||
CMP_UW, // sets processor status flags based on comparison, instead of actually storing a result value
|
||||
CMP_B, // sets processor status flags based on comparison, instead of pushing a result value
|
||||
CMP_UB, // sets processor status flags based on comparison, instead of pushing a result value
|
||||
CMP_W, // sets processor status flags based on comparison, instead of pushing a result value
|
||||
CMP_UW, // sets processor status flags based on comparison, instead of pushing a result value
|
||||
|
||||
// array access and simple manipulations
|
||||
READ_INDEXED_VAR_BYTE,
|
||||
|
@ -414,7 +414,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
DataType.UWORD -> Value(DataType.UWORD, numericValue())
|
||||
DataType.WORD -> Value(DataType.WORD, numericValue())
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
|
||||
else -> throw ValueException("invalid type cast from $type to $targetType") // @todo ast-check for this
|
||||
else -> TODO("invalid type cast from $type to $targetType - should be an ast-check")
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
@ -424,7 +424,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535)
|
||||
DataType.WORD -> Value(DataType.WORD, integerValue())
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
|
||||
else -> throw ValueException("invalid type cast from $type to $targetType") // @todo ast-check for this
|
||||
else -> TODO("invalid type cast from $type to $targetType - should be an ast-check")
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
@ -438,7 +438,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
Value(DataType.WORD, -(65536-integerValue()))
|
||||
}
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
|
||||
else -> throw ValueException("invalid type cast from $type to $targetType") // @todo ast-check for this
|
||||
else -> TODO("invalid type cast from $type to $targetType - should be an ast-check")
|
||||
}
|
||||
}
|
||||
DataType.WORD -> {
|
||||
@ -447,7 +447,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535)
|
||||
DataType.WORD -> this
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
|
||||
else -> throw ValueException("invalid type cast from $type to $targetType") // @todo ast-check for this
|
||||
else -> TODO("invalid type cast from $type to $targetType - should be an ast-check")
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
@ -457,7 +457,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
if(integer in -128..127)
|
||||
Value(DataType.BYTE, integer)
|
||||
else
|
||||
throw AstException("overflow when casting float to byte: $this") // @todo ast-check for this
|
||||
TODO("overflow when casting float to byte: $this - should be an ast-check")
|
||||
}
|
||||
DataType.UBYTE -> Value(DataType.UBYTE, numericValue().toInt() and 255)
|
||||
DataType.UWORD -> Value(DataType.UWORD, numericValue().toInt() and 65535)
|
||||
@ -466,13 +466,13 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
if(integer in -32768..32767)
|
||||
Value(DataType.WORD, integer)
|
||||
else
|
||||
throw AstException("overflow when casting float to word: $this") // @todo ast-check for this
|
||||
TODO("overflow when casting float to word: $this - should be an ast-check")
|
||||
}
|
||||
DataType.FLOAT -> this
|
||||
else -> throw ValueException("invalid type cast from $type to $targetType") // @todo ast-check for this
|
||||
else -> TODO("invalid type cast from $type to $targetType - should be an ast-check")
|
||||
}
|
||||
}
|
||||
else -> throw ValueException("invalid type cast from $type to $targetType") // @todo ast-check for this
|
||||
else -> TODO("invalid type cast from $type to $targetType - should be an ast-check")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,8 +480,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
// restore all registers and cpu status flag
|
||||
" pla | tay | pla | tax | pla | plp"
|
||||
}
|
||||
Opcode.RSAVEX -> " stx ${C64Zeropage.SCRATCH_REG_X}" // TODO on stack instead, to allow nested calls?
|
||||
Opcode.RRESTOREX -> " ldx ${C64Zeropage.SCRATCH_REG_X}"
|
||||
Opcode.RSAVEX -> " txa | pha"
|
||||
Opcode.RRESTOREX -> " pla | tax"
|
||||
Opcode.RSAVEY -> " tya | pha"
|
||||
Opcode.RRESTOREY -> " pla | tay"
|
||||
Opcode.DISCARD_BYTE -> " inx"
|
||||
@ -829,7 +829,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x"
|
||||
Opcode.MKWORD -> " inx | lda ${ESTACK_LO.toHex()},x | sta ${(ESTACK_HI+1).toHex()},x "
|
||||
|
||||
Opcode.ADD_UB, Opcode.ADD_B -> { // TODO inline better?
|
||||
Opcode.ADD_UB, Opcode.ADD_B -> { // TODO inline better (pattern with more opcodes)
|
||||
"""
|
||||
lda ${(ESTACK_LO + 2).toHex()},x
|
||||
clc
|
||||
@ -838,7 +838,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
sta ${(ESTACK_LO + 1).toHex()},x
|
||||
"""
|
||||
}
|
||||
Opcode.SUB_UB, Opcode.SUB_B -> { // TODO inline better?
|
||||
Opcode.SUB_UB, Opcode.SUB_B -> { // TODO inline better (pattern with more opcodes)
|
||||
"""
|
||||
lda ${(ESTACK_LO + 2).toHex()},x
|
||||
sec
|
||||
@ -1047,17 +1047,17 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
Opcode.SHL_BYTE -> AsmFragment(" asl $variable+$index", 8)
|
||||
Opcode.SHR_UBYTE -> AsmFragment(" lsr $variable+$index", 8)
|
||||
Opcode.SHR_SBYTE -> AsmFragment(" lda $variable+$index | asl a | ror $variable+$index")
|
||||
Opcode.SHL_WORD -> AsmFragment(" asl $variable+${index+1} | rol $variable+$index", 8)
|
||||
Opcode.SHR_UWORD -> AsmFragment(" lsr $variable+${index+1} | ror $variable+$index", 8)
|
||||
Opcode.SHR_SWORD -> AsmFragment(" lda $variable+${index+1} | asl a | ror $variable+${index+1} | ror $variable+$index", 8)
|
||||
Opcode.SHL_WORD -> AsmFragment(" asl $variable+${index*2+1} | rol $variable+$index*2", 8)
|
||||
Opcode.SHR_UWORD -> AsmFragment(" lsr $variable+${index*2+1} | ror $variable+$index*2", 8)
|
||||
Opcode.SHR_SWORD -> AsmFragment(" lda $variable+${index*2+1} | asl a | ror $variable+${index*2+1} | ror $variable+$index*2", 8)
|
||||
Opcode.ROL_BYTE -> AsmFragment(" rol $variable+$index", 8)
|
||||
Opcode.ROR_BYTE -> AsmFragment(" ror $variable+$index", 8)
|
||||
Opcode.ROL_WORD -> AsmFragment(" rol $variable+${index+1} | rol $variable+$index", 8)
|
||||
Opcode.ROR_WORD -> AsmFragment(" ror $variable+${index+1} | ror $variable+$index", 8)
|
||||
Opcode.ROL_WORD -> AsmFragment(" rol $variable+${index*2+1} | rol $variable+$index*2", 8)
|
||||
Opcode.ROR_WORD -> AsmFragment(" ror $variable+${index*2+1} | ror $variable+$index*2", 8)
|
||||
Opcode.ROL2_BYTE -> AsmFragment(" lda $variable+$index | cmp #\$80 | rol $variable+$index", 8)
|
||||
Opcode.ROR2_BYTE -> AsmFragment(" lda $variable+$index | lsr a | bcc + | ora #\$80 |+ | sta $variable+$index", 10)
|
||||
Opcode.ROL2_WORD -> AsmFragment(" asl $variable+${index+1} | rol $variable+$index | bcc + | inc $variable+$index |+",20) // todo wrong???
|
||||
Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index+1} | ror $variable+$index | bcc + | lda $variable+${index+1} | ora #\$80 | sta $variable+${index+1} |+", 30)
|
||||
Opcode.ROL2_WORD -> AsmFragment(" asl $variable+${index*2+1} | rol $variable+$index*2 | bcc + | inc $variable+$index*2+1 |+",20)
|
||||
Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index*2+1} | ror $variable+$index*2 | bcc + | lda $variable+${index*2+1} | ora #\$80 | sta $variable+${index*2+1} |+", 30)
|
||||
Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> AsmFragment(" inc $variable+$index", 2)
|
||||
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> AsmFragment(" dec $variable+$index", 5)
|
||||
Opcode.INC_INDEXED_VAR_W -> TODO("inc array_w")
|
||||
@ -1228,8 +1228,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
AsmFragment(" lda $variable | cmp #\$80 | rol $variable | rol $variable+1", 10)
|
||||
}
|
||||
Opcode.ROR2_WORD -> {
|
||||
// todo: ror2_word is very slow; it requires a library routine
|
||||
AsmFragment(" lda $variable | sta ${C64Zeropage.SCRATCH_W1} | lda $variable+1 | sta ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | lda ${C64Zeropage.SCRATCH_W1} | sta $variable | lda ${C64Zeropage.SCRATCH_W1+1} | sta $variable+1", 30)
|
||||
AsmFragment(" lsr $variable+1 | ror $variable | bcc + | lda $variable+1 | ora #\$80 | sta $variable+1 |+", 30)
|
||||
}
|
||||
// Opcode.SYSCALL -> {
|
||||
// TODO("optimize SYSCALL $ins in-place on variable $variable")
|
||||
|
@ -4,13 +4,53 @@
|
||||
|
||||
sub start() {
|
||||
|
||||
str question = "how are you?\n"
|
||||
byte b
|
||||
ubyte ub
|
||||
memory ubyte mb = $c000
|
||||
memory uword muw = $c000
|
||||
word w
|
||||
uword uw
|
||||
uword[4] uwa
|
||||
|
||||
; use iteration to write text
|
||||
for ubyte char in question { ; @todo fix iteration
|
||||
;vm_write_char(char)
|
||||
c64.CHROUT(char)
|
||||
ub=%10001011
|
||||
for ubyte i in 0 to 10 {
|
||||
c64scr.print_ubbin(1, ub)
|
||||
rol2(ub)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
uw=%1000101100001110
|
||||
for ubyte i in 0 to 10 {
|
||||
c64scr.print_uwbin(1, uw)
|
||||
rol2(uw)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
muw=%1000101100001110
|
||||
for ubyte i in 0 to 10 {
|
||||
c64scr.print_uwbin(1, muw)
|
||||
rol2(muw)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
ubyte x=2
|
||||
uwa[x]=%1000101100001110
|
||||
for ubyte i in 0 to 10 {
|
||||
c64scr.print_uwbin(1, uwa[x])
|
||||
rol2(uwa[x])
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
uwa[2]=%1000101100001110
|
||||
for ubyte i in 0 to 10 {
|
||||
c64scr.print_uwbin(1, uwa[2])
|
||||
rol2(uwa[2]) ; @todo wrong
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user