base:codegen-scripts.asm
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | base:codegen-scripts.asm [2015-04-17 04:30] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | < | ||
+ | //general helper scripts.. | ||
+ | //gets hi-byte of 16 bit arguments | ||
+ | .function _16bit_nextArgument(arg) { | ||
+ | .if (arg.getType() == AT_IMMEDIATE) .return CmdArgument(arg.getType(), | ||
+ | .if (arg.getType() == AT_IZEROPAGEY || arg.getType() == AT_IZEROPAGEX) .return arg | ||
+ | .return CmdArgument(arg.getType(), | ||
+ | } | ||
+ | |||
+ | //move byte | ||
+ | .pseudocommand mb src;tar { | ||
+ | lda src | ||
+ | .if (tar.getType() == AT_INDIRECT) { | ||
+ | ldy #0 | ||
+ | sta (tar.getValue()), | ||
+ | } else { | ||
+ | sta tar | ||
+ | } | ||
+ | } | ||
+ | |||
+ | //move word | ||
+ | .pseudocommand mw src; | ||
+ | :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 | ||
+ | && | ||
+ | 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/ | ||
+ | .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: | ||
+ | ": | ||
+ | sta target,y | ||
+ | ":gc #$ea" => output #$ea => | ||
+ | lda #$ea | ||
+ | sta target,y | ||
+ | ":gc #NOP" => output a nop instruction, | ||
+ | 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, | ||
+ | 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; # | ||
+ | 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, | ||
+ | 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 ; #> | ||
+ | Or the relOffset argument can be used for altering bytes ahead/ | ||
+ | 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/ | ||
+ | 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 " | ||
+ | */ | ||
+ | .eval relOffset = relOffset.getValue() | ||
+ | .var args = List().add(arg1, | ||
+ | .var progress = 1 | ||
+ | .for (var i=0; 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< | ||
+ | //only lda if there' | ||
+ | .if (arg.getType() != AT_NONE) { | ||
+ | .if (b == 0) lda arg | ||
+ | else lda #> | ||
+ | } | ||
+ | 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, | ||
+ | :gc #LDA_ABSX; ;#> | ||
+ | lda something | ||
+ | and somethingElse | ||
+ | :gcr -2 //adds the middle byte | ||
+ | */ | ||
+ | .pseudocommand gcr relOffset { | ||
+ | :gc ;;; | ||
+ | } | ||
+ | |||
+ | .macro setCodeOuts(adrs) { | ||
+ | .for (var i=0; i< | ||
+ | sta adrs.get(i) | ||
+ | } | ||
+ | |||
+ | </ |
base/codegen-scripts.asm.txt · Last modified: 2015-04-17 04:30 by 127.0.0.1