How to use jc-assembler for the Commodore-64 Instructions for version 0.97 Please note sys 32780!!! The assembler was made by Jolly Cracker of XAKK. It was never completely finished, but it works. I won't add any new features or do anything on the 64 anymore, but the assembler is released under a BSD-like license so anyone can grab the sources and do whatever you want as long as you don't remove the license. See http://zzlevo.net/64/ for details. There are some sys-addresses you need to know to use it: sys 32768(,x): Assemble program in memory. If x is specified, it tells the assembler the max number of passes. 2 will be enough for most programs. If too few passes are specified, the assembler will give an error and you shouldn't try to run your program. If too many are given, less than one or not specified at all, the assembler will do one pass more than needed and tell you how many it really needs. sys 32771(,x): Renumber + assemble. Renumbering sets first line to 0 and next to 10 then 20, 30, 40 and so on. to renumber in another way, begin a line with two exclamation marks and then the new line number and (if you want) a space and the increment. example: 0 sys 32771,2 ! renum+assem 10 *=$c000 20 opt m1 100 !! 100 110 loop inc $d020 120 jmp loop 1000 !! 1000 5 1005 ! now renumbering will be 1010 ! done with steps of 5 1015 ! See sys 32768 for instructions about the assembly function. sys 32774,text or sys 32774"text Searches through the program for 'text'. The difference between a comma and a quotation mark is that text after a quotation mark is not tokenized. Try 'sys 32774,print' and 'sys 32774"print' sys 32777 Shows labellist after assembly. Each label is shown with its value, number of times used and name. If the label isn't used at all it will be highlighted indicating something probably is wrong sys 32780 Protect assembler from basic. Since the assembler is at address $8000 (32768), and that memory area might be used by basic (programs & variables), there is a risk that the assembler will be destroyed if this sys is not executed after the assembler is loaded. This sys also initializes the function keys and the routine that makes it possible to scroll the listing up and down. **** Always do this sys first!!! **** sys 32783,device(,4command4) Device must be 8-11 (disk drive). If command is omitted, this sys reads the error channel of the disk drive. If command starts with '$', the directory of the disk is shown. Otherwise the command is sent to the drive. During assembly, the labels are stored at $a000 and if you intend to put your programs there, see opt s. The function keys have the following defaults: f1=sys 32768,2 f2=sys 32771,2 f3=sys 32774 f4=sys 32777 f5=lO "0: ,8,1 f6=save "0: f7=sys 32783,8,"$0:*" f8=sys 32783,8," shift+r/s=load "0:*",8,1 run To reprogram any of these keys, put a zero terminated ascii string anywhere in memory (may be under the rom or the i/o) and put the start address in the following address: (lo/hi byte) $9fee 40942 shift+r/s $9ff0 40944 f1 $9ff2 40946 f3 $9ff4 40948 f5 $9ff6 40950 f7 $9ff8 40952 f2 $9ffa 40954 f4 $9ffc 40956 f6 $9ffe 40958 f8 All numeric expressions (except the line numbers and increments used by renumber which has to be normal, decimal numbers) may consist of labels, numbers or expressions obeying the following rules: To use the value of a label, just write the labelname. A decimal number is entered as normal (eg 53280). A hexadecimal number is preceded by a dollar sign (eg $d020). A binary number is preceded by a percent sign (eg %1101000000100000). An octal number is preceded by an at sign (eg @150040). An ascii value is preceded by an apostrophe (eg 'a). A screen code is preceded by an ampersand (eg &a). Expressions may be calculated using the following operators: Addition (eg label1+label2). Subtraction (eg label1-label2). Logical and (eg label1&label2). Logical or (eg label1'label2). Logical exclusive-or (eg label1@label2). Multiplication (eg label1*label2). Division (eg label1/label2). Modulus (eg label1%label2). No parentheses are allowed and calculations are performed from left to right. ('l1+l2*l3' is interpreted as '(l1+l2)*l3'.) To simulate parentheses, define a temporary label holding the value inside parentheses. Eg 'l1=l2' 1b80: '+(l3*l4)' might be written like this: 10 [pi]temp=l3*l4:l1=l2+[pi]temp (Of course it could be written like 'l1=l3*l4+l2' too...) To get the low byte of a number, use < and to get the high byte of a number use >. To make a number forced long (two bytes) use ;. Eg 'lda $02' will generate the code a5 02 while 'lda ;$02' will generate the code ad 02 00. Text strings are written as in basic, starting and ending with quotation marks. If the last character in a label is up arrow (^), then that character is replaced with a four-digit hexadecimal string (see 'mac' for details). If the first character in a label is pi ([pi]), then it's possible to redefine that label. Note that all occurrences of this kind of labels have to be defined before used! (Eg 'inc $02:bne [pi]jump:inc $03:[pi]jump' will not make the desired jump) The assembler is a multi-pass assembler doing as many passes as needed. If the assembler isn't told how many passes are needed it will do one extra as it doesn't know how many passes are needed until it's too late. You write your program using the basic full-screen editor, with the added features that you can scroll the listing up and down using the up and down cursor keys at the top or bottom of the screen and that you can use the function keys. Enter your assembler program as if it was a basic program. A simple example of an assembler program is shown last in these instructions. The assembler recognizes all standard 6502/6510 opcodes, the 'illegal' quasi-opcodes (see list below) and some pseudo opcodes. The pseudocodes are chosen so that the assembler is compatible with micro assembler with very few changes in the source code. (However, this assembler has lots of features not found (as far as i know) anywhere else!) The pseudocodes may be preceded with a full stop (.) to help compatibility with some other assemblers. '.byt 5' is the same as 'byt 5' etc. Exclamation marks are used to start a comment (like rem in basic). The pseudo opcodes are listed below: bhi x1(,x2(,x3...)) x = a numeric expression. The high byte of each expression will be stored by the assembler. blo x1(,x2(,x3...)) x = a numeric expression. The low byte of each expression will be stored by the assembler. byt x1(,x2(,x3...)) x = a numeric expression or a text string. The assembler will store the low byte of the numeric expression (giving a warning if the value exceeds $ff (255)) or the ascii values of each character in the text string. cod x x = a numeric expression. This pseudo code makes the assembler code all following bytes (code as well as data) in one of three different ways: (y is the uncoded byte) If x<256 then store x + y. If x>$feff then store (low byte of x) - y. If x is any other value then call a routine at address x with y in the accumulator. The routine should be terminated with rts when the value to store is in the accumulator. cod 0 turns the coding off. end Start next pass. (This pseudocode isn't needed if the last line of sourcecode is the last line in memory.) end ("filename"(,device number)) Load the file specified and start next pass (see lnk). lnk ("filename"(,device number)) Load the file and continue assembling. If the source code is too big to fit in memory at one time, it can be split up in several files. At the end of each file except the last one, lnk tell the assembler which file comes next. The last file tell the assembler which the first file is (for the next pass) using end. Note that some disk turbos (eg tfc or action replay) will grab some buffers in the diskdrive causing trouble if you are using opt d (see below) at the same time as lnk and end! mac Increases a two-byte counter by one. This counter can be used in labels to allow the same label in more than one place. If the label is ended with an up arrow (^) the hex value of the counter will be added to the label name (not the value!). This was meant to insert a macro, and to allow labels for loops etc inside macros, there has to be some way to use the same label in more than one place. Version 0.97 doesn't support macros, but the counter works fine! opt (m#) (d"name"(,#)) (h(,#)) (l(,#)) (s(,#)) Some extra features of this assembler: opt m numeric expression If numeric expression = 0 then don't put anything in memory (default) otherwise assemble to memory. (This assembler puts everything in ram, even under the i/o.) opt d"name"(,numeric expression) Assemble to a file on the device specified by the numeric expression (default 8). The device can't be tape, but disk is ok. When a new start address is given (eg *=$c100), the file closes and nothing more will be written to disk unless opt d is used again. See note at 'lnk'. opt h(,numeric expression) Makes a hexdump to the device specified by numeric expression (default 4 = printer). To make a hex dump to the screen, use opt h,3 opt l(,numeric expression) display the labellist (same as sys 32777) after assembly to the device specified by the numeric expression (default 3 = screen). opt s(,numeric expression) Start address of label storage. If any labels are already defined, this one will fail. Default label start is $a000 pad number(,value) Number and value are numeric expressions Generates 'number' bytes with value 'value'. If value is not specified it will be zero This could be used if you want to be sure that something will begin at a new page. The following line will do that: pad *-1&$ff@$ff scr x1(,x2(,x3...)) x = numeric expression or text string. If text string then store the screen codes of the characters, else the same as byt. txt x1(,x2(,x3...)) Same as byt. Included only for compatibility with micro assembler. wor x1(,x2(,x3...)) x = numeric expressions. Store two-byte numbers with low byte first. *=assembly start(,memory start) Sets the start of the assembly. If memory start is omitted, it will be set to the same value as assembly start. Assembly start is where the code should be put when the program is run. Memory start is where the assembler puts the code. If assembly to disk is in progress, it will be shut off when the addess is set. label=* Sets the value of the label to the current assembly address. Calculations can be done using * (see pad) Due to lack of time, the following features never were included (they were planned to be in v1.0): More pseudo codes like bas, def, hex, num, shw, if, else, endif. Possibility to use macros and conditional assembly. Disk turbo Much faster assembly (the labels are stored in a very clumsy way now) The quasiopcodes: aso $hhll 0f ll hh aso $hhll,x 1f ll hh aso $hhll,y 1b ll hh aso $zz 07 zz aso $zz,x 17 zz aso ($zz,x) 03 zz aso ($zz),y 13 zz aso #$xx 0b xx rla $hhll 2f ll hh rla $hhll,x 3f ll hh rla $hhll,y 3b ll hh rla $zz 27 zz rla $zz,x 37 zz rla ($zz,x) 23 zz rla ($zz),y 33 zz rla #$xx 2b xx lse $hhll 4f ll hh lse $hhll,x 5f ll hh lse $hhll,y 5b ll hh lse $zz 47 zz lse $zz,x 57 zz lse ($zz,x) 43 zz lse ($zz),y 53 zz rra $hhll 6f ll hh rra $hhll,x 7f ll hh rra $hhll,y 7b ll hh rra $zz 67 zz rra $zz,x 77 zz rra ($zz,x) 63 zz rra ($zz),y 73 zz axs $hhll 8f ll hh axs $zz 87 zz axs $zz,y 97 zz axs ($zz,x) 83 zz lax $hhll af ll hh lax $hhll,y bf ll hh lax $zz a7 zz lax $zz,x b7 zz lax ($zz,x) a3 zz lax ($zz),y b3 zz dcm $hhll cf ll hh dcm $hhll,x df ll hh dcm $hhll,y db ll hh dcm $zz c7 zz dcm $zz,x d7 zz dcm ($zz,x) c3 zz dcm ($zz),y d3 zz ins $hhll ef ll hh ins $hhll,x ff ll hh ins $hhll,y fb ll hh ins $zz e7 zz ins $zz,x f7 zz ins ($zz,x) e3 zz ins ($zz),y f3 zz alr #$xx 4b xx arr #$xx 6b xx oal #$xx ab xx sax #$xx cb xx axa #$xx 8b xx axl ($zz),y 93 zz skb 80 skw 0c crs 02 An explanation of (most of) these instructions is found in 'programming the Commodore 64 the definitive guide' from compute! Isbn 0-942386-50-7 That's a good book about the c-64!!! Now for the sample program: 0 sys 32771,2 ! assemble with run from basic 10 *=$d000 ! code routine under i/o 20 opt m1 ! code routine is used during assembly, assemble it first and 30 ! make sure it will get into ram! 40 codebyte=$37 ! the byte used to code the program 100 !! 100 110 coderoutine eor #codebyte ! byte to code is in .a 120 rts ! simple type of coding... 1000 !! 1000 ! start the real program 1010 *=$c000 1020 opt m0 d"my program" l ! assemble to disk, not ram, show labels 1030 lda #start:sta $03 ! uncode text 1040 ldy #$00 1050 mac:loop^ lda $02:cmp #stop:beq start ! everything uncoded? 1070 uncode lda ($02),y:eor #codebyte:sta ($02),y ! uncode a byte 1080 inc $02:bne loop^:inc $03:bne loop^ ! loop^ = loop0001 2000 !! 2000 ! the program (coded before start) 2010 cod coderoutine ! start coding 2020 start lda #text:sta $03 2030 ! .y is already 0 2040 mac:loop^ lda ($02),y:beq alldone !.loop^ = loop0002 2050 jsr $ffd2:iny:bne loop^ ! display character (loop^ = loop0002) 2060 alldone inc $d000+32:jmp alldone 2070 text byt $93,"this text will be displayed on the",13 2080 byt "screen, but it is coded after load",13,13 2090 byt "this program may only be run once!",0 2100 stop ! end of coding The assembler and the source can be found at http://zzlevo.net/64/ My e-mail address is jc@zzlevo.net