Doc for version v1.2 of the snes assembler. (Snes-Pac)

Copyright 1992-1993 Elitendo/Cynix
No permission to sell this program for ANY amount of money.
Permission to give it away for FREE or swap against other software.

Updated:
When going to a new line for editing, then entered '2' it jumped
to the next page, this is fixed.

Changed: Page up/down CONTROL-Arrows (no more shift)
Changed: Orginate range

These types of instructions are fixed:
        jmp ($00ec)     ;less then $100
        jmp $0000
        sta $0004,y
        jsr $0000
        jml (Label)     ;better label check routine..

Changed: All calculation routines > recursive calculation
         You can now use things like this:

        ldx.l   #[14+(test+4)!($922>>2)^*2]

New: Rept/Endr
New: Set
New: la/li/sa/si

 

Snes-pac History:
-----------------
When I finished and released my snes-disassembler, I received a call
from Cynix, they were quite pleased with. So they asked me to convert
their assembler (written by Corsair) to a nice looking/handy/etc.. thing.
So they gave me their source, and I started to work on it.
I took an old Genst.prg (from Devpack) v1.22 and disassembled it.
Old because the new ones were awful big! Then I labeled most of the stuff.
And removed all the st assembler parts, leaving a nice short editor.
Then I inserted the Corsair part. This needed a lot of converting, changes
etc.. I inserted the rsc file and changed a lot in this too.
When it finally worked I made about 7 updates, each time improving the
capability, and make it more 'error free'.    
This is the result........

One disadvantage of the editor is that the horizontal slider is not active.
In order to change this I have to completely rewrite the gem based editor.
And that's a LOT of work. But then, you can't have it all?
 
Credits go to Corsair/CYNIX for the 'Heart' of the assembler.
(although he will not recognize his own part anymore)
To the developers of the old GENST, sorry i didn't ask permission.
Rest of the Credits goes to Sledge/Hotline/Elite(ndo) for testing and
keeping everybody at work.....


If ya guys/ladies have made some nice sources for 'any' snes-assembler
available, we would be happy to receive them from you, so we can test
a lot of things, and maybe learn some snes-programming tricks from you!
That's a good trade for this nice snes-assembler? No problems sending
checks or money etc.. just send us some sources call our bbs.... 

If you find any strange things, or errors in the snes-pac, leave
a fully detailed description of the problem on our BBS.


                The Magician/MCA/Elite(ndo)


How snes-pac works:
-------------------

PSEUDO OPCODES:
~~~~~~~~~~~~~~~
  
All pseudo/normal opcodes can be mixed upper/lowercase.
Labels CANNOT be mixed.
All pseudo opcodes need the 1st 3 characters to be recognized by the 
assembler. So 'nat' will be the same as 'native'.
Normal opcodes may NOT be extended (only with .l and a few others) 

org = original place where the code should begin.
      (sets internal programcounter to assigned value)
      If no org is set, $8000 will be assumed.
      All absolute references will be affected.

Example 1:

        ORG     $F000           ;assume code starts at $f000
start   jmp     start           ;jump to $f000

Use other values if you have to insert the code into a game at a
certain place or so.

Example 2:
        org     $700            ;this is ok
start   jmp     start           ;start begins at adres $700 (system stuff)
         
Finnish assembler used by baseline:
They use org $0000 then rorg $8000.
Don't use rorg $8000. It will cause an error.
-----------------------------------------------------------------------

nat = native mode 16 bits will put an clc & xce in code!!!!
emu = emulation mode 8 bits will put an sec & xce in code!!!

Example 1:

        NATIVE          ;ONLY THE 1ST 3 ARE CHECKED
        SEI             ;STOP INTERRUPTS

Same as above:
        clc             ;clear carry flag
        xce             ;Xfer carry flag to emulation flag >16 bit mode
        sei

--------------------------------------------------------
There are pseudo opcodes used ONLY between int and end:
Use these things to get the vectors at the right place.

int = interrupt handling startlist (tells assembler list begins here)
all = set ALL interrupts to a certain value,(8 & 16 bit)
nmi = non maskable interrupt vector
res = reset vector
brk = break vector
abo = abort vector
cop = coprocessor vector 
irq = interrupt request vector
end = end of interrupt handling list(tells assembler this is the END of list)

Example 1:

        interrupts
all_vecs =       rti_instr       ;set ALL vectors to point at rti_instr
reset    =       startprogram    ;reset vector to startprogram
                                 ;all of this must point to 1st bank! 
         end                     ;don't forget end!!!!!
                                 ;use all first!!! else res will be the same!

startprogram    nop
                ......
rti_instr       rti
nmi_start       jml     vbl_native      ;see below
nmi_emu         jml     vbl_emulation 

If you want a specific emulation or native vector defined you can use:
the .e or .n attached to the 1st label. 

