subroutines are now wrapped in .proc/.pend for 64tass

This commit is contained in:
Irmen de Jong 2019-01-06 02:32:51 +01:00
parent f803b4edc1
commit 775cdd451c
10 changed files with 174 additions and 63 deletions

View File

@ -1,52 +1,150 @@
%import c64utils
%import c64flt
~ main {
const uword width = 40
const uword height = 25
; vertices
byte[8] xcoor = [ -50, -50, -50, -50, 50, 50, 50, 50 ]
byte[8] ycoor = [ -50, -50, 50, 50, -50, -50, 50, 50 ]
byte[8] zcoor = [ -50, 50, -50, 50, -50, 50, -50, 50 ]
; storage for rotated coordinates
word[len(xcoor)] rotatedx=0
word[len(ycoor)] rotatedy=0
word[len(zcoor)] rotatedz=-1
sub start() {
ubyte a=200
ubyte b=33
ubyte c
byte ab=100
byte bb=-6
byte cb
uword wa=50000
uword wb=999
uword wc
word wab=30000
word wbb=-99
word wcb
c=a//b
c64scr.print_ub(c)
c64.CHROUT('\n')
a=155
b=11
c=a//b
c64scr.print_ub(c)
c64.CHROUT('\n')
cb=ab//bb
c64scr.print_b(cb)
c64.CHROUT('\n')
ab=-100
bb=6
cb=ab//bb
c64scr.print_b(cb)
c64.CHROUT('\n')
ab=-100
bb=-6
cb=ab//bb
c64scr.print_b(cb)
c64.CHROUT('\n')
ab=100
bb=6
cb=ab//bb
c64scr.print_b(cb)
c64.CHROUT('\n')
c64scr.print_ub(X)
c64.CHROUT('\n')
uword anglex
uword angley
uword anglez
while(true) {
rotate_vertices(msb(anglex), msb(angley), msb(anglez))
c64.CLEARSCR()
draw_edges()
anglex+=1000
angley+=333
anglez+=807
}
}
sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
; rotate around origin (0,0,0)
; set up the 3d rotation matrix values
word wcosa = cos8(ax) as word
word wsina = sin8(ax) as word
word wcosb = cos8(ay) as word
word wsinb = sin8(ay) as word
word wcosc = cos8(az) as word
word wsinc = sin8(az) as word
word wcosa_sinb = wcosa*wsinb
lsr(wcosa_sinb)
lsr(wcosa_sinb)
lsr(wcosa_sinb)
lsr(wcosa_sinb)
lsr(wcosa_sinb)
lsr(wcosa_sinb)
lsr(wcosa_sinb) ; / 128
word wsina_sinb = wsina*wsinb
lsr(wsina_sinb)
lsr(wsina_sinb)
lsr(wsina_sinb)
lsr(wsina_sinb)
lsr(wsina_sinb)
lsr(wsina_sinb)
lsr(wsina_sinb) ; / 128
float cosa_sinb = wcosa_sinb as float / 128.0
float sina_sinb = wsina_sinb as float / 128.0
float Axx = wcosa*wcosb as float / 16384.0
float Axy = cosa_sinb*(wsinc as float / 128.0) - (wsina*wcosc as float / 16384.0)
float Axz = cosa_sinb*(wcosc as float / 128.0) + (wsina*wsinc as float / 16384.0)
float Ayx = wsina*wcosb as float / 16384.0
float Ayy = sina_sinb*(wsinc as float / 128.0) + (wcosa*wcosc as float / 16384.0)
float Ayz = sina_sinb*(wcosc as float / 128.0) - (wcosa*wsinc as float / 16384.0)
float Azx = -wsinb as float / 128.0
float Azy = wcosb*wsinc as float / 16384.0
float Azz = wcosb*wcosc as float / 16384.0
word wAxx = Axx * 128.0 as word
word wAxy = Axy * 128.0 as word
word wAxz = Axz * 128.0 as word
word wAyx = Ayx * 128.0 as word
word wAyy = Ayy * 128.0 as word
word wAyz = Ayz * 128.0 as word
word wAzx = Azx * 128.0 as word
word wAzy = Azy * 128.0 as word
word wAzz = Azz * 128.0 as word
for ubyte i in 0 to len(xcoor)-1 {
word xc = xcoor[i] as word
word yc = ycoor[i] as word
word zc = zcoor[i] as word
word zz = wAxx*xc + wAxy*yc + wAxz*zc
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz) ; /128
rotatedx[i] = zz
zz=wAyx*xc + wAyy*yc + wAyz*zc
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz) ; /128
rotatedy[i] = zz
zz = wAzx*xc + wAzy*yc + wAzz*zc
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz)
lsr(zz) ; /128
rotatedz[i] = zz
}
}
sub draw_edges() {
sub toscreenx(float x, float z) -> byte {
return x/(250.0+z) * (height as float) as byte + width // 2
}
sub toscreeny(float y, float z) -> byte {
return y/(250.0+z) * (height as float) as byte + height // 2
}
; plot the points of the 3d cube
; first the points on the back, then the points on the front (painter algorithm)
for ubyte i in 0 to len(xcoor)-1 {
word rz = rotatedz[i]
if rz >= 10 {
ubyte sx = toscreenx(rotatedx[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param!
ubyte sy = toscreeny(rotatedy[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param!
c64scr.setchrclr(sx, sy, 46, i+2)
}
}
; @todo integer / integer should usually result in a FLOAT, not INT. the // operator is for integer division!
for ubyte i in 0 to len(xcoor)-1 {
word rz = rotatedz[i]
if rz < 10 {
ubyte sx = toscreenx(rotatedx[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param!
ubyte sy = toscreeny(rotatedy[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param!
c64scr.setchrclr(sx, sy, 81, i+2)
}
}
}
}

View File

@ -62,9 +62,8 @@ sub irq() {
angle++
c64.MSIGX=0
for ubyte i in 0 to 14 step 2 {
word x = (sin8(angle*2-i*8) as word)+190
byte y = cos8(angle*3-i*8)
lsr(y)
word x = (sin8(angle*2-i*8) as word)+190 ; @todo will/should be using shifts for faster multiplication
byte y = cos8(angle*3-i*8) // 2 ; @todo will/should be using shifts for faster multiplication
@(SP0X+i) = lsb(x)
@(SP0Y+i) = y+150 as ubyte

View File

@ -153,10 +153,11 @@ private class StatementTranslator(private val prog: IntermediateProgram,
override fun process(block: Block): IStatement {
prog.newBlock(block.scopedname, block.name, block.address, block.options())
processVariables(block) // @todo optimize initializations with same value: load the value only once (sort on initalization value, datatype ?)
prog.label("block."+block.scopedname)
prog.label("block."+block.scopedname, false)
prog.line(block.position)
translate(block.statements)
return super.process(block)
val r = super.process(block)
return r
}
private fun processVariables(scope: INameScope) {
@ -168,18 +169,22 @@ private class StatementTranslator(private val prog: IntermediateProgram,
override fun process(subroutine: Subroutine): IStatement {
if(subroutine.asmAddress==null) {
prog.label(subroutine.scopedname)
prog.label(subroutine.scopedname, true)
prog.instr(Opcode.START_PROCDEF)
prog.line(subroutine.position)
// note: the caller has already written the arguments into the subroutine's parameter variables.
translate(subroutine.statements)
val r= super.process(subroutine)
prog.instr(Opcode.END_PROCDEF)
return r
} else {
// asmsub
if(subroutine.isNotEmpty())
throw CompilerException("kernel subroutines (with memory address) can't have a body: $subroutine")
prog.memoryPointer(subroutine.scopedname, subroutine.asmAddress, DataType.UBYTE) // the datatype is a bit of a dummy in this case
return super.process(subroutine)
}
return super.process(subroutine)
}
private fun translate(statements: List<IStatement>) {
@ -1809,6 +1814,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
// TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH_BYTE / SUB opcodes and make use of the wrapping around of the value.
// TODO: ubyte/uword can't count down to 0 with negative step because test value will be <0 which causes "value out of range" crash
prog.instr(opcodePush(varDt), Value(varDt, range.last + range.step))
prog.instr(opcodePushvar(varDt), callLabel = varname)
prog.instr(opcodeSub(varDt))

View File

@ -34,7 +34,7 @@ open class Instruction(val opcode: Opcode,
}
}
class LabelInstr(val name: String) : Instruction(Opcode.NOP, null, null) {
class LabelInstr(val name: String, val asmProc: Boolean) : Instruction(Opcode.NOP, null, null) {
override fun toString(): String {
return "\n$name:"
}

View File

@ -358,8 +358,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
currentBlock.instructions.add(Instruction(opcode, arg, callLabel = callLabel))
}
fun label(labelname: String) {
val instr = LabelInstr(labelname)
fun label(labelname: String, asmProc: Boolean=false) {
val instr = LabelInstr(labelname, asmProc)
currentBlock.instructions.add(instr)
currentBlock.labels[labelname] = instr
}

View File

@ -239,10 +239,12 @@ enum class Opcode {
JNZW, // branch if value is not zero (word)
// subroutine calling
// subroutines
CALL,
RETURN,
SYSCALL,
START_PROCDEF,
END_PROCDEF,
// misc
SEC, // set carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations

View File

@ -33,7 +33,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
val newlabels = block.labels.map { symname(it.key, block) to it.value}.toMap().toMutableMap()
val newinstructions = block.instructions.asSequence().map {
when {
it is LabelInstr -> LabelInstr(symname(it.name, block))
it is LabelInstr -> LabelInstr(symname(it.name, block), it.asmProc)
it.opcode == Opcode.INLINE_ASSEMBLY -> it
else ->
Instruction(it.opcode, it.arg, it.arg2,
@ -394,16 +394,21 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
if(ins is LabelInstr) {
if(ins.name.startsWith("block."))
return ""
return if(ins.name.startsWith("${block.shortname}."))
ins.name.substring(block.shortname.length+1)
else
ins.name
val labelresult =
if(ins.name.startsWith("${block.shortname}."))
ins.name.substring(block.shortname.length+1)
else
ins.name
return if(ins.asmProc) labelresult+"\t\t.proc" else labelresult
}
// simple opcodes that are translated directly into one or a few asm instructions
return when(ins.opcode) {
Opcode.LINE -> " ;\tsrc line: ${ins.callLabel}"
Opcode.NOP -> " nop" // shouldn't be present anymore though
Opcode.START_PROCDEF -> "" // is done as part of a label
Opcode.END_PROCDEF -> " .pend"
Opcode.TERMINATE -> " brk"
Opcode.SEC -> " sec"
Opcode.CLC -> " clc"

View File

@ -19,7 +19,7 @@ class Program (val name: String,
{
init {
// add end of program marker and some sentinel instructions, to correctly connect all others
program.add(LabelInstr("____program_end"))
program.add(LabelInstr("____program_end", false))
program.add(Instruction(Opcode.TERMINATE))
program.add(Instruction(Opcode.NOP))
connect()

View File

@ -254,6 +254,7 @@ class StackVm(private var traceOutputFile: String?) {
traceOutput?.println("\n$ins")
when (ins.opcode) {
Opcode.NOP -> {}
Opcode.START_PROCDEF, Opcode.END_PROCDEF -> {}
Opcode.PUSH_BYTE -> {
checkDt(ins.arg, DataType.UBYTE, DataType.BYTE)
evalstack.push(ins.arg)

View File

@ -156,9 +156,9 @@ mul_word .proc
stx c64.SCRATCH_ZPREGX
jsr math.multiply_words
ldx c64.SCRATCH_ZPREGX
lda math.multiply_words_result
lda math.multiply_words.multiply_words_result
sta c64.ESTACK_LO+1,x
lda math.multiply_words_result+1
lda math.multiply_words.multiply_words_result+1
sta c64.ESTACK_HI+1,x
rts
.pend