This commit is contained in:
Irmen de Jong 2019-01-12 13:34:45 +01:00
parent f00d2f06c9
commit 0b86af0c4e
10 changed files with 123 additions and 63 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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