SPC700 assemblers overview

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Post by Near »

Well, like I tell others, if // for comments bothers you that much, change it or use something else.

I abhor :less labels because that makes any error compile as valid code.

Code: Select all

clx  //should've been clc, but now it's a label named clx
adc $2100
And with :, block separators on labels become unreadable:

Code: Select all

loop: : dec : beq end : inx : bra loop : end: : rts

Code: Select all

loop:; dec; beq end; inx; bra loop; end:; rts
Defines have both start and close markers so that they are not ambiguous with labels, opcodes and directives, and can concatenate.

Try and specify define x, then define y, then the letter z.

Code: Select all

{x}{y}z
<- very clear purpose

Code: Select all

!x!yz
<- !x + !yz

Code: Select all

xyz
<- is it an opcode? A define named xyz? A label?

Otherwise, I would certainly like markerless defines. It'd basically be a true table assembler at that point.
define clc = db $18 //or whatever clc is
define adc #n = db $69,{n}
define add n = clc; adc {n}
add #$24 //clc; adc #$24

But well, whatever. The code is extremely clean. It's not at all hard to change this stuff. Given how obscure SPC700 ASM code is, just include the assembler source with your SPC700 source.

Or don't worry about minor semantics issues ;)
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

byuu wrote:I abhor :less labels because that makes any error compile as valid code.
Same here.
And with :, block separators on labels become unreadable:

Code: Select all

loop: : dec : beq end : inx : bra loop : end: : rts

Code: Select all

loop:; dec; beq end; inx; bra loop; end:; rts
I don't put multiple instructions on one line in my own code, instead choosing to edit in a narrower window and use a newline and two spaces between instructions. But one could decide that when the label separator and the instruction separator are set to the same, a label may appear only in the first position on a line.

Code: Select all

loop: dec : beq end : inx : bra loop
end: rts
This would be a compromise between detecting incorrect 'clx : ' and allowing the more familiar syntax.
Defines have both start and close markers so that they are not ambiguous with labels, opcodes and directives, and can concatenate.

Try and specify define x, then define y, then the letter z.

Code: Select all

{x}{y}z
<- very clear purpose
Or as the C preprocessor puts it: x ## y ## z
Shiru
Posts: 1161
Joined: Sat Jan 23, 2010 11:41 pm

Post by Shiru »

byuu, how can you explain this?

This does not compile, gives both 'unknown token' and 'unrecognized token' errors on the line where the macro used:

Code: Select all

define dspa reg
	sti {ADDR},#{reg}
	sta {DATA}
enddef

..

{dspa {DSP_ADSR1}}
This compiles. Obviously does not work, I just tried it at random after ran out of ideas why seemingly correct code just don't want to compile (as compiler does not provide too much info in the error messages, I had to exclude bits of code to find what exactly causes the problem):

Code: Select all

define dspa reg
	sta {DATA}
	sti {ADDR},#{reg}
enddef

..

{dspa {DSP_ADSR1}}
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Post by Near »

A bug, was seeing the first '}' as the end of a define. That was prior to me adding arguments to defines. Unfortunately nobody tested it, sorry.

Please replace Bass::evalDefines with the below function in eval.cpp:

Code: Select all

void Bass::evalDefines(string &line) {
  unsigned length = line.length();
  for(unsigned x = 0; x < length; x++) {
    if(line[x] == '{') {
      signed counter = 1;
      for(unsigned y = x + 1; y < length; y++) {
        if(line[y] == '{') counter++;
        if(line[y] == '}') counter--;
        if(line[y] == '}' && counter == 0) {
          string name = substr(line, x + 1, y - x - 1);
          if(!name.position("::")) name = { activeNamespace, "::", name };

          lstring header, args;
          header.split<1>(" ", name);
          if(header[1] != "") args.split(",", header[1]);

          foreach(define, defines) {
            if(header[0] == define.name && args.size() == define.args.size()) {
              string result;
              evalParams(result, define, args);
              line = string(substr(line, 0, x), result, substr(line, y + 1));
              defineExpandCounter++;
              return evalDefines(line);
            }
          }
          break;
        }
      }
    }
  }
}
Also, it's odd code that seems to assume A already has the value you want to write. I assume that was your intention.
But one could decide that when the label separator and the instruction separator are set to the same, a label may appear only in the first position on a line.
That would break my macro expansions (it turns each line feed into a separator, so that error messages are on the same line# and I only have to replace data on the currently selected line block), and it would also require a specialized parsing grammar instead of just qsplit(";", line);
Shiru
Posts: 1161
Joined: Sat Jan 23, 2010 11:41 pm

Post by Shiru »

Thanks for the fix, it works.

Other problem, maybe a minor one, but can make some headache - no errors if an undefined label is used in a beq. I.e., no label anywhere: is defined, bra anywhere makes a error, while beq anywhere shows no error.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Post by Near »

Here's a fixed version for the define and beq issues. Also added -overwrite option to forcefully overwrite existing files.

Code: Select all

http://byuu.org/files/bass_v02.tar.bz2
Sorry again that you're effectively the beta tester here, but I appreciate the bug reports at any rate.
Post Reply