Example 2:

        int
all     equ     rti_instr
res     equ     startprogram    ;res=always emulation mode
irq.n   equ     irq_start       ;set irq native vector
irq.e   equ     irq_emu         ;same but for emulation
        end

All interrupt vectors MUST point to the 1st bank.
Snes works no other way!
--------------------------------------------------------------
bin = binary include of file (specify drive an path if needed)
      Files may not exceed $8000 bytes of length.
      Actually only $8000 bytes will be loaded.(1 bank,no header)
      So if you have big graphic files, split them first into separate banks.

Example 1:

cynixlogo       bin     c:\snes\logo.bin

Example 2:

grafix_start    bin     "c:\logo.bin"

-----------------------------------------------
dcb = define character byte
dcw = word size
dsb = define space/storage byte (fill up space)
dsw = word size fillup

These can also be typed as dc.b or ds.w etc..

Example:
       
datafield dc.b    $31,20,%00000001,$ff-14,"test",10,'shit'
fillup    dsw     $200

start     dcw     start,start+40,'ab',$1234

ALL dcw values will be converted to intel format!
so $1234 will become $3412 and 'ab' will become 'ba' !!
labels can be used, but stay in the same bank! 
--------------------------------------------------------------------
pad = pad to next bank, set internal programcounter at the beginning
      of a next bank. (inbetween adresses are filled with 0)

Example 1:

start      jml     nextbank     ;start=$8000
           nop                  ;$8004
           ldx.l   #'ab'        ;swichtes to ..ba !!
label      padbank              ;label points at $8007 !!!!!
nextbank   nop                  ;nextbank=$18000
           nop                  ;$18001
           ldx     #'A'         ;load x register with $41

Example 2:
        
start      jml     nextbank
           nop
           pad     $ffc0        ;With VALUE things change a little
           dc.b    "Made by me..."
           pad
nextbank   nop

pad $ffc0 will skip the programcounter to adres $ffc0 (info area)
Values between $8000-$ffff will be accepted. Others will be masked off!
Errors in these values are NOT displayed.

If you don't put any text at the info area, the assembler will automaticly
fill it with our copyrights. (MADE WITH SNESPAC)

Example 3:

        pad     $18000          ;set counter to $8000!!!
                                ;use single pad instead

You cannot use any labels in the pad command!
The only check after pad is $.... if no dollar sign found it assumes
a single pad command.

If the programcounter crosses the bank boundary you will be informed
with: Boundery cross ok at line ...
So each pad does this. So you know what is happening. At what line
it has crossed.

If a boundery is crossed NOT using the pad command, it will be checked
on a 'bad cross', and inform you this has happend.
A bad cross is for instance: a jml $188000 starting at $01fffe.
The instruction is 4 bytes and sets the counter to $028002

Another one is: using bin and cross the boundery.

It will display the error, but will not be handled as an error.
Assembling will be continued, you might want to cross the boundery this way?
----------------------------------------------------------------------------
Label values can have byte, word, or long length.

Long labels need .l attached to the opcode.(cannot use equ)
     (except for jsl or jml)
Word labels need no extension. They can be defined with equ,
     or at the beginning of a line.
Byte labels can only be defined in the equ table.

Example:

tab     equ     9       ;byte label
nmiflag equ     $4200   ;word label

        org     $8000
        
        sep     #$30    ;set a,x,y to 8 bit
start   ldx     #tab    ;load 9 in x register
        stx     nmiflag ;put 9 in adres $4200
        lda     start   ;load $8000 in accumulator
        ldy.w   #$1234  ;word length
        ldy.l   #$1234  ;word length 
        jml     bank2   ;long label
        pad
bank2   nop
-----------------------------------------------------------------
Error checking:
~~~~~~~~~~~~~~~
Each error adds 1 to the internal error counter if > 0 no program
will be saved or no send will be done. Also if an error occured in pass 1,
pass 2 will be canceled.


Illegal opcode at line 1 jms

Example:
test    jms     loop    ;jms does not exist

Illegal operand at line 1

Example:

test    jsr     [$12],x         ;adressing mode is wrong

Error in expression at line 1

Example:

test    ldy.l   #(test/2)*(test^4   ;last parenthesis missing

or      ldy     #4>1                ;shift right must be >>

Maximal 1000 labels of 22 characters length can be handled.
If using too much, you will be informed.
Better save a few banks (no header) then bin them in if you're short
on labels.

In the first Pass each label is checked whether its defined twice, you
will be informed on doubles. At the 2nd pass labels will be checked if they
are missing or if the size is incorrect, you will be informed as well.
Short labels(byte) are checked in the 1st pass and must be defined before
you call them.
               

Error example:
        org     $7000   ;will put in $8000

start   nop             
        bra     bank2   ;This branch is too far>error
        pad             ;bra must be within byte boundery (signed!)
