mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
implemented all bit rotate and shift operations
This commit is contained in:
parent
da3f79c092
commit
b8f3f942d4
@ -1,3 +1,4 @@
|
||||
%import c64utils
|
||||
%option enable_floats
|
||||
|
||||
~ irq {
|
||||
|
@ -1,3 +1,4 @@
|
||||
%import c64utils
|
||||
%option enable_floats
|
||||
|
||||
~ main {
|
||||
|
@ -1,16 +1,17 @@
|
||||
%output prg
|
||||
%import c64lib
|
||||
%import c64utils
|
||||
%import mathlib
|
||||
|
||||
~ main {
|
||||
sub start() -> () {
|
||||
str name = "?" * 80
|
||||
str guess = "?" * 80
|
||||
byte secretnumber = 0
|
||||
byte attempts_left = 10
|
||||
memory word freadstr_arg = $22 ; argument for FREADSTR
|
||||
sub start() {
|
||||
str name = "????????????????????????????????????????"
|
||||
str guess = "??????????"
|
||||
ubyte secretnumber = 0
|
||||
ubyte attempts_left = 10
|
||||
memory uword freadstr_arg = $22 ; argument for FREADSTR
|
||||
|
||||
c64.init_system()
|
||||
c64utils.init_system()
|
||||
c64.VMCSB |= 2 ; activate lowercase charset
|
||||
|
||||
; greeting
|
||||
|
@ -1,3 +1,5 @@
|
||||
%import c64utils
|
||||
|
||||
~ main {
|
||||
sub start() {
|
||||
str name = " "
|
||||
|
@ -1,3 +1,4 @@
|
||||
%import c64utils
|
||||
%option enable_floats
|
||||
|
||||
~ main {
|
||||
|
@ -1,88 +1,15 @@
|
||||
;%import c64utils
|
||||
%option enable_floats
|
||||
%import c64utils
|
||||
%output prg
|
||||
%launcher basic
|
||||
|
||||
~ main {
|
||||
|
||||
|
||||
sub start() {
|
||||
|
||||
byte bvar
|
||||
ubyte ubvar
|
||||
memory byte mbvar = $c400
|
||||
memory ubyte mubvar = $c400
|
||||
byte[10] barray
|
||||
ubyte[10] ubarray
|
||||
|
||||
memory word mword = $c000
|
||||
memory word mword2 = $c200
|
||||
memory uword muword = $c100
|
||||
memory uword muword2 = $c300
|
||||
float fvar
|
||||
uword uwvar
|
||||
word wvar
|
||||
uword[10] uwarray
|
||||
|
||||
|
||||
lsl(Y)
|
||||
lsl(ubvar)
|
||||
lsl(mubvar)
|
||||
lsl(ubarray[2])
|
||||
|
||||
lsl(AY)
|
||||
lsl(uwvar)
|
||||
lsl(muword)
|
||||
lsl(uwarray[3])
|
||||
|
||||
lsr(Y)
|
||||
lsr(ubvar)
|
||||
lsr(mubvar)
|
||||
lsr(ubarray[2])
|
||||
|
||||
lsr(AY)
|
||||
lsr(uwvar)
|
||||
lsr(muword)
|
||||
lsr(uwarray[3])
|
||||
|
||||
rol(Y)
|
||||
rol(ubvar)
|
||||
rol(mubvar)
|
||||
rol(ubarray[2])
|
||||
|
||||
rol(AY)
|
||||
rol(uwvar)
|
||||
rol(muword)
|
||||
rol(uwarray[3])
|
||||
|
||||
ror(Y)
|
||||
ror(ubvar)
|
||||
ror(mubvar)
|
||||
ror(ubarray[2])
|
||||
|
||||
ror(AY)
|
||||
ror(uwvar)
|
||||
ror(muword)
|
||||
ror(uwarray[3])
|
||||
|
||||
rol2(Y)
|
||||
rol2(ubvar)
|
||||
rol2(mubvar)
|
||||
rol2(ubarray[2])
|
||||
|
||||
rol2(AY)
|
||||
rol2(uwvar)
|
||||
rol2(muword)
|
||||
rol2(uwarray[3])
|
||||
|
||||
ror2(Y)
|
||||
ror2(ubvar)
|
||||
ror2(mubvar)
|
||||
ror2(ubarray[2])
|
||||
|
||||
ror2(AY)
|
||||
ror2(uwvar)
|
||||
ror2(muword)
|
||||
ror2(uwarray[3])
|
||||
c64.VMCSB |= 2 ; activate lowercase charset
|
||||
|
||||
; greeting
|
||||
c64scr.print_string("Enter your name: ")
|
||||
|
||||
return
|
||||
|
||||
|
@ -69,6 +69,12 @@ fun main(args: Array<String>) {
|
||||
zpType, zpReserved,
|
||||
options.any{ it.name=="enable_floats"})
|
||||
|
||||
if(compilerOptions.launcher==LauncherType.BASIC && compilerOptions.output!=OutputType.PRG)
|
||||
throw ParsingFailedError("${moduleAst.position} BASIC launcher requires output type PRG.")
|
||||
if(compilerOptions.output==OutputType.PRG || compilerOptions.launcher==LauncherType.BASIC) {
|
||||
if(namespace.lookup(listOf("c64utils"), moduleAst.statements.first())==null)
|
||||
throw ParsingFailedError("${moduleAst.position} When using output type PRG and/or laucher BASIC, the 'c64utils' module must be imported.")
|
||||
}
|
||||
|
||||
// perform initial syntax checks and constant folding
|
||||
val heap = HeapValues()
|
||||
|
@ -409,7 +409,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
litVal.parent = decl
|
||||
decl.value = litVal
|
||||
}
|
||||
else -> err("var/const declaration needs a compile-time constant initializer value for this type") // const fold should have provided it!
|
||||
else -> err("var/const declaration needs a compile-time constant initializer value for type ${decl.datatype}") // const fold should have provided it!
|
||||
}
|
||||
return super.process(decl)
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ import prog8.ast.*
|
||||
import prog8.compiler.intermediate.IntermediateProgram
|
||||
import prog8.compiler.intermediate.Opcode
|
||||
import prog8.compiler.intermediate.Value
|
||||
import prog8.stackvm.*
|
||||
import prog8.stackvm.Syscall
|
||||
import prog8.stackvm.VmExecutionException
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
|
@ -14,8 +14,9 @@ open class Instruction(val opcode: Opcode,
|
||||
val argStr = arg?.toString() ?: ""
|
||||
val result =
|
||||
when {
|
||||
opcode== Opcode.LINE -> "_line $callLabel"
|
||||
opcode== Opcode.SYSCALL -> {
|
||||
opcode==Opcode.LINE -> "_line $callLabel"
|
||||
opcode==Opcode.INLINE_ASSEMBLY -> "inline_assembly"
|
||||
opcode==Opcode.SYSCALL -> {
|
||||
val syscall = Syscall.values().find { it.callNr==arg!!.numericValue() }
|
||||
"syscall $syscall"
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package prog8.compiler.target.c64
|
||||
|
||||
// note: to put stuff on the stack, we use Absolute,X addressing mode which is 3 bytes / 4 cycles
|
||||
// possible space optimization is to use zeropage (indirect),Y which is 2 bytes, but 5 cycles
|
||||
|
||||
|
||||
import prog8.ast.DataType
|
||||
import prog8.ast.Register
|
||||
import prog8.compiler.*
|
||||
@ -312,9 +316,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
else throw AssemblyError("invalid array type")
|
||||
}
|
||||
|
||||
// note: to put stuff on the stack, we use Absolute,X addressing mode which is 3 bytes / 4 cycles
|
||||
// possible space optimization is to use zeropage (indirect),Y which is 2 bytes, but 5 cycles
|
||||
|
||||
private fun instr2asm(ins: List<Instruction>): Int {
|
||||
// find best patterns (matching the most of the lines, then with the smallest weight)
|
||||
val fragments = findPatterns(ins).sortedWith(compareBy({it.segmentSize}, {it.prio}))
|
||||
@ -373,6 +374,13 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
Opcode.DISCARD_WORD -> " inx"
|
||||
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
|
||||
Opcode.INLINE_ASSEMBLY -> ins.callLabel ?: "" // All of the inline assembly is stored in the calllabel property.
|
||||
Opcode.PUSH_BYTE -> {
|
||||
" lda #${ins.arg!!.integerValue().toHex()} | sta $ESTACK_LO,x | dex"
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
val value = ins.arg!!.integerValue().toHex()
|
||||
" lda #<$value | sta $ESTACK_LO,x | lda #>$value | sta $ESTACK_HI,x | dex"
|
||||
}
|
||||
Opcode.COPY_VAR_BYTE -> {
|
||||
when {
|
||||
ins.callLabel2 in registerStrings -> {
|
||||
@ -574,34 +582,94 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
(opcodes[0]==Opcode.PUSH_BYTE && opcodes[1]==Opcode.READ_INDEXED_VAR_WORD &&
|
||||
opcodes[3]==Opcode.PUSH_BYTE && opcodes[4]==Opcode.WRITE_INDEXED_VAR_WORD)) {
|
||||
if(segment[0].arg==segment[3].arg && segment[1].callLabel==segment[4].callLabel) {
|
||||
val fragment = sameIndexedVarOperation(segment[1].callLabel!!, segment[0].arg!!.integerValue(), segment[2])
|
||||
val fragment = sameConstantIndexedVarOperation(segment[1].callLabel!!, segment[0].arg!!.integerValue(), segment[2])
|
||||
if(fragment!=null){
|
||||
fragment.segmentSize = 5
|
||||
result.add(fragment)
|
||||
}
|
||||
}
|
||||
}
|
||||
for(pattern in patterns.filter { opcodes.subList(0, it.sequence.size) == it.sequence }) {
|
||||
val asm = pattern.asm(segment)
|
||||
if(asm!=null)
|
||||
result.add(AsmFragment(asm, pattern.prio, pattern.sequence.size))
|
||||
else if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[1]==Opcode.READ_INDEXED_VAR_BYTE &&
|
||||
opcodes[3]==Opcode.PUSH_VAR_BYTE && opcodes[4]==Opcode.WRITE_INDEXED_VAR_BYTE) ||
|
||||
(opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[1]==Opcode.READ_INDEXED_VAR_WORD &&
|
||||
opcodes[3]==Opcode.PUSH_VAR_BYTE && opcodes[4]==Opcode.WRITE_INDEXED_VAR_WORD)) {
|
||||
if(segment[0].callLabel==segment[3].callLabel && segment[1].callLabel==segment[4].callLabel) {
|
||||
val fragment = sameIndexedVarOperation(segment[1].callLabel!!, segment[0].callLabel!!, segment[2])
|
||||
if(fragment!=null){
|
||||
fragment.segmentSize = 5
|
||||
result.add(fragment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(pattern in patterns.filter { it.sequence.size <= segment.size}) {
|
||||
if(pattern.sequence == opcodes.subList(0, pattern.sequence.size)) {
|
||||
val asm = pattern.asm(segment)
|
||||
if(asm!=null)
|
||||
result.add(AsmFragment(asm, pattern.prio, pattern.sequence.size))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun sameIndexedVarOperation(variable: String, index: Int, ins: Instruction): AsmFragment? {
|
||||
val idx = index.toHex()
|
||||
private fun sameConstantIndexedVarOperation(variable: String, index: Int, ins: Instruction): AsmFragment? {
|
||||
return when(ins.opcode) {
|
||||
Opcode.SHL_BYTE -> AsmFragment(" txa | ldx #$idx | asl $variable,x | tax", 10)
|
||||
Opcode.SHR_BYTE -> AsmFragment(" txa | ldx #$idx | lsr $variable,x | tax", 10)
|
||||
Opcode.SHL_WORD -> AsmFragment(" txa | ldx #$idx | asl $variable,x | rol $variable+1,x | tax", 10)
|
||||
Opcode.SHR_WORD -> AsmFragment(" txa | ldx #$idx | lsr $variable+1,x | ror $variable,x | tax", 10)
|
||||
Opcode.ROL_BYTE -> AsmFragment(" txa | ldx #$idx | rol $variable,x | tax", 10)
|
||||
Opcode.ROR_BYTE -> AsmFragment(" txa | ldx #$idx | ror $variable,x | tax", 10)
|
||||
Opcode.ROL_WORD -> AsmFragment(" txa | ldx #$idx | rol $variable,x | rol $variable+1,x | tax", 10)
|
||||
Opcode.ROR_WORD -> AsmFragment(" txa | ldx #$idx | ror $variable+1,x | ror $variable,x | tax", 10)
|
||||
Opcode.ROL2_BYTE -> AsmFragment(" stx ${C64Zeropage.SCRATCH_B1} | ldx #$idx | lda $variable,x | cmp #\$80 | rol $variable,x | ldx ${C64Zeropage.SCRATCH_B1}", 10)
|
||||
Opcode.ROR2_BYTE -> AsmFragment(" stx ${C64Zeropage.SCRATCH_B1} | ldx #$idx | lda $variable,x | lsr a | bcc + | ora #\$80 |+ | sta $variable,x | ldx ${C64Zeropage.SCRATCH_B1}", 10)
|
||||
Opcode.SHL_BYTE -> AsmFragment(" asl $variable+$index", 8)
|
||||
Opcode.SHR_BYTE -> AsmFragment(" lsr $variable+$index", 8)
|
||||
Opcode.SHL_WORD -> AsmFragment(" asl $variable+$index | rol $variable+$index+1", 8)
|
||||
Opcode.SHR_WORD -> AsmFragment(" lsr $variable+$index+1,x | ror $variable+$index", 8)
|
||||
Opcode.ROL_BYTE -> AsmFragment(" rol $variable+$index", 8)
|
||||
Opcode.ROR_BYTE -> AsmFragment(" ror $variable+$index", 8)
|
||||
Opcode.ROL_WORD -> AsmFragment(" rol $variable+$index | rol $variable+$index+1", 8)
|
||||
Opcode.ROR_WORD -> AsmFragment(" ror $variable+$index+1 | ror $variable+$index", 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 | rol $variable+$index+1 | bcc + | inc $variable+$index |+",20)
|
||||
Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+$index+1 | ror $variable+$index | bcc + | lda $variable+$index+1 | ora #\$80 | sta $variable+$index+1 |+", 30)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun sameIndexedVarOperation(variable: String, indexVar: String, ins: Instruction): AsmFragment? {
|
||||
val saveX = " stx ${C64Zeropage.SCRATCH_B1} |" // todo optimize to TXA when possible
|
||||
val restoreX = " | ldx ${C64Zeropage.SCRATCH_B1}"
|
||||
var loadX = ""
|
||||
var loadXWord = ""
|
||||
|
||||
when(indexVar) {
|
||||
"X" -> {
|
||||
loadXWord = " txa | asl a | tax |"
|
||||
}
|
||||
"Y" -> {
|
||||
loadX = " tya | tax |"
|
||||
loadXWord = " tya | asl a | tax |"
|
||||
}
|
||||
"A" -> {
|
||||
loadX = " tax |"
|
||||
loadXWord = " asl a | tax |"
|
||||
}
|
||||
"AX", "AY", "XY" -> throw AssemblyError("cannot index with word/registerpair")
|
||||
else -> {
|
||||
// the indexvar is a real variable, not a register
|
||||
loadX = " ldx $indexVar |"
|
||||
loadXWord = " lda $indexVar | asl a | tax |"
|
||||
}
|
||||
}
|
||||
|
||||
return when (ins.opcode) {
|
||||
Opcode.SHL_BYTE -> AsmFragment("$saveX $loadX asl $variable,x $restoreX", 10)
|
||||
Opcode.SHR_BYTE -> AsmFragment("$saveX $loadX lsr $variable,x $restoreX", 10)
|
||||
Opcode.SHL_WORD -> AsmFragment("$saveX $loadXWord asl $variable,x | rol $variable+1,x $restoreX", 10)
|
||||
Opcode.SHR_WORD -> AsmFragment("$saveX $loadXWord lsr $variable+1,x | ror $variable,x $restoreX", 10)
|
||||
Opcode.ROL_BYTE -> AsmFragment("$saveX $loadX rol $variable,x $restoreX", 10)
|
||||
Opcode.ROR_BYTE -> AsmFragment("$saveX $loadX ror $variable,x $restoreX", 10)
|
||||
Opcode.ROL_WORD -> AsmFragment("$saveX $loadXWord rol $variable,x | rol $variable+1,x $restoreX", 10)
|
||||
Opcode.ROR_WORD -> AsmFragment("$saveX $loadXWord ror $variable+1,x | ror $variable,x $restoreX", 10)
|
||||
Opcode.ROL2_BYTE -> AsmFragment("$saveX $loadX lda $variable,x | cmp #\$80 | rol $variable,x $restoreX", 10)
|
||||
Opcode.ROR2_BYTE -> AsmFragment("$saveX $loadX lda $variable,x | lsr a | bcc + | ora #\$80 |+ | sta $variable,x $restoreX", 10)
|
||||
Opcode.ROL2_WORD -> AsmFragment("$saveX $loadXWord asl $variable,x | rol $variable+1,x | bcc + | inc $variable,x |+ $restoreX", 30)
|
||||
Opcode.ROR2_WORD -> AsmFragment("$saveX $loadXWord lsr $variable+1,x | ror $variable,x | bcc + | lda $variable+1,x | ora #\$80 | sta $variable+1,x |+ $restoreX", 30)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -620,6 +688,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
Opcode.ROR_WORD -> AsmFragment(" ror $addrHi | ror $addr", 10)
|
||||
Opcode.ROL2_BYTE -> AsmFragment(" lda $addr | cmp #\$80 | rol $addr", 10)
|
||||
Opcode.ROR2_BYTE -> AsmFragment(" lda $addr | lsr a | bcc + | ora #\$80 |+ | sta $addr", 10)
|
||||
Opcode.ROL2_WORD -> AsmFragment(" lda $addr | cmp #\$80 | rol $addr | rol $addrHi", 10)
|
||||
Opcode.ROR2_WORD -> AsmFragment(" lsr $addrHi | ror $addr | bcc + | lda $addrHi | ora #$80 | sta $addrHi |+", 20)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -692,10 +762,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
}
|
||||
Opcode.ROL2_BYTE -> { // 8-bit rol
|
||||
when (variable) {
|
||||
"A" -> AsmFragment(" cmp #$80 | rol a", 10)
|
||||
"X" -> AsmFragment(" txa | cmp #$80 | rol a | tax", 10)
|
||||
"Y" -> AsmFragment(" tya | cmp #$80 | rol a | tay", 10)
|
||||
else -> AsmFragment(" lda $variable | cmp #$80 | rol $variable", 10)
|
||||
"A" -> AsmFragment(" cmp #\$80 | rol a", 10)
|
||||
"X" -> AsmFragment(" txa | cmp #\$80 | rol a | tax", 10)
|
||||
"Y" -> AsmFragment(" tya | cmp #\$80 | rol a | tay", 10)
|
||||
else -> AsmFragment(" lda $variable | cmp #\$80 | rol $variable", 10)
|
||||
}
|
||||
}
|
||||
Opcode.ROR2_BYTE -> { // 8-bit ror
|
||||
@ -706,6 +776,23 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
else -> AsmFragment(" lda $variable | lsr a | bcc + | ora #\$80 |+ | sta $variable", 10)
|
||||
}
|
||||
}
|
||||
Opcode.ROL2_WORD -> {
|
||||
when(variable) {
|
||||
"AX" -> AsmFragment(" cmp #\$80 | rol a | tay | txa | rol a | tax | tya", 10)
|
||||
"AY" -> AsmFragment(" sty ${C64Zeropage.SCRATCH_B1} | cmp #\$80 | rol a | rol ${C64Zeropage.SCRATCH_B1} | ldy ${C64Zeropage.SCRATCH_B1} ", 10)
|
||||
"XY" -> AsmFragment(" sty ${C64Zeropage.SCRATCH_B1} | txa | cmp #\$80 | rol a | rol ${C64Zeropage.SCRATCH_B1} | ldy ${C64Zeropage.SCRATCH_B1} | tax", 10)
|
||||
else -> 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
|
||||
when(variable) {
|
||||
"AX" -> AsmFragment(" sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | lda ${C64Zeropage.SCRATCH_W1} | ldx ${C64Zeropage.SCRATCH_W1+1}", 20)
|
||||
"AY" -> AsmFragment(" sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | lda ${C64Zeropage.SCRATCH_W1} | ldy ${C64Zeropage.SCRATCH_W1+1}", 20)
|
||||
"XY" -> AsmFragment(" stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | ldx ${C64Zeropage.SCRATCH_W1} | ldy ${C64Zeropage.SCRATCH_W1+1}", 20)
|
||||
else -> 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)
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -714,216 +801,28 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
|
||||
class AsmPattern(val sequence: List<Opcode>, val prio: Int, val asm: (List<Instruction>)->String?)
|
||||
|
||||
|
||||
private val patterns = listOf<AsmPattern>(
|
||||
private val patterns = listOf(
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_VAR_BYTE), 10) { segment ->
|
||||
when (segment[1].callLabel) {
|
||||
"A", "X", "Y" -> " ld${segment[1].callLabel!!.toLowerCase()} #${segment[0].arg!!.integerValue().toHex()}"
|
||||
else -> null
|
||||
}
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_VAR_WORD), 10) { segment ->
|
||||
val number = segment[0].arg!!.integerValue().toHex()
|
||||
when (segment[1].callLabel) {
|
||||
"AX" -> " lda #<$number | ldx #>$number"
|
||||
"AY" -> " lda #<$number | ldy #>$number"
|
||||
"XY" -> " ldx #<$number | ldy #>$number"
|
||||
else -> null
|
||||
}
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE), 10) { segment ->
|
||||
val index = segment[0].arg!!.integerValue()
|
||||
when (segment[2].callLabel) {
|
||||
"A", "X", "Y" -> " ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
/*
|
||||
private fun oldinstr2asm(insIdx: Int, ins: Instruction, block: IntermediateProgram.ProgramBlock): Int {
|
||||
when(ins.opcode) {
|
||||
Opcode.PUSH_BYTE -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_BYTE)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_BYTE) {
|
||||
if(nextIns.callLabel in registerStrings) {
|
||||
// load a register with constant value
|
||||
out("\tld${nextIns.callLabel!!.toLowerCase()} #${ins.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// load a variable with a constant value
|
||||
out("\tlda #${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_B || nextIns.opcode==Opcode.POP_MEM_UB) {
|
||||
// memory location = constant value
|
||||
out("\tlda #${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte onto stack
|
||||
pushByte(ins.arg!!.integerValue())
|
||||
}
|
||||
Opcode.PUSH_MEM_UB, Opcode.PUSH_MEM_B -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_BYTE)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_BYTE) {
|
||||
if(nextIns.callLabel in registerStrings) {
|
||||
// load a register with memory location
|
||||
out("\tld${nextIns.callLabel!!.toLowerCase()} ${ins.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// load var with mem b
|
||||
out("\tlda ${ins.arg!!.integerValue().toHex()}\n\tsta ${nextIns.callLabel}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_B || nextIns.opcode==Opcode.POP_MEM_UB) {
|
||||
// copy byte from mem -> mem
|
||||
out("\tlda ${ins.arg!!.integerValue().toHex()}\n\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte from memory onto stack
|
||||
pushMemByte(ins.arg!!.integerValue())
|
||||
}
|
||||
Opcode.PUSH_VAR_BYTE -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_BYTE)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_BYTE)
|
||||
throw CompilerException("push var+pop var should have been replaced by copy var")
|
||||
if(nextIns.opcode==Opcode.POP_MEM_B || nextIns.opcode==Opcode.POP_MEM_UB) {
|
||||
// copy byte from var -> mem
|
||||
out("\tlda ${ins.callLabel}\n\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte from variable onto stack
|
||||
when(ins.callLabel) {
|
||||
"A" -> pushByteA()
|
||||
"X" -> throw CompilerException("makes no sense to push X it's used as a stack pointer itself")
|
||||
"Y" -> pushByteY()
|
||||
else -> pushVarByte(ins.callLabel!!)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_WORD)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_WORD) {
|
||||
val value = ins.arg!!.integerValue()
|
||||
if(nextIns.callLabel in registerStrings) {
|
||||
// we load a register (AX, AY, XY) with constant value
|
||||
val regs = nextIns.callLabel!!.toLowerCase()
|
||||
out("\tld${regs[0]} #<${value.toHex()}")
|
||||
out("\tld${regs[1]} #>${value.toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// load a word variable with a constant value
|
||||
out("\tlda #<${value.toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}")
|
||||
out("\tlda #>${value.toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}+1")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_W || nextIns.opcode==Opcode.POP_MEM_UW) {
|
||||
// we're loading a word into memory
|
||||
out("\tlda #<${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
out("\tlda #>${ins.arg.integerValue().toHex()}")
|
||||
out("\tsta ${(nextIns.arg.integerValue()+1).toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(ins.arg!!.type in StringDatatypes) {
|
||||
TODO("strings from heap")
|
||||
}
|
||||
pushWord(ins.arg.integerValue())
|
||||
}
|
||||
Opcode.PUSH_MEM_UW, Opcode.PUSH_MEM_W -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_WORD)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_WORD) {
|
||||
if(nextIns.callLabel in registerStrings) {
|
||||
// load a register (AX, AY, XY) with word from memory
|
||||
val regs = nextIns.callLabel!!.toLowerCase()
|
||||
val value = ins.arg!!.integerValue()
|
||||
out("\tld${regs[0]} ${value.toHex()}")
|
||||
out("\tld${regs[1]} ${(value + 1).toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// load var with mem word
|
||||
out("\tlda ${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}")
|
||||
out("\tlda ${(ins.arg.integerValue()+1).toHex()}")
|
||||
out("\tsta ${nextIns.callLabel}+1")
|
||||
return 1 // skip 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_W || nextIns.opcode==Opcode.POP_MEM_UW) {
|
||||
// copy word mem->mem
|
||||
out("\tlda ${ins.arg!!.integerValue().toHex()}")
|
||||
out("\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
out("\tlda ${(ins.arg.integerValue()+1).toHex()}")
|
||||
out("\tsta ${(nextIns.arg.integerValue()+1).toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// word from memory onto stack
|
||||
pushMemWord(ins.arg!!.integerValue())
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_FLOAT)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_WORD)
|
||||
throw CompilerException("push var+pop var should have been replaced by copy var")
|
||||
if(nextIns.opcode==Opcode.POP_MEM_W || nextIns.opcode==Opcode.POP_MEM_UW) {
|
||||
// copy word from var -> mem
|
||||
out("\tlda ${ins.callLabel}\n\tsta ${nextIns.arg!!.integerValue().toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
// word from memory onto stack
|
||||
when(ins.callLabel) {
|
||||
"AX" -> TODO()
|
||||
"AY" -> TODO()
|
||||
"XY" -> TODO()
|
||||
else -> pushVarWord(ins.callLabel!!)
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_FLOAT)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
val float = ins.arg!!.numericValue().toDouble()
|
||||
val label = globalFloatConsts[float]!!
|
||||
if(nextIns.opcode==Opcode.POP_MEM_FLOAT) {
|
||||
// set a float in memory to a constant float value
|
||||
copyFloat(label, nextIns.arg!!.integerValue().toHex())
|
||||
return 1
|
||||
} else if(nextIns.opcode==Opcode.POP_VAR_FLOAT) {
|
||||
// set a variable to a constant float value
|
||||
copyFloat(label, nextIns.callLabel!!)
|
||||
return 1
|
||||
}
|
||||
pushFloat(label)
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_FLOAT)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_FLOAT)
|
||||
throw CompilerException("push var+pop var should have been replaced by copy var")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
if(nextIns.opcode==Opcode.POP_MEM_FLOAT) {
|
||||
copyFloat(ins.callLabel!!, nextIns.arg!!.integerValue().toHex()) // copy var float to memory
|
||||
return 1
|
||||
}
|
||||
pushFloat(ins.callLabel!!)
|
||||
}
|
||||
Opcode.PUSH_MEM_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
if(nextIns==Opcode.DISCARD_FLOAT)
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_FLOAT) {
|
||||
copyFloat(ins.arg!!.integerValue().toHex(), nextIns.callLabel!!) // copy memory float to var
|
||||
return 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_FLOAT) {
|
||||
copyFloat(ins.arg!!.integerValue().toHex(), nextIns.arg!!.integerValue().toHex()) // copy memory float to memory float
|
||||
return 1
|
||||
}
|
||||
pushFloat(ins.arg!!.integerValue().toHex())
|
||||
}
|
||||
|
||||
else-> TODO("asm for $ins")
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package prog8.compiler.target.c64
|
||||
|
||||
import prog8.compiler.*
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.CompilerException
|
||||
import prog8.compiler.Zeropage
|
||||
import prog8.compiler.ZeropageType
|
||||
import java.awt.Color
|
||||
import java.awt.image.BufferedImage
|
||||
import javax.imageio.ImageIO
|
||||
|
@ -37,6 +37,9 @@ fun importModule(filePath: Path) : Module {
|
||||
|
||||
// process imports
|
||||
val lines = moduleAst.statements.toMutableList()
|
||||
// always import the prog8 compiler library
|
||||
if(!moduleAst.position.file.startsWith("prog8lib."))
|
||||
lines.add(0, Directive("%import", listOf(DirectiveArg(null, "prog8lib", null, moduleAst.position)), moduleAst.position))
|
||||
val imports = lines
|
||||
.asSequence()
|
||||
.mapIndexed { i, it -> Pair(i, it) }
|
||||
|
@ -153,10 +153,4 @@ class ScreenDialog : JFrame() {
|
||||
val repaintTimer = Timer(1000 / 60) { _ -> repaint() }
|
||||
repaintTimer.start()
|
||||
}
|
||||
|
||||
private fun onOK() {
|
||||
// add your code here
|
||||
dispose()
|
||||
System.exit(0)
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import prog8.ast.*
|
||||
import prog8.compiler.*
|
||||
import prog8.compiler.target.c64.*
|
||||
import prog8.compiler.intermediate.Value
|
||||
import prog8.compiler.target.c64.*
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertFalse
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
@ -7,270 +7,24 @@
|
||||
|
||||
~ prog8_lib {
|
||||
; note: the following ZP scratch registers must be the same as in c64lib
|
||||
memory byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
memory word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||
memory word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||
memory ubyte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory ubyte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
memory uword SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||
memory uword SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||
|
||||
|
||||
%asm {{
|
||||
; ---- jmp (indirect) routines for register pairs containing the indirect address
|
||||
; @todo still needed??
|
||||
jsr_indirect_nozpuse_AX
|
||||
sta jsr_indirect_tmp
|
||||
stx jsr_indirect_tmp+1
|
||||
jmp (jsr_indirect_tmp)
|
||||
jsr_indirect_nozpuse_AY
|
||||
sta jsr_indirect_tmp
|
||||
sty jsr_indirect_tmp+1
|
||||
jmp (jsr_indirect_tmp)
|
||||
jsr_indirect_nozpuse_XY
|
||||
stx jsr_indirect_tmp
|
||||
sty jsr_indirect_tmp+1
|
||||
jmp (jsr_indirect_tmp)
|
||||
jsr_indirect_tmp
|
||||
.byte 0, 0
|
||||
|
||||
|
||||
jsr_indirect_AX
|
||||
sta SCRATCH_ZP1
|
||||
stx SCRATCH_ZP2
|
||||
jmp (SCRATCH_ZP1)
|
||||
jsr_indirect_AY
|
||||
sta SCRATCH_ZP1
|
||||
sty SCRATCH_ZP2
|
||||
jmp (SCRATCH_ZP1)
|
||||
jsr_indirect_XY
|
||||
stx SCRATCH_ZP1
|
||||
sty SCRATCH_ZP2
|
||||
jmp (SCRATCH_ZP1)
|
||||
|
||||
|
||||
; copy memory UP from (SCRATCH_ZPWORD1) to (SCRATCH_ZPWORD2) of length X/Y (16-bit, X=lo, Y=hi)
|
||||
; clobbers register A,X,Y
|
||||
memcopy16_up
|
||||
source = SCRATCH_ZPWORD1
|
||||
dest = SCRATCH_ZPWORD2
|
||||
length = SCRATCH_ZP1 ; (and SCRATCH_ZP2)
|
||||
|
||||
stx length
|
||||
sty length+1
|
||||
|
||||
ldx length ; move low byte of length into X
|
||||
bne + ; jump to start if X > 0
|
||||
dec length ; subtract 1 from length
|
||||
+ ldy #0 ; set Y to 0
|
||||
- lda (source),y ; set A to whatever (source) points to offset by Y
|
||||
sta (dest),y ; move A to location pointed to by (dest) offset by Y
|
||||
iny ; increment Y
|
||||
bne + ; if Y<>0 then (rolled over) then still moving bytes
|
||||
inc source+1 ; increment hi byte of source
|
||||
inc dest+1 ; increment hi byte of dest
|
||||
+ dex ; decrement X (lo byte counter)
|
||||
bne - ; if X<>0 then move another byte
|
||||
dec length ; weve moved 255 bytes, dec length
|
||||
bpl - ; if length is still positive go back and move more
|
||||
rts ; done
|
||||
|
||||
|
||||
; copy memory UP from (SCRATCH_ZPWORD1) to (AY) with length X (1 to 256, 0 meaning 256)
|
||||
; destination must not overlap, or be before start, then overlap is possible.
|
||||
; clobbers A, X, Y
|
||||
|
||||
memcopy
|
||||
sta SCRATCH_ZPWORD2
|
||||
sty SCRATCH_ZPWORD2+1
|
||||
ldy #0
|
||||
- lda (SCRATCH_ZPWORD1), y
|
||||
sta (SCRATCH_ZPWORD2), y
|
||||
iny
|
||||
dex
|
||||
bne -
|
||||
rts
|
||||
|
||||
|
||||
; fill memory from (SCRATCH_ZPWORD1), length XY, with value in A.
|
||||
; clobbers X, Y
|
||||
memset stx SCRATCH_ZP1
|
||||
sty SCRATCH_ZP2
|
||||
ldy #0
|
||||
ldx SCRATCH_ZP2
|
||||
beq _lastpage
|
||||
|
||||
_fullpage sta (SCRATCH_ZPWORD1),y
|
||||
iny
|
||||
bne _fullpage
|
||||
inc SCRATCH_ZPWORD1+1 ; next page
|
||||
dex
|
||||
bne _fullpage
|
||||
|
||||
_lastpage ldy SCRATCH_ZP1
|
||||
beq +
|
||||
- dey
|
||||
sta (SCRATCH_ZPWORD1),y
|
||||
bne -
|
||||
|
||||
+ rts
|
||||
|
||||
|
||||
|
||||
; fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY.
|
||||
; clobbers A, X, Y
|
||||
memsetw
|
||||
sta _mod1+1 ; self-modify
|
||||
sty _mod1b+1 ; self-modify
|
||||
sta _mod2+1 ; self-modify
|
||||
sty _mod2b+1 ; self-modify
|
||||
ldx SCRATCH_ZPWORD1
|
||||
stx SCRATCH_ZP1
|
||||
ldx SCRATCH_ZPWORD1+1
|
||||
inx
|
||||
stx SCRATCH_ZP2 ; second page
|
||||
|
||||
ldy #0
|
||||
ldx SCRATCH_ZPWORD2+1
|
||||
beq _lastpage
|
||||
|
||||
_fullpage
|
||||
_mod1 lda #0 ; self-modified
|
||||
sta (SCRATCH_ZPWORD1),y ; first page
|
||||
sta (SCRATCH_ZP1),y ; second page
|
||||
iny
|
||||
_mod1b lda #0 ; self-modified
|
||||
sta (SCRATCH_ZPWORD1),y ; first page
|
||||
sta (SCRATCH_ZP1),y ; second page
|
||||
iny
|
||||
bne _fullpage
|
||||
inc SCRATCH_ZPWORD1+1 ; next page pair
|
||||
inc SCRATCH_ZPWORD1+1 ; next page pair
|
||||
inc SCRATCH_ZP1+1 ; next page pair
|
||||
inc SCRATCH_ZP1+1 ; next page pair
|
||||
dex
|
||||
bne _fullpage
|
||||
|
||||
_lastpage ldx SCRATCH_ZPWORD2
|
||||
beq _done
|
||||
|
||||
ldy #0
|
||||
-
|
||||
_mod2 lda #0 ; self-modified
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
inc SCRATCH_ZPWORD1
|
||||
bne _mod2b
|
||||
inc SCRATCH_ZPWORD1+1
|
||||
_mod2b lda #0 ; self-modified
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
inc SCRATCH_ZPWORD1
|
||||
bne +
|
||||
inc SCRATCH_ZPWORD1+1
|
||||
+ dex
|
||||
bne -
|
||||
_done rts
|
||||
|
||||
|
||||
; increments/decrements a byte referenced by indirect register pair by 1
|
||||
; clobbers A/Y, Carry flag determines incr or decr
|
||||
incrdecr_deref_byte_reg_AX
|
||||
sta SCRATCH_ZPWORD1
|
||||
stx SCRATCH_ZPWORD1+1
|
||||
bcc incr_deref_byte
|
||||
bcs decr_deref_byte
|
||||
incrdecr_deref_byte_reg_AY
|
||||
sta SCRATCH_ZPWORD1
|
||||
sty SCRATCH_ZPWORD1+1
|
||||
bcc incr_deref_byte
|
||||
bcs decr_deref_byte
|
||||
incrdecr_deref_byte_reg_XY
|
||||
stx SCRATCH_ZPWORD1
|
||||
sty SCRATCH_ZPWORD1+1
|
||||
bcs decr_deref_byte
|
||||
|
||||
incr_deref_byte
|
||||
ldy #0
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #1 ; carry's cleared already
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
decr_deref_byte
|
||||
ldy #0
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
sbc #1 ; carry's set already
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
|
||||
; increments/decrements a word referenced by indirect register pair by 1
|
||||
; clobbers A/Y, Carry flag determines incr or decr
|
||||
incrdecr_deref_word_reg_AX
|
||||
sta SCRATCH_ZPWORD1
|
||||
stx SCRATCH_ZPWORD1+1
|
||||
bcc incr_deref_word
|
||||
bcs decr_deref_word
|
||||
incrdecr_deref_word_reg_AY
|
||||
sta SCRATCH_ZPWORD1
|
||||
sty SCRATCH_ZPWORD1+1
|
||||
bcc incr_deref_word
|
||||
bcs decr_deref_word
|
||||
incrdecr_deref_word_reg_XY
|
||||
stx SCRATCH_ZPWORD1
|
||||
sty SCRATCH_ZPWORD1+1
|
||||
bcs decr_deref_word
|
||||
|
||||
incr_deref_word
|
||||
ldy #0
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #1 ; carry's cleared already
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
; 16-bit rotate right (as opposed to the 6502's usual 17-bit rotate with carry)
|
||||
; the word is placed in SCRATCH_ZPWORD1
|
||||
ror2_word
|
||||
lsr SCRATCH_ZPWORD1+1
|
||||
ror SCRATCH_ZPWORD1
|
||||
bcc +
|
||||
iny
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #0 ; carry is set
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
+ rts
|
||||
|
||||
decr_deref_word
|
||||
ldy #0
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
bne +
|
||||
pha
|
||||
iny
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
sbc #1 ; carry's set already
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
dey
|
||||
pla
|
||||
+ sec
|
||||
sbc #1
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
|
||||
|
||||
; shift bits in A right by X positions
|
||||
lsr_A_by_X
|
||||
cpx #8
|
||||
bcc _shift
|
||||
lda #0 ; x >=8, result always 0
|
||||
rts
|
||||
_shift cpx #0
|
||||
beq +
|
||||
- lsr a
|
||||
dex
|
||||
bne -
|
||||
lda SCRATCH_ZPWORD1+1
|
||||
ora #$80
|
||||
sta SCRATCH_ZPWORD1+1
|
||||
+ rts
|
||||
|
||||
|
||||
; shift bits in A left by X positions
|
||||
asl_A_by_X
|
||||
cpx #8
|
||||
bcc _shift
|
||||
lda #0 ; x >=8, result always 0
|
||||
rts
|
||||
_shift cpx #0
|
||||
beq +
|
||||
- asl a
|
||||
dex
|
||||
bne -
|
||||
+ rts
|
||||
|
||||
|
||||
}}
|
||||
}
|
||||
|
276
prog8lib/prog8lib_OLD.p8
Normal file
276
prog8lib/prog8lib_OLD.p8
Normal file
@ -0,0 +1,276 @@
|
||||
; Prog8 internal library routines - always included by the compiler
|
||||
;
|
||||
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||
;
|
||||
; indent format: TABS, size=8
|
||||
|
||||
|
||||
~ prog8_lib {
|
||||
; note: the following ZP scratch registers must be the same as in c64lib
|
||||
memory byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
memory word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||
memory word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||
|
||||
|
||||
%asm {{
|
||||
; ---- jmp (indirect) routines for register pairs containing the indirect address
|
||||
; @todo still needed??
|
||||
jsr_indirect_nozpuse_AX
|
||||
sta jsr_indirect_tmp
|
||||
stx jsr_indirect_tmp+1
|
||||
jmp (jsr_indirect_tmp)
|
||||
jsr_indirect_nozpuse_AY
|
||||
sta jsr_indirect_tmp
|
||||
sty jsr_indirect_tmp+1
|
||||
jmp (jsr_indirect_tmp)
|
||||
jsr_indirect_nozpuse_XY
|
||||
stx jsr_indirect_tmp
|
||||
sty jsr_indirect_tmp+1
|
||||
jmp (jsr_indirect_tmp)
|
||||
jsr_indirect_tmp
|
||||
.byte 0, 0
|
||||
|
||||
|
||||
jsr_indirect_AX
|
||||
sta SCRATCH_ZP1
|
||||
stx SCRATCH_ZP2
|
||||
jmp (SCRATCH_ZP1)
|
||||
jsr_indirect_AY
|
||||
sta SCRATCH_ZP1
|
||||
sty SCRATCH_ZP2
|
||||
jmp (SCRATCH_ZP1)
|
||||
jsr_indirect_XY
|
||||
stx SCRATCH_ZP1
|
||||
sty SCRATCH_ZP2
|
||||
jmp (SCRATCH_ZP1)
|
||||
|
||||
|
||||
; copy memory UP from (SCRATCH_ZPWORD1) to (SCRATCH_ZPWORD2) of length X/Y (16-bit, X=lo, Y=hi)
|
||||
; clobbers register A,X,Y
|
||||
memcopy16_up
|
||||
source = SCRATCH_ZPWORD1
|
||||
dest = SCRATCH_ZPWORD2
|
||||
length = SCRATCH_ZP1 ; (and SCRATCH_ZP2)
|
||||
|
||||
stx length
|
||||
sty length+1
|
||||
|
||||
ldx length ; move low byte of length into X
|
||||
bne + ; jump to start if X > 0
|
||||
dec length ; subtract 1 from length
|
||||
+ ldy #0 ; set Y to 0
|
||||
- lda (source),y ; set A to whatever (source) points to offset by Y
|
||||
sta (dest),y ; move A to location pointed to by (dest) offset by Y
|
||||
iny ; increment Y
|
||||
bne + ; if Y<>0 then (rolled over) then still moving bytes
|
||||
inc source+1 ; increment hi byte of source
|
||||
inc dest+1 ; increment hi byte of dest
|
||||
+ dex ; decrement X (lo byte counter)
|
||||
bne - ; if X<>0 then move another byte
|
||||
dec length ; weve moved 255 bytes, dec length
|
||||
bpl - ; if length is still positive go back and move more
|
||||
rts ; done
|
||||
|
||||
|
||||
; copy memory UP from (SCRATCH_ZPWORD1) to (AY) with length X (1 to 256, 0 meaning 256)
|
||||
; destination must not overlap, or be before start, then overlap is possible.
|
||||
; clobbers A, X, Y
|
||||
|
||||
memcopy
|
||||
sta SCRATCH_ZPWORD2
|
||||
sty SCRATCH_ZPWORD2+1
|
||||
ldy #0
|
||||
- lda (SCRATCH_ZPWORD1), y
|
||||
sta (SCRATCH_ZPWORD2), y
|
||||
iny
|
||||
dex
|
||||
bne -
|
||||
rts
|
||||
|
||||
|
||||
; fill memory from (SCRATCH_ZPWORD1), length XY, with value in A.
|
||||
; clobbers X, Y
|
||||
memset stx SCRATCH_ZP1
|
||||
sty SCRATCH_ZP2
|
||||
ldy #0
|
||||
ldx SCRATCH_ZP2
|
||||
beq _lastpage
|
||||
|
||||
_fullpage sta (SCRATCH_ZPWORD1),y
|
||||
iny
|
||||
bne _fullpage
|
||||
inc SCRATCH_ZPWORD1+1 ; next page
|
||||
dex
|
||||
bne _fullpage
|
||||
|
||||
_lastpage ldy SCRATCH_ZP1
|
||||
beq +
|
||||
- dey
|
||||
sta (SCRATCH_ZPWORD1),y
|
||||
bne -
|
||||
|
||||
+ rts
|
||||
|
||||
|
||||
|
||||
; fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY.
|
||||
; clobbers A, X, Y
|
||||
memsetw
|
||||
sta _mod1+1 ; self-modify
|
||||
sty _mod1b+1 ; self-modify
|
||||
sta _mod2+1 ; self-modify
|
||||
sty _mod2b+1 ; self-modify
|
||||
ldx SCRATCH_ZPWORD1
|
||||
stx SCRATCH_ZP1
|
||||
ldx SCRATCH_ZPWORD1+1
|
||||
inx
|
||||
stx SCRATCH_ZP2 ; second page
|
||||
|
||||
ldy #0
|
||||
ldx SCRATCH_ZPWORD2+1
|
||||
beq _lastpage
|
||||
|
||||
_fullpage
|
||||
_mod1 lda #0 ; self-modified
|
||||
sta (SCRATCH_ZPWORD1),y ; first page
|
||||
sta (SCRATCH_ZP1),y ; second page
|
||||
iny
|
||||
_mod1b lda #0 ; self-modified
|
||||
sta (SCRATCH_ZPWORD1),y ; first page
|
||||
sta (SCRATCH_ZP1),y ; second page
|
||||
iny
|
||||
bne _fullpage
|
||||
inc SCRATCH_ZPWORD1+1 ; next page pair
|
||||
inc SCRATCH_ZPWORD1+1 ; next page pair
|
||||
inc SCRATCH_ZP1+1 ; next page pair
|
||||
inc SCRATCH_ZP1+1 ; next page pair
|
||||
dex
|
||||
bne _fullpage
|
||||
|
||||
_lastpage ldx SCRATCH_ZPWORD2
|
||||
beq _done
|
||||
|
||||
ldy #0
|
||||
-
|
||||
_mod2 lda #0 ; self-modified
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
inc SCRATCH_ZPWORD1
|
||||
bne _mod2b
|
||||
inc SCRATCH_ZPWORD1+1
|
||||
_mod2b lda #0 ; self-modified
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
inc SCRATCH_ZPWORD1
|
||||
bne +
|
||||
inc SCRATCH_ZPWORD1+1
|
||||
+ dex
|
||||
bne -
|
||||
_done rts
|
||||
|
||||
|
||||
; increments/decrements a byte referenced by indirect register pair by 1
|
||||
; clobbers A/Y, Carry flag determines incr or decr
|
||||
incrdecr_deref_byte_reg_AX
|
||||
sta SCRATCH_ZPWORD1
|
||||
stx SCRATCH_ZPWORD1+1
|
||||
bcc incr_deref_byte
|
||||
bcs decr_deref_byte
|
||||
incrdecr_deref_byte_reg_AY
|
||||
sta SCRATCH_ZPWORD1
|
||||
sty SCRATCH_ZPWORD1+1
|
||||
bcc incr_deref_byte
|
||||
bcs decr_deref_byte
|
||||
incrdecr_deref_byte_reg_XY
|
||||
stx SCRATCH_ZPWORD1
|
||||
sty SCRATCH_ZPWORD1+1
|
||||
bcs decr_deref_byte
|
||||
|
||||
incr_deref_byte
|
||||
ldy #0
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #1 ; carry's cleared already
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
decr_deref_byte
|
||||
ldy #0
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
sbc #1 ; carry's set already
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
|
||||
; increments/decrements a word referenced by indirect register pair by 1
|
||||
; clobbers A/Y, Carry flag determines incr or decr
|
||||
incrdecr_deref_word_reg_AX
|
||||
sta SCRATCH_ZPWORD1
|
||||
stx SCRATCH_ZPWORD1+1
|
||||
bcc incr_deref_word
|
||||
bcs decr_deref_word
|
||||
incrdecr_deref_word_reg_AY
|
||||
sta SCRATCH_ZPWORD1
|
||||
sty SCRATCH_ZPWORD1+1
|
||||
bcc incr_deref_word
|
||||
bcs decr_deref_word
|
||||
incrdecr_deref_word_reg_XY
|
||||
stx SCRATCH_ZPWORD1
|
||||
sty SCRATCH_ZPWORD1+1
|
||||
bcs decr_deref_word
|
||||
|
||||
incr_deref_word
|
||||
ldy #0
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #1 ; carry's cleared already
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
bcc +
|
||||
iny
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #0 ; carry is set
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
+ rts
|
||||
|
||||
decr_deref_word
|
||||
ldy #0
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
bne +
|
||||
pha
|
||||
iny
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
sbc #1 ; carry's set already
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
dey
|
||||
pla
|
||||
+ sec
|
||||
sbc #1
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
|
||||
|
||||
; shift bits in A right by X positions
|
||||
lsr_A_by_X
|
||||
cpx #8
|
||||
bcc _shift
|
||||
lda #0 ; x >=8, result always 0
|
||||
rts
|
||||
_shift cpx #0
|
||||
beq +
|
||||
- lsr a
|
||||
dex
|
||||
bne -
|
||||
+ rts
|
||||
|
||||
|
||||
; shift bits in A left by X positions
|
||||
asl_A_by_X
|
||||
cpx #8
|
||||
bcc _shift
|
||||
lda #0 ; x >=8, result always 0
|
||||
rts
|
||||
_shift cpx #0
|
||||
beq +
|
||||
- asl a
|
||||
dex
|
||||
bne -
|
||||
+ rts
|
||||
|
||||
|
||||
}}
|
||||
}
|
Loading…
Reference in New Issue
Block a user