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.