bank2   nop
        jmp     start   ;also wrong this is an absolute word length jump

        jml     start   ;this one is ok (not an original one)
                        ;actually it should be jmp,but it's hard to make
                        ;any error checks on jmp long/jmp absolute
or      jmp.l   start   ;also ok (these 2 are replacements)

        jsr     start   ;wrong
        jsr.l   start   ;ok (added to make it compatible)
        jsl     start   ;this is ok (this IS original)    

rep and sep don't affect the size of the operand while assembling!
If an opcode is followed by .l it will generate a long form.
also ok for immediate adressing is .w (not for absolute modes!)

so ldx   #1 = will assemble 2 bytes
   ldx.l #1 = '''           3 bytes 

if cpx #$1234 is found, an out of range error will occur
change it to cpx.w or cpx.l or cpx.v #$1234

.w = word size 2 bytes (only immedate forms)
.l = long size 2 or 3 bytes (immediate or absolute forms)
.v = same as .w ,to keep it compatible with the baseline assembler
.v stands for some kind of Finnish name.
every other extender will be ignored.

Example:
        
        lda.l   loop,x          ;this is ok
        nop                     ;lda loop,x   will make it short!!!
        pad                     ;so beware...
loop    nop  

If you want to use absolute long labels(pointers to other banks) use
the .l extension!!!

Example:        ldx.l   #$120*2         ;multiply
                ldx     #$20/10         ;divide
loop            ldx     #20+90          ;add
                ldx.l   #$4490-20       ;minus
                lda     loop+4,x        ;all 4 work on labels too

;---------------------------------------------------------------
Most people have difficulties in remembering what values rep/sep
represent, therefore a few 'make-it-easy-for-you-directives'
Replacements for rep #$.. and sep #$.. are:

la = long  accumulator (rep #$20)
li = long  index (x+y) (rep #$10)
sa = short accumulator (sep #$20)
si = short index (x+y) (sep #$10)

format of these pseudo opcodes:

Label   la      ;comment
        si      ;comment

or      la,si   ;will convert into rep #$20 + sep #$10

or      la,li   ;will convert to rep #$30
or      sa,si   ;will convert to sep #$30
----------------------------------------------------------------------
rept/endr = repeat/end repeat

format: assembles 10*nop

label   rept    10      ;values between 0-$ffff
        nop             ;NO labels in between!
        endr 

Set = set temporary value (used for rept)

format:

label   set     1               ;init label with 1
       
label2  rept    10
        lda     #label          ;1,2,....10
        sta     $2000+label
        set     label+1         ;add 1 to label value each time
        endr                    ;subtract 1 from rept counter until 0

Nested rept is NOT included!
--------------------------------------------------
Recursive calculation:

Used operators:

+,-     add,minus
*       multiply
/       quotient of division
%       remainder of division
&       logical and
!       logical or
~       compliment (not)
^       eor
<<      shift left x times  (22<<4)
>>      shift right x time (22>>5)
()      parenthesis
[]      brackets

%       binary
$       hex
        decimal
        labels
--------------------------------------

Various (rare) instruction forms:

wdm     #$12            ;illegal opcode uses 2 bytes gives NO error assembling.
brk     #$12            ;calls break vector
cop     #$12            ;calls coprocessor vector
rep     #%00100000      ;set accumulator moves to 16 bit
rep     #%00010000      ;set all X and Y moves to 16 bit
sep     #%00100000      ;set accumulator moves to 8 bit
sep     #%00010000      ;set X and Y moves to 8 bit
pei     ($12)           ;push to stack
per     relative        ;push relative adres to stack
brl     relative        ;branch long, stay IN bank
bra     relative        ;short form
mvp     #$12,#$34       ;move blocks, using x,y as offsets, accu as counter
mvn     #$12,#$34       ;same but negative 12 34 are bank numbers? 
tcd = tad               ;both of these opcodes can be used
tcs = tas
tdc = tda
tsc = tsa 

Maybe other assemblers use other adressing mode forms on some of
these instrutions, but i haven't seen another assembler yet.
Also I don't have PROPER up-to-date info on some of these things. 
----------------------------------------------------------------
Assemble options:
~~~~~~~~~~~~~~~~~
Extend, add header = fill up the bank 'till the end, fill in the VECTORS
                     at the 1st bank and glue a header to it.

Extend, no header  = only fill up to a whole bank, vectors set.

No extend          = Binary file just the assembled bytes. No vectors!

Send to Snes       = If on, and assembled without errors, it sends.
------------------------------------------------------------------
JUMP TO ERROR
~~~~~~~~~~~~~
When about 11 or more errors occured in assembling, the editor jumps
automaticly to the 1st error, then you can jump to the next one by 
pressing alt-j. After the last one it will jump to the 1st one again.
--------------------------------------------------------------------- 
    




                The Magician.

