optimized stuff

This commit is contained in:
Irmen de Jong 2019-01-09 00:25:02 +01:00
parent 58854ef45b
commit 0ab0f02e75
11 changed files with 152 additions and 177 deletions

View File

@ -9,7 +9,6 @@
~ c64flt {
; ---- this block contains C-64 floating point related functions ----
; @todo enable float-checkin astchecker.process(decl: VarDecl) again
const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586
@ -192,54 +191,31 @@ asmsub GETADRAY () -> clobbers(X) -> (uword @ AY) {
}}
}
sub print_f (float value) {
asmsub print_f (float value @ AY) -> clobbers(A, Y) -> () {
; ---- prints the floating point value (without a newline) using basic rom routines.
; clobbers no registers.
; @todo version that takes A/Y pointer to float instead
%asm {{
pha
tya
pha
txa
pha
lda #<print_f_value
ldy #>print_f_value
stx c64.SCRATCH_ZPREGX
jsr c64flt.MOVFM ; load float into fac1
jsr c64flt.FOUT ; fac1 to string in A/Y
jsr c64.STROUT ; print string in A/Y
pla
tax
pla
tay
pla
ldx c64.SCRATCH_ZPREGX
rts
}}
}
sub print_fln (float value) {
asmsub print_fln (float value @ AY) -> clobbers(A, Y) -> () {
; ---- prints the floating point value (with a newline at the end) using basic rom routines
; clobbers no registers.
; @todo version that takes A/Y pointer to float instead
%asm {{
pha
tya
pha
txa
pha
lda #<print_fln_value
ldy #>print_fln_value
stx c64.SCRATCH_ZPREGX
jsr c64flt.MOVFM ; load float into fac1
jsr c64flt.FPRINTLN ; print fac1 with newline
pla
tax
pla
tay
pla
ldx c64.SCRATCH_ZPREGX
rts
}}
}
; --- low level floating point assembly routines
%asm {{
ub2float .proc

View File

@ -42,6 +42,7 @@
memory ubyte SPRPTR5 = 2045
memory ubyte SPRPTR6 = 2046
memory ubyte SPRPTR7 = 2047
memory ubyte[8] SPRPTR = 2040
; ---- VIC-II registers ----
@ -62,6 +63,7 @@
memory ubyte SP6Y = $d00d
memory ubyte SP7X = $d00e
memory ubyte SP7Y = $d00f
memory ubyte[16] SPXY = $d000
memory ubyte MSIGX = $d010
memory ubyte SCROLY = $d011
@ -95,6 +97,8 @@
memory ubyte SP5COL = $d02c
memory ubyte SP6COL = $d02d
memory ubyte SP7COL = $d02e
memory ubyte[8] SPCOL = $d027
; ---- end of VIC-II registers ----

View File

@ -364,7 +364,7 @@ lesseq_ub .proc
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
bcc equal_b._equal_b_true
beq equal_b._equal_b_true ; @todo optimize by flipping comparison
beq equal_b._equal_b_true ; @todo optimize by flipping comparison?
bcs equal_b._equal_b_false
.pend

View File

@ -272,7 +272,8 @@ class AstChecker(private val namespace: INameScope,
err("parameter '${param.first.name}' should be (u)byte")
}
else if(param.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
if (param.first.type != DataType.UWORD && param.first.type != DataType.WORD && param.first.type !in StringDatatypes && param.first.type !in ArrayDatatypes)
if (param.first.type != DataType.UWORD && param.first.type != DataType.WORD
&& param.first.type !in StringDatatypes && param.first.type !in ArrayDatatypes && param.first.type != DataType.FLOAT)
err("parameter '${param.first.name}' should be (u)word/address")
}
else if(param.second.statusflag!=null) {
@ -286,7 +287,8 @@ class AstChecker(private val namespace: INameScope,
err("return value #${ret.first.index + 1} should be (u)byte")
}
else if(ret.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
if (ret.first.value != DataType.UWORD && ret.first.value != DataType.WORD && ret.first.value !in StringDatatypes && ret.first.value !in ArrayDatatypes)
if (ret.first.value != DataType.UWORD && ret.first.value != DataType.WORD
&& ret.first.value !in StringDatatypes && ret.first.value !in ArrayDatatypes && ret.first.value != DataType.FLOAT)
err("return value #${ret.first.index + 1} should be (u)word/address")
}
else if(ret.second.statusflag!=null) {

View File

@ -967,6 +967,10 @@ private class StatementTranslator(private val prog: IntermediateProgram,
pushStringAddress(arg.first, false) // TODO with or without remove last opcode??
prog.instr(Opcode.POP_REGAX_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGAX_WORD)
}
else -> TODO("pass parameter of type $paramDt in registers AX at $callPosition")
}
}
@ -993,6 +997,10 @@ private class StatementTranslator(private val prog: IntermediateProgram,
pushStringAddress(arg.first, false) // TODO with or without remove last opcode??
prog.instr(Opcode.POP_REGAY_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGAY_WORD)
}
else -> TODO("pass parameter of type $paramDt in registers AY at $callPosition")
}
}
@ -1023,6 +1031,10 @@ private class StatementTranslator(private val prog: IntermediateProgram,
pushStringAddress(arg.first, false) // TODO with or without remove last opcode??
prog.instr(Opcode.POP_REGXY_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGXY_WORD)
}
else -> TODO("pass parameter of type $paramDt in registers XY at $callPosition")
}
}
@ -1485,6 +1497,19 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
}
private fun pushFloatAddress(value: IExpression) {
when (value) {
is LiteralValue -> {
prog.instr(Opcode.PUSH_ADDR_FLOAT, Value(value.type, value.floatvalue!!))
}
is IdentifierReference -> {
val vardecl = value.targetStatement(namespace) as VarDecl
prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname)
}
else -> throw CompilerException("literal float value or float variable expected")
}
}
private fun translateMultiReturnAssignment(stmt: Assignment) {
val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace)
if(targetStmt is Subroutine && targetStmt.isAsmSubroutine) {

View File

@ -19,6 +19,7 @@ enum class Opcode {
PUSH_REGAY_WORD, // push registers A/Y as a 16-bit word
PUSH_REGXY_WORD, // push registers X/Y as a 16-bit word
PUSH_ADDR_STR, // push the address of the string value (literal)
PUSH_ADDR_FLOAT, // push the address of the float value (literal)
PUSH_ADDR_HEAPVAR, // push the address of the variable that's on the heap (string or array)
// popping values off the (evaluation) stack, possibly storing them in another location

View File

@ -536,6 +536,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.PUSH_ADDR_HEAPVAR -> {
" lda #<${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | lda #>${ins.callLabel} | sta ${ESTACK_HI.toHex()},x | dex"
}
Opcode.PUSH_ADDR_FLOAT -> {
val varname = getFloatConst(ins.arg!!)
" lda #<$varname | sta ${ESTACK_LO.toHex()},x | lda #>$varname | sta ${ESTACK_HI.toHex()},x | dex"
}
Opcode.POP_REGAX_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself")
Opcode.POP_REGXY_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself")
Opcode.POP_REGAY_WORD -> {
@ -570,9 +574,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.WRITE_INDEXED_VAR_BYTE -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
inx
ldy ${ESTACK_LO.toHex()},x
inx
lda ${ESTACK_LO.toHex()},x
sta ${ins.callLabel},y
"""
}
@ -701,6 +705,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
Opcode.INC_MEMORY -> " inc ${hexVal(ins)}"
Opcode.DEC_MEMORY -> " dec ${hexVal(ins)}"
Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> " inx | txa | pha | lda ${ESTACK_LO.toHex()},x | tax | inc ${ins.callLabel},x | pla | tax"
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> " inx | txa | pha | lda ${ESTACK_LO.toHex()},x | tax | dec ${ins.callLabel},x | pla | tax"
Opcode.NEG_B -> " jsr prog8_lib.neg_b"
Opcode.NEG_W -> " jsr prog8_lib.neg_w"
Opcode.NEG_F -> " jsr c64flt.neg_f"
@ -1034,10 +1041,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> AsmFragment(" txa | $loadX inc $variable,x | tax", 10)
Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> AsmFragment(" txa | $loadX dec $variable,x | tax", 10)
Opcode.INC_INDEXED_VAR_W -> TODO("inc array_w")
Opcode.INC_INDEXED_VAR_UW -> TODO("inc array_uw")
Opcode.INC_INDEXED_VAR_UW -> AsmFragment("$saveX $loadXWord inc $variable,x | bne + | inc $variable+1,x |+ $restoreX", 10)
Opcode.INC_INDEXED_VAR_FLOAT -> TODO("inc array_f")
Opcode.DEC_INDEXED_VAR_W -> TODO("dec array_w")
Opcode.DEC_INDEXED_VAR_UW -> TODO("dec array_uw")
Opcode.DEC_INDEXED_VAR_UW -> AsmFragment("$saveX $loadXWord lda $variable,x | bne + | dec $variable+1,x |+ | dec $variable,x $restoreX", 10)
Opcode.DEC_INDEXED_VAR_FLOAT -> TODO("dec array_f")
else -> null
@ -2915,6 +2922,19 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.POP_REGXY_WORD)) { segment ->
" ldx #<${segment[0].callLabel} | ldy #>${segment[0].callLabel} "
},
// set a register pair to a certain memory address (of a floating point value)
AsmPattern(listOf(Opcode.PUSH_ADDR_FLOAT, Opcode.POP_REGAX_WORD)) { segment ->
val varname=getFloatConst(segment[0].arg!!)
" lda #<$varname | ldx #>$varname "
},
AsmPattern(listOf(Opcode.PUSH_ADDR_FLOAT, Opcode.POP_REGAY_WORD)) { segment ->
val varname=getFloatConst(segment[0].arg!!)
" lda #<$varname | ldy #>$varname "
},
AsmPattern(listOf(Opcode.PUSH_ADDR_FLOAT, Opcode.POP_REGXY_WORD)) { segment ->
val varname=getFloatConst(segment[0].arg!!)
" ldx #<$varname | ldy #>$varname "
},
// set a register pair to a certain memory address (of a literal string value)
AsmPattern(listOf(Opcode.PUSH_ADDR_STR, Opcode.POP_REGAX_WORD)) { segment ->
TODO("$segment")

View File

@ -1443,13 +1443,18 @@ class StackVm(private var traceOutputFile: String?) {
val heapId = variables[ins.callLabel]!!.heapId
if(heapId<0)
throw VmExecutionException("expected variable on heap")
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable (this is taken care of properly in the assembly code generator)
}
Opcode.PUSH_ADDR_STR -> {
val heapId = ins.arg!!.heapId
if(heapId<0)
throw VmExecutionException("expected string to be on heap")
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string (this is taken care of properly in the assembly code generator)
}
Opcode.PUSH_ADDR_FLOAT -> {
val floatvalue = ins.arg!!
checkDt(floatvalue, DataType.FLOAT)
evalstack.push(Value(DataType.UWORD, floatvalue.numericValue().toInt() and 65535)) // push the "address" of the floating point value (this is taken care of properly in the assembly code generator)
}
Opcode.CAST_UB_TO_B -> typecast(DataType.UBYTE, DataType.BYTE)
Opcode.CAST_W_TO_B -> typecast(DataType.WORD, DataType.BYTE)

View File

@ -39,19 +39,10 @@
c64.STROUT("balloon sprites!\n")
c64.STROUT("...we are all floating...\n")
const uword sprite_address_ptr = $0a00 // 64
c64.SPRPTR0 = sprite_address_ptr
c64.SPRPTR1 = sprite_address_ptr
c64.SPRPTR2 = sprite_address_ptr
c64.SPRPTR3 = sprite_address_ptr
c64.SPRPTR4 = sprite_address_ptr
c64.SPRPTR5 = sprite_address_ptr
c64.SPRPTR6 = sprite_address_ptr
c64.SPRPTR7 = sprite_address_ptr
for ubyte i in 0 to 7 {
@(SP0X+i*2) = 50+25*i
@(SP0Y+i*2) = rnd()
c64.SPRPTR[i] = $0a00 // 64
c64.SPXY[i*2] = 50+25*i
c64.SPXY[i*2+1] = rnd()
}
c64.SPENA = 255 ; enable all sprites
@ -63,15 +54,17 @@
~ irq {
sub irq() {
c64.EXTCOL--
; float up & wobble horizontally
for ubyte i in 0 to 14 step 2 {
@(main.SP0Y+i)--
c64.SPXY[i+1]--
ubyte r = rnd()
if r>200
@(main.SP0X+i)++
c64.SPXY[i]++
else if r<40
@(main.SP0X+i)--
c64.SPXY[i]--
}
c64.EXTCOL++
}

View File

@ -1,60 +1,20 @@
%import c64utils
%import c64flt
~ main {
sub start() {
ubyte ub=20
ubyte ub2
byte b =-10
byte b2
uword uw = 2000
uword uw2
word w = -222
word w2
; @todo create word function ;c64.SPXY[i] = (rnd() as uword) * 256 + (50+25*i)
; @todo more efficient +1/-1 additions in expressions
A>>=1
A>>=3
A<<=1
A<<=3
lsr(A)
lsl(A)
float f1 = c64flt.TWOPI
ub2 = ub>>1
ub2 = ub>>2
ub2 = ub<<1
ub2 = ub<<2
b2 = b>>1
b2 = b>>2
b2 = b<<1
b2 = b<<2
uw2 = uw>>1
uw2 = uw>>2
uw2 = uw<<1
uw2 = uw<<2
w2 = w>>1
w2 = w>>2
w2 = w<<1
w2 = w<<2
lsr(ub)
lsr(b)
lsr(uw)
lsr(w)
lsl(ub)
lsl(b)
lsl(uw)
lsl(w)
rol(ub)
rol(uw)
rol2(ub)
rol2(uw)
ror(ub)
ror(uw)
ror2(ub)
ror2(uw)
;c64scr.print_ub(X)
;c64.CHROUT('\n')
c64flt.print_fln(3.1415)
c64flt.print_fln(f1)
f1 = 3.1415
f1 = 3.1415
f1 = 3.1415
f1 = 3.1415
}
}

View File

@ -33,16 +33,9 @@
sub start() {
const uword sprite_address_ptr = $0a00 // 64
c64.SPRPTR0 = sprite_address_ptr
c64.SPRPTR1 = sprite_address_ptr
c64.SPRPTR2 = sprite_address_ptr
c64.SPRPTR3 = sprite_address_ptr
c64.SPRPTR4 = sprite_address_ptr
c64.SPRPTR5 = sprite_address_ptr
c64.SPRPTR6 = sprite_address_ptr
c64.SPRPTR7 = sprite_address_ptr
for ubyte i in 0 to 7 {
c64.SPRPTR[i] = $0a00//64
}
c64.SPENA = 255 ; enable all sprites
c64utils.set_rasterirq(260) ; enable animation
}
@ -54,21 +47,17 @@
ubyte angle=0
sub irq() {
const uword SP0X = $d000
const uword SP0Y = $d001
c64.EXTCOL--
angle++
c64.MSIGX=0
ubyte i=14
ubyte i=14
nextsprite: ; @todo should be a for loop from 14 to 0 step -2 but this causes a value out of range error at the moment
uword x = sin8u(angle*2-i*8) as uword + 50
ubyte y = cos8u(angle*3-i*8) // 2 + 70
@(SP0X+i) = lsb(x)
@(SP0Y+i) = y
c64.SPXY[i] = lsb(x)
c64.SPXY[i+1] = y
lsl(c64.MSIGX)
if msb(x) c64.MSIGX++
i-=2