User Tools

Site Tools


base:codegen-scripts.asm

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

base:codegen-scripts.asm [2015-04-17 04:30] (current)
Line 1: Line 1:
 +<​code>​
 +//general helper scripts..
  
 +//gets hi-byte of 16 bit arguments
 +.function _16bit_nextArgument(arg) {
 + .if (arg.getType() == AT_IMMEDIATE) .return CmdArgument(arg.getType(),​ >​arg.getValue())
 + .if (arg.getType() == AT_IZEROPAGEY || arg.getType() == AT_IZEROPAGEX) .return arg
 + .return CmdArgument(arg.getType(),​ arg.getValue()+1)
 +}
 +
 +//move byte
 +.pseudocommand mb src;tar {
 + lda src
 + .if (tar.getType() == AT_INDIRECT) {
 + ldy #0
 + sta (tar.getValue()),​y
 + } else {
 + sta tar
 + }
 +}
 +
 +//move word
 +.pseudocommand mw src;​tar;​tar2 {
 + :mb src;tar
 + .var yInced = false
 + .if (src.getType() == AT_IZEROPAGEY) {
 + iny
 + lda tar
 + .eval yInced = true
 + } else {
 + lda _16bit_nextArgument(src)
 + }
 + .var nextTar
 + .if (tar2.getType() != AT_NONE) .eval nextTar = tar2
 + else .eval nextTar = _16bit_nextArgument(tar)
 + .if (nextTar.getType() == AT_IZEROPAGEY) {
 + .if (!yInced) iny
 + sta tar
 + } else {
 + sta nextTar
 + }
 +}
 +
 +//add word
 +.pseudocommand aw src;tar {
 + :ab src;tar
 + .var nextTar = _16bit_nextArgument(tar)
 + .if (src.getType() == AT_IZEROPAGEY || tar.getType() == AT_IZEROPAGEY) {
 + iny
 + }
 + .if (src.getType() == AT_IMMEDIATE && src.getValue() < $80 && src.getValue() >= 0
 + &&​ tar.getType() != AT_IZEROPAGEY) {
 + bcc !+
 + inc nextTar
 + !:
 + } else {
 + lda _16bit_nextArgument(src)
 + adc nextTar
 + sta nextTar
 + }
 +}
 +
 +//add byte
 +.pseudocommand ab src;tar {
 + clc
 + lda src
 + adc tar
 + sta tar
 +}
 +
 +//scripts for code generation...
 +.var codeOuts // list of speedcode outputting places that must be updated on page change
 +.var offset // keeps track of where in the code segment we are, and can be used to
 + // determine length of the segment
 +.var codeTarget
 +
 +.macro startCodeGen(target) {
 + .eval codeTarget = target
 +}
 +
 +// starts a new segment of speedcode, in this case lineInit/​plasmer
 +.macro newSegment() {
 + .eval codeOuts = List()
 + .eval offset = 0
 + ldy codePnt+0
 +}
 +
 +.pseudocommand gc arg1; arg2; arg3; relOffset {
 +/* Generates a codegenerator stub for 1-3 bytes of speedcode, based on the arguments.
 + The speedcode generator works like:
 + [lda source]
 + sta target,y
 + Which means that the high byte of the sta's have to be incremented each time y rolls over.
 + For this purpose, the locations of the sta hi-bytes are stored in a list called codeOuts, which
 + can be used for incrementing them when needed.
 + In addition the offset is auto-incremented by 1 for every generated byte. The offset is located in 
 + a variable called offset, which can be used afterwards to determine the length of the code segment.
 + Examples:
 + ":​gc"​ => no arguments means it will just output the content of the accumulator =>
 + sta target,y
 + ":gc #$ea" => output #$ea =>
 + lda #$ea
 + sta target,y
 + ":gc #NOP" => output a nop instruction,​ which is also $ea => same result as before. The opcode constants
 + are built into KickAss.
 + ":gc #LDX_ZP; #$fe" => generate "ldx $fe" =>
 + lda #LDX_ZP
 + sta target,y
 + lda #$fe
 + sta target+1,y
 + This will increment the offset by 2, where it was only 1 for the previous examples. Note the # before $fe -
 + if this had been left out, the value for the 2nd byte would have been loaded from $fe.
 + ":gc #LDA_IMM; cnt" => generate "lda $xx" where xx is loaded from the cnt label by the code generator.
 + Note the lack of # before cnt =>
 + lda #LDA_IMM
 + sta target,y
 + lda cnt
 + sta target+1,y
 + All addressing modes can be used for fetching bytes to generate, also indexed.
 + ":gc #LDY_IMM; colors,​x"​ => generate "ldy $xx" where xx is looked up in the colors table =>
 + lda #LDY_IMM
 + sta target,y
 + lda colors,x
 + sta target+1,y
 + If the second argument is 16 bits it will result in two generated bytes. E.g.
 + ":gc #INC_ABS; #​$d020"​ => generate "inc $d020" =>
 + lda #INC_ABS
 + sta target,y
 + lda #$20
 + sta target+1,y
 + lda #$d0
 + sta target+2,y
 + This currently only works for immediate values, so if the address had to be looked up you have to
 + specify the lo/hi bytes separately:
 + ":gc #INC_ABS; adrs+0,x; adrs+1,​x"​ =>
 + lda #INC_ABS
 + sta target,y
 + lda adrs+0,x
 + sta target+1,y
 + lda adrs+1,x
 + sta target+2,y
 + If more advanced methods of calculating bytes are needed, they can be generated one at a time, like:
 + :gc #LDA_IMM
 + lda something
 + ora somethingElse
 + :gc //no args = output accumulator
 + Another one...
 + :gc #STA_ABS
 + lda something
 + ora somethingElse
 + :gc ; #>​address //empty first argument = first output accumulator,​ then hi-byte of address.
 + Or the relOffset argument can be used for altering bytes ahead/​behind the current offset. If this is set
 + the offset will not be auto incremented. In most cases it's probably easier to use :grc for this though.
 + Remember to set the argument that needs to be altered before/​after to empty, in order to avoid redundancy.
 + If the code bugs, a good way of debugging is to take a look at the generated code generator in a monitor.
 + The location can be printed at assembly time with .print "​here:"​ + toHexString(*)
 +*/
 + .eval relOffset = relOffset.getValue()
 + .var args = List().add(arg1,​arg2,​arg3)
 + .var progress = 1
 + .for (var i=0; i<​args.size();​ i++) {
 + .var arg = args.get(i)
 + .if (i==0 || arg.getType() != AT_NONE) {
 + .var numBytes = 1
 + //16 bit support for 2nd argument...
 + .if (i==1 && arg.getValue() >= $100 && arg.getType() == AT_IMMEDIATE)
 + .eval numBytes = 2
 + .for (var b=0; b<​numBytes;​ b++) {
 + //only lda if there'​s a non-empty argument..
 + .if (arg.getType() != AT_NONE) {
 + .if (b == 0) lda arg
 + else lda #>​arg.getValue()
 + }
 + sta codeTarget + offset + i + b + relOffset,y
 + .eval codeOuts.add(* - 1)
 + .eval progress = i + numBytes
 + }
 + }
 + }
 + .if (relOffset==0) .eval offset = offset + progress
 +}
 +/*
 + Generates a byte (the content of the accumulator) with a relative offset.
 + Can be used together with an empty param for :gc for 3-byte instructions where the middle one requires
 + special handling, e.g. "lda sine,​x"​ with a different lo-byte:
 + :gc #LDA_ABSX; ;#>​sine //​skips the middle byte
 + lda something
 + and somethingElse
 + :gcr -2 //adds the middle byte
 +*/
 +.pseudocommand gcr relOffset {
 + :gc ;;;​relOffset
 +}
 +
 +.macro setCodeOuts(adrs) {
 + .for (var i=0; i<​adrs.size();​ i++)
 + sta adrs.get(i)
 +}
 +
 +</​code>​
base/codegen-scripts.asm.txt ยท Last modified: 2015-04-17 04:30 (external edit)