PRO-LINE SOFTWARE PAL 64TM Toolkit for machine code programmers includes: supermon 64 unassembler 64 palverter64 PAL 64 Manual PAL 64TM Programmed for the Commodore 64 Computer and Commodore 1541 Disk Drive. Program by: Brad Templeton Manual by: Brad Templeton Manufactured and distributed exclusively by: Pro-Line Software Ltd., 755 The Queensway East, Unit 8, Mississauga, Ontario, L4Y 4C5. (416) 273-6350 Programs Copyright (c) 1983 Brad Templeton Manual Copyright (c) 1983 Brad Templeton PRO-LINE SOFTWARE LTD. 83-08-03 PAL 64 Manual TABLE OF CONTENTS 1. Introduction to PAL 64. 2. Basics of Using PAL. 3. Source Line Format. 4. Expressions. 5. Pseudo-ops. 6. Error Messages. 7. More Notes. APPENDIX A: PAL Environment. APPENDIX B: Internal Routine Vectors. APPENDIX C: PAL Memory Maps. APPENDIX D: Converting CBM/MOS Assembler to PAL. APPENDIX E: Extra Files. APPENDIX F: The Relocatable Object PAL. APPENDIX G: The PAL Relocating Loader. PRO-LINE SOFTWARE LTD. 83-08-03 PAL 64 Manual 1. Introduction Personal Assembly Language 1. Introduction PAL stands for Personal Assembly Language. It is a program that takes a program written in symbolic format and converts it to machine code that the 6510 processor in the CBM 64 can execute. Such a program is called an assembler. To use PAL 64, you should have some familiarity with the machine language of the 6510. You should know what instructions it can perform, what ways it can address its data, and the general principles of its operation. Machine language programming is quite different from other sorts of programming, such as you might do in BASIC. You have to tell the processor exactly what to do, using statements that play around with data in its simplest form, manipulating machine registers individually. Naturally, there are advantages to knowing how to do this. For one, programs written in machine language run much faster than those written any other way. They can often also be made more compact than BASIC programs, even though they run all on their own without an interpreter. In addition, there are some things you want to do that just can't be done in BASIC, such as playing with Interrupts. The new world opened up makes the work to understand machine language worth it by far. What is called machine language is just the string of bytes that the processor executes. This is not easily read by a human, nor is it easily manipulated or written by one. To help in this task, an assembler, like PAL, comes in. PAL lets you write a program in a symbolic fashion. You use mnemonics to represent the operations the processor can do. You get to specify the addressing modes of the processor in a symbolic way. Best of all, you can assign values to symbols so that programs are more readable and can be modified much more easily. The essential purpose of an assembler is to help you abstract your program from the actual bytes as much as possible without taking away the ability to do intimate tinkering with the hardware of the machine. An assembler takes an abstract program, called the source, and turns it into a machine program, called the object. A line of the form "LDA #10" gets turned into the string of bits "1010100100001010". You may have run into several assembler programs in your experience with computers. There are others for other Commodore computers, such as the one produced by Commodore itself. These differ from PAL in ways that will be described below. In addition, you may have heard of macro assemblers. These are programs that include some form of what is called a macro package. Macros allow you to abstract your program even more by allowing you to define statements that imply large and complex text substitutions based on arguments provided to the macro statement. PAL does not as yet provide Page 1 PAL 64 Manual 1. Introduction such a feature. There are several reasons for this, one of which is that PAL 64 fits in just over 4K bytes of 6510 machine language code. Macros are a complex feature and could not easily be supported in such a small amount of memory. PAL 64 is of the size that it can easily be burned into a single ROM chip that may be adapted to the CBM 64 cartridge port and reside there at all times. 1.1 Features of Note What PAL 64 provides that many other assemblers do not is a high level of convenience. First of all, it fits in just over 4096 bytes of memory as described above. It can quietly sit in your machine, taking up only this small amount of memory. It can also be put together with POWER 64 in one 8K block of memory, which allows it to be put with that program in a cartridge that plugs in the back of the machine. With this version, you never have to worry about loading it from disk or losing it. PAL 64 was designed to fit in as much as possible with the BASIC environment that the CBM 64 owners know so well. Because of this, it is hoped that new assembler programmers will be able to use PAL to move into the world of assembler programming from BASIC more easily. Many of the operations involved with using PAL are the very same operations that are used by BASIC programmers. PAL achieves this similarity with BASIC by using the BASIC program format for its source files. PAL program lines are typed in and worked with in exactly the same way that BASIC programs are worked with. This means that you use the line numbered editor of BASIC to enter and change your program. You use the BASIC SAVE and LOAD commands to store your programs on disk or tape. In addition, you can use packages that enhance the editing power of BASIC to help you with your program. I suggest you use the package known as POWER 64 published by Pro-Line Software Ltd. of Mississauga, Ont. This package was written by myself, and is used together with PAL 64 for all my 6510 software development. Of course, you can use any such package to develop your programs. You should use whatever you are comfortable with. POWER 64 does have one feature to help PAL 64 users that will be detailed later. PAL assemblies are accomplished just by typing RUN when you have a PAL source file in the machine. As you know, a RUN command starts up a BASIC program - so how does one get this to start an assembly? The answer is to make the first line of your program a BASIC statement to start the assembler. This is the SYS statement that you will grow to know and love as you your experience with assembler. PAL will sit in your CBM 64's memory at some location. Most commonly this is around address 9000 hexadecimal, sitting right at the top of memory. Since the place PAL loads depends on your memory configuration, PAL stores where it is located when you load it from the disk. The new address is put in what is called a vector in what machine language programmers refer to as page 2 of machine memory. The magic number you need to know is 700. To get PAL to run when you Page 2 PAL 64 Manual 1. Introduction say RUN, you simply make the first line of you program a SYS to call PAL. For example, no matter where PAL is loaded you might have something like: 10 SYS 700 with this system, you can assemble your program just by typing RUN. Page 3 PAL 64 Manual 2. Basics of Using PAL 2. Basics of Using PAL Before you learn anything more about PAL, you should know how to load it and play with it. As you will read later, there is a version of PAL that allows you to generate machine programs that will load anywhere in memory. This version has been used to generate the PAL that is on your disk. If you look at your disk directory, you will find a number of different files on it. The first will be called "PAL". To load in a copy of the assembler to use, just load that file into memory and type RUN. This will load a 4.1K copy of PAL at the very top o memory in your CBM 64. The top of memory is defined by two bytes in zero page at locations 55 & 56(decimal). If these bytes contain the value $A000, then PAL will load starting at just below $9000 and the pointer will be moved down to point there. This means that BASIC will not touch PAL any more, since it thinks physical memory ends where that pointer says it does. Most other programs are the same way. After the program is loaded, it is executed. Since it was not called from within a BASIC program, PAL does nothing but print some data. You will also see a copyright notice and some numbers that are currently meaningless to you. You now have PAL in your machine. It should be noted that every time PAL executes, it alters the top of memory pointer to point to itself. This means that when you load in you fresh copy of PAL, you can sys to the first location in it and have your copy of PAL sealed away at the top of memory, safe from BASIC. PAL will never alter the top of memory pointer to something higher than it already is, however, so if you combine PAL with other programs that sit at the top of the CBM 64 memory, like a fancy monitor, executing PAL will not unseal these programs. The same is true if you put PAL in rom. After loading PAL, it may be necessary to do a new or POWER FIX to restore some of BASIC's pointers. This is common in the loading of machine language programs. 2.1 Special Loading Problems You may want to load PAL in some special way not provided for by the "PAL" file. For this purpose, a file with the relocatable object is included on your disk. It's name is "PAL.R" where the .R stands for relocatable. You can load PAL anywhere you like, using the "FLOADER" program found on your disk. See the section on the relocatable output version of PAL for details on how to use the FLOADER. You will need to use it, for example, if you want to make a version of PAL you can load directly or one that goes into EPROM. You should note that such a version of PAL does not run from its first address and will not store the right address at 700. You will have to set up something to do this. PAL is pure code, ie. it does not modify itself, so it Page 4 PAL 64 Manual 2. Basics of Using PAL can be safely burned into ROM. If you make a version of PAL that loads without relocating, you should note the following: Every time PAL executes, it alters the top of memory pointer to point to itself. This means that when you load in your fresh copy of PAL, you can SYS to the first location in it and have your copy of PAL sealed away at the top of memory, safe from BASIC. PAL will never alter the top of memory pointer to something higher than it already is, however, so if you combine PAL with other programs that sit at the top of the CBM 64 memory, like a fancy monitor, executing PAL will not unseal these programs. After loading PAL, it may be necessary to do a NEW or POWER FIX to restore some of BASIC'S pointers. This is common in the loading of machine language programs. 2.2 A Simple Assembly To see how PAL works, try a sample program. First load in PAL as described above. Now type NEW to make BASIC ready for a new program. If you have loaded PAL from a pre-saved version you made yourself, and done it with the machine language monitor, you need not type NEW. If you have POWER in place, you can use the PTR command instead. Now type in the following sample program. Note that the SYS line at the beginning of the file is what calls the assembler. No matter where PAL is loaded, this is the address you will use to call it. 10 SYS 700 20 .OPT P,OO 22 ;SAMPLE TEST PROGRAM 25 *=$C000 30 LDX #0 40 LOOP LDA 0,X ;GET BYTE FROM ZERO PAGE 50 STA $400,X ;STORE IT IN SCREEN MEMORY 60 INX 70 BNE LOOP 80 RTS The above simple program transfers 256 bytes of memory from zero page to the screen. You can see it loading the accumulator with a byte from zero page indexed with the X register, and storing that same byte into screen memory, which begins at $400 on the CBM 64. After the store, it bumps the X register with "INX" and tests if the register has looped up to zero again. If it has, it returns with the RTS. If you did not understand this simple program, you should consider going back and reading some more about the 6510 processor. Some things you might want to note about the listing. First, as pointed out before, it is just like a BASIC listing, except we're dealing with assembler here. Secondly, it is free format. There is no indentation like you might see in a normal assembler listing. The statement on line 40, which has a label called "LOOP" is indented no differently Page 5 PAL 64 Manual 2. Basics of Using PAL from the others. Thirdly, the statement on line 20 starts with a dot, and looks like no assembler mnemonic in the 6510 set. What does this all mean? As you have learned, PAL files are just like BASIC files. It is the SYS at the beginning that makes them special. Otherwise, PAL follows fairly closely what is called the "MOS Assembler Standard". MOS is the company that first make the 6510. Along with the chip, they defined a standard of what an assembler program for the 6510 should look like. This included listing all the mnemonics and giving a syntax for expressions and all the addressing modes. In addition, some special operations, called "pseudo-ops" or "directives" are defined. These are not machine instructions, but rather instructions to the assembler. You use them to work with symbols and to do all sorts of special things that don't generate machine instructions. This MOS assembler standard is the one you will most commonly see in books on the 6510. Many assemblers do not adhere to this standard, however. Peter Jennings' Micro-Adetm, which was the assembler that the first version of PAL was written in, (PAL now assembles itself, of course) takes a very different syntax. MAEtm by Carl Moser is not as different as "Micro-Ade", but differs quite a bit on some matters. The assembler put out by Commodore itself is quite close to the standard, since MOS is owned by Commodore and they defined it. PAL is also quite close to that standard. in reality, it accepts far more things than are defined there, and so can be considered a superset. There are some things in the standard that PAL does not handle, and these are described in Appendix D. This means, however, that with a minimum of work, you should be able to take a MOS standard program and assemble it with PAL. One of the rules n this MOS standard is that assembler files should be free form. No indentation is required to distinguish things. PAL figures out if the line is a machine operation, a statement with a label, or one of its own pseudo-ops. PAL knows a statement has no label if the first word on the line is one of the 56 mnemonics in the 6510 set. This means that you cannot use a mnemonic name like "LDA" for a label. If a statement begins with a word that is not a mnemonic, it is assumed that it is a label. Words that begin with dots or special symbols are expected to be pseudo-ops, however since a label must begin with a letter. PAL goes beyond this in allowing free form, however. In PAL, you can pad your statement with spaces to make it look nicer as you please. You can put as many spaces you like between operators, mnemonics and operands, just as you can in BASIC. You must have a space between major parts of a statement, like between a label and the opcode, and between the opcode ant the operand, but otherwise you may pack things together as you please. The line at the top, ".OPT P,OO", is a pseudo-op. In this case, it gives output options to the assembler. The P Page 6 PAL 64 Manual 2. Basics of Using PAL means you would like a printout of the program, and the OO means you would like the machine or "object" code of the program put where it is "origined". This just means that the program will be put right into memory where it is supposed to run. If you recall from your 6510 readings, the line "*=$C000" sets this "origin" to be address $C000 (PC defaults to here when origin not specified). In general, "*=" is a pseudo-op that sets the assembler's "program counter". You will learn more about it later. Now that you understand a little about the program, you are ready to try it. Type "RUN". You should instantly see a listing of the program in a big fancy format. At the bottom will be a line of the form "]C000-C00B" which indicates the object code runs from address $C000 to $C00A (The last number is always one more than the last byte, and is the one you should use in saving the program with a machine language monitor). If you got any error messages, you should check to make sure you have entered the program correctly. The listing you get is quite a bit more voluminous than the program you typed in. For one thing, you can see that it is all neatly indented and formatted the way a program listing you see in a book is. PAL has taken your free format program and put it out in a more readable format. At the beginning of each line, you can see the BASIC line number that the statement came from followed by a colon. This is for your reference, so you can see where in the program our listing comes from. This is followed by the hexadecimal address of the code for that statement. This is what is referred to as the "program counter" of the assembler. The "*=$C000" set the program counter, and you should see that number as the first one at the top of the program. The address is followed by the bytes (in hex) generated by that statement. This is the actual machine code that the assembler produced. Up to three bytes are shown. After these bytes is an area for any label put on a statement. in your program, most lines will have this area blank, except for one, which has the label LOOP in it. After the label comes the opcode or pseudo-op of the instruction, such as the "STA" on line 50. Two spaces after this comes the operand for that statement. Further on, you find the comment if there is one. You will also note one exception to this listing format, and that is the line with only a comment on it. Comments, as you can see, begin with a semicolon. In this case, a line with only a comment on it is listed as just that comment with no other information. The comment begins in the label field. Now that you have seen the listing, you can try the program. If you have a dissassembler, such as that in "SUPERMON" which is included on the PAL disk, you might want to go into it and look at the program at $C000. Otherwise, just type "SYS12*4096" from BASIC and that will run your program. You should see a bunch of garbage appear at the top of your screen. Some of it may be in bright white because you did not copy the color table. This is zero page. If Page 7 PAL 64 Manual 2. Basics of Using PAL this happens, you have done your first PAL assembly. You are now in a position to try further programs, depending on your knowledge of 6510 assembler. You might try making changes in the program you have typed in, moving it in memory, or perhaps chaining where on the screen you dump the memory. After you make a change, just type RUN and the program will be assembled. 2.3 An Assembly An actual assembly is a complicated process. The most important thing you should know about a PAL assembly is that it is what is called "two pass". This means that PAL reads over the source file two times. On the first pass, PAL figures out how many bytes each statement will take up in memory. It does this so that it can figure the location of each statement and set the program counter properly. All labels are given their value on the first pass. Certain pseudo-ops, which you will see described later, only operate on the first pass. After PAL completes the first pass, it begins to read the source again. Before it does this, it prints the digit "2" on the output to indicate that the second pass has begun. It is in this pass that PAL actually generates the machine code for the program. It is also on this pass that PAL prepares any printed listing that is desired. In the second pass all expressions are evaluated as well. Certain error messages occur in each pass, and some occur in both. You will thus get some error messages twice. See the section on errors to figure out the differences. Some expressions get evaluated on the first pass, so expression errors can occur on any pass. When PAL reads in a statement from your program, it goes through the following process. First, it parses (splits apart) your statement into the major components. These components are described in the next section. After it does this, it figures out what kind of op or pseudo-op this line contains. On the first pass, symbols are assigned. On the second pass, pseudo-ops are worked through and instructions are decoded. Expressions are evaluated and the code is generated. Finally, a listing of the line is given if requested. If there is an error, a listing of the line is given under any circumstances, and code is generated with a zero in the first byte. After all this, PAL goes on fetch the next instruction. At any time while PAL is running, you can hit the STOP key on your keyboard to abort the assembly. You should note that you cannot restart the assembly after doing this, and you will have to go back to the beginning. On a long assembly, PAL gives you some idea of what is going on by always printing .FILE statements whether you have asked for printing or not. This way you can see both what file is being processed, and how many bytes have been Page 8 PAL 64 Manual 2. Basics of Using PAL assembled so far. The statement is listed after the file and has been read properly into memory. See the section on pseudo-ops for more details on .FILE. Page 9 PAL 64 Manual 3. Source Line Format 3. Source Line Format Let's go into some more detail on the format of a source line to PAL. A full source line looks like this: LABEL OP OPERAND;COMMENT As noted above, the entry is "free form", so typing in stuff is fairly easy. On the other hand, you might feel that a free format listing is difficult to read and hard to play around with. It is harder to spot the labels, instructions and comments because they do not all line up like you are used to in a listing. If you feel this way, you may wish to pretty up your listing with proper indentation of the various parts of the line. Unfortunately, the CBM 64 BASIC editor will delete any space you put at the beginning of a line. This means if you put spaces before an unlabelled statement to indent it, all the indentation will go away and you are back where you started from. To help this, PAL will ignore the up arrow character (^) if it is at the beginning of the line. If you wish to indent a line, just type an up arrow followed by the number of spaces you wish to indent by. Since PAL allows 8 character labels, you probably want an up arrow and 8 spaces. If you have a package like POWER, you can probably define a key to do this. To indent the rest of your program, you can include spaces as you desire, since PAL will not be affected by them. 3.1 Labels Any normal PAL statement can have a label. This will assign that label to the value of the PAL program counter at the beginning of the assemble of that statement. Normally, you only want to label statements that generate output, like machine instructions and some pseudo-ops. All statements can be labelled, however. This label can be as long as you like, and must be terminated by a space. You should be warned, however, that only the first 8 characters of the label will be recognized in comparison. This means that the labels "BIGLONGLABEL" and "BIGLONGLIBEL" will be considered the same by PAL. The first character of a label must be a letter. The following characters may be either a letter or a digit. The label at the beginning of a statement should always be followed by a space to divide it from the remainder of the statement. As noted previously, a label may not be the same as one of the 56 three letter mnemonics for 6510 instructions. Nor should the label A be used, since this letter can indicate the accumulator addressing mode. You should note that you can not have a statement with just a label on it. Some assemblers allow this, but PAL does not, as i is more likely that a statement consisting of just a string of letters is some kind of accidental mistake. If you just want to assign a label to the value of the program counter, you can try a statement o the form "LABEL = *". Explanation of that statement follows later. Page 10 PAL 64 Manual 3. Source Line Format 3.2 Opcodes and Operands After the label comes the most important part of the statement, called the op. This can either be a machine opcode or a pseudo-op. If there were no label on the statement, this would be the first thing on the line. The op field is short. All machine opcodes are three letters long, and the pseudo-ops are from one to 5 characters long. After the op can come the operand. Many ops do not take operands, so this may not always be present. If it is, there must be a space between it and the op. The operand will usually consist of some syntactic constructs and an expression to give the value of the operand. PAL expressions can be quite complex, and so the whole next section of the manual is devoted to them. For initial experiments, you can make your expressions consist of simple things like numbers in decimal and labels. 3.3 Addressing Modes The operand of a machine instruction should usually give the addressing mode you wish to use for that instruction. The 6510 has a wide range of addressing modes which you will find detailed in various books on the subject. Not all addressing modes can be used with all instructions, so you have to be careful what kind of instructions you use. PAL will tell you if you try to use an invalid combination by issuing an error message. Below the syntaxes for the various addressing modes are given. Since most operands include an expression with the addressing mode, the characters "expr" are used below to indicate where the expression should go. For example, if the syntax for "immediate addressing" is given as "#expr", that indicates you statements with immediate addressing should like something like "LDA #5". The various modes are as follows: Syntax Name Example #expr Immediate mode addressing LDA #10 expr Absolute o relative mode addressing JSR SUBRU A Accumulator addressing (shift instructions) ASL A A blank operand also gives this. ROL expr,x Absolute addressing indexed by the X register LDA TABLE,X expr,y Absolute addressing indexed by the Y register LDA TAB2,Y (expr,x) Zero page addressing indexed by the X LDA (PTAB,X) register followed by indirection (expr),y Zero page indirection indexed by the Y register LDA (PTR),Y (expr) Indirect addressing for JMP instruction only JMP (VECTOR) In your reading about the 6510, you will have read about zero page addressing modes. In PAL, you only use absolute addressing modes on your instructions. PAL will figure out if it can use a zero page instruction in place of the absolute one, and do this if it can. Normally you need not worry about the problems of zero page addressing. There are a few pitfalls to watch out for though, and these are Page 11 PAL 64 Manual 3. Source Line Format described in the section on expressions in the part about "modifiers". Normally you should have no worries. Some of the explicitly stated addressing modes, like those involving indirection, must work in zero page. You should make sure that expressions provided for those modes correspond to the 6510 zero page. It is also important to note that conversion on an addressing mode to zero page must occur on pass one. This means that any symbol used in a zero page operand must be defined before it is used. Otherwise, PAL will think that it has a normal operand on pass one and a zero page operand on pass two. This will cause a phase error, explained in the error appendix. Make sure you define all zero page symbols at the front of your program, before you use them. 3.4 Comments At any point, after the last valid thing in a statement, a comment may come. You separate the comment from the rest o the statement by a semicolon. You need not put a space before the semicolon if you desire not to. As you see in a listing, comments are indented a short space after the operand, and bumped to the right if the operand is long. Your comments will thus line up to some degree, but you also have some control over the matter. In addition, you may have noticed you can have a line that has nothing on it but a comment. Such a line begins with a semicolon and contains a plain text after it. These lines get special treatment in a PAL listing. The comment is printed, starting in the label field, with the semicolon in the second column of that field. You will note that the line does not have a line number or address printed with it. This helps the comment to stand out in your listing, and means you can put small gaps in your listings with a comment line. Many assembler programmers feel it is good style to leave lots of blank lines in a program to separate out its various parts. You can do this with comment lines. PAL will also handle a blank line. This will be printed in the listing with no label, opcode or operand. Normally, it is not possible to put a blank line into a CBM BASIC file, but you can do it with the use of colons. You should now have a basic understanding of what a PAL source line looks like. You can look at some of the sample programs that can be found in this manual and with your copy of PAL. With this knowledge, you can begin to type in programs using the 6510 instructions you know. Make sure to have a listing generated when you try things out. To do this, include the statement: .OPT P at the top of your programs. Naturally, in the course of your experimentation, you will make some errors. PAL will spot most of these for you, and print out error messages. Page 12 PAL 64 Manual 3. Source Line Format There are a number of such messages, all of which are detailed in an appendix. The most common one you will get is a SYNTAX error. Hopefully, the error will be obvious enough for you to figure out the problem. If it is not, you can refer to the section on errors for extra help. 3.5 Multiple Statements There is one more important feature of PAL involving the format of source lines. If you have used BASIC, you will know that you can put more than one statement on a single line by separating statements with colons. You can do the same trick in PAL. If you wanted to use the PLA instruction of the 6510 twice to pop the stack of the machine twice, it is possible to write it as: 100 PLA 110 PLA But it is also possible to say: 100 PLA:PLA You can do this with full PAL statement lines too, for example: 100 BRLAB LDA #23;LINE COUNT:STA LNCNT;SAVE IT You see that you can even include a comment on the first statement. This means, by the way, that you can not normally use the colon character in a comment, as you might make PAL think it is starting a new line. If you really must have a colon in a comment, you can enclose it in quotes. Just like BASIC, PAL does not pay attention to special meanings of characters like a colon when they are enclosed in double quotes. When you use a colon to put two statements on one line, the two lines still show up in the listing separately. They will both be given the same line number in the listing, but otherwise there will be no way in the listing to tell they were on the same line. Normally, using this feature is not encouraged. It will tend to make your programs more cluttered and difficult to read. It does save space however, and you may be forced into it. In addition, it is necessary to use this feature with the .IF pseudo-op which you will read about later. Page 13 PAL 64 Manual 4. Expressions 4. Expressions A good part of the power of PAL resides in its expression evaluator. This is the part of the program that calculates the values of the instruction operands from the expressions you give. In some assemblers, you may only specify the value of these operands n a fairly simplistic way. PAL, in helping you to abstract your program as much as possible, allows you to use complex expressions involving a wide set of operators and operand formats. BASIC allows you to use expressions in most places that it requires a value. The same is true of PAL. You must remember, however, that PAL is working with the 16 bit values that an assembler programmer deals with rather than the floating point numbers BASIC uses. In addition, you should note that the order of evaluation o the terms in a PAL expression is strictly left to right unless parentheses are used, and does not depend on the operator involved. Expressions consist of terms and operators. Terms are essentially values, like numbers. Operators give operations like addition and subtraction. 4.1 Term Formats A term in a PAL expression can take one of the following forms: Decimal - You can use a decimal number, just like in BASIC. The number may be anywhere from 0 to 65535. The number is typed in straight. For example: LDA #10 loads the accumulator with the decimal value 10. You can get negative numbers with the unary minus operator described below. Hexadecimal - Many assembler programmers like to work with numbers in hexadecimal, since it makes it easier to cope with the binary nature of the machine. You can give a hexadecimal number by preceding it with a dollar sign ($). You need not put any leading zeroes on your number if you do not wish to, as is demanded by the CBM 64 output routine, you could enter: JSR $FFD2 where FFD2 is the hexadecimal address of the entry point for that machine language routine. Binary - Machines work in binary, and sometimes you wish to provide your numbers in that format. This might be the case if you had to deal with a string of bits in operations involving AND and OR instructions. Quite often you will find that you Page 14 PAL 64 Manual 4. Expressions have to deal with single bits in some of the I/O hardware of the CBM 64. You can enter your operand in binary by preceding it with a percent sign (%). For example, to OR in a one to the second least significant bit of the accumulator, you could type: ORA #%00000010 and that would do the job. The leading zeroes are not needed at all, they are just there for effect, since a single byte involves eight bits and we are dealing with one. If all this "bit-banging" means nothing to you, don't worry about it. When you begin to work in this area, just remember that you can provide your values in binary when the need arises. Program Counter - If you want, you can use the value of the assembler's program counter as the value of a term. This can be done if you want to work with an expression relative to the location your statement will run in memory. Use the symbol star (*) for this. Star has the value of the assembler program counter before the current instruction is processed. For example, if you wanted to loop forever, you could code: JMP * Such a program is not of much use though! More commonly, one likes to assign a symbol to the program counter. Many programmers, the author included, like to assign major labels with the sequence: SUBRTN = * LDA #10 ;START OF ROUTINE rather than SUBRTN LDA #10;START OF ROUTINE These two bits of code mean the same thing, but the first method makes it much easier to insert instructions at the beginning of the routine. There are many other uses for star, including figuring out the lengths of tables. If you had a table of values, and wanted a symbol to be equal to the length of that table, you could say: TABLE = * ... values ... TABLELEN = * - TABLE You will note that we have subtraction and a few other features here. You can read more about them below. Page 15 PAL 64 Manual 4. Expressions Character - You may want to work with ASCII characters. Rather than remembering that the CBM 64 printing code for an "A" is 65, you can just type the character surrounded by double quotes. To put an A in the accumulator, try: LDA #"A" Use of this is very similar to the use of the ASC function in BASIC. Just like the CBM 64, you don't need to put on the closing quote if there is nothing else on the line. It really isn't good practise to leave it off though Label - As you have seen in some cases above, you can use labels as terms. the syntax for labels is given in the section on statement syntax. Using a label means using the value you assigned to it by some means. You will want to use labels as much as possible in expressions, since they help you abstract the program. If you have any value you can assign a symbolic name to, it is best to do so, since it will make your program easier to read. In addition, if his value changes, you need only change it in one place in the program. Expression - You can use a complete expression as a term if you include it in parentheses. This allows you to change the order of evaluation when the value if the expression is calculated. For example, "($100+4)" is a valid term. You will see more examples of this later. Negation - You can use the negative of any term by placing a negative sign in front of it. Most commonly you wish to have the negative of decimal numbers, but you can negate labels and whole expressions in parentheses if you want. Quite common is something like: LDA #-1 User expression - If there is some format you want that can't be provided by those methods listed above, you can have PAL call your own routine to calculate an expression. You do his by placing an at-sign in the expression. You can follow the at-sign with data to be read by your routine. An old version of PAL had it arranged so that you could use a BASIC expression, with BASIC variables and functions like PEEK and POKE right on a PAL line. To do this you need a fair bit of familiarity with the PAL operating environment. That's in an appendix. 4.2 Operators To make expressions, you combine terms with operators. PAL operators are all binary, which is to say they take a Page 16 PAL 64 Manual 4. Expressions left and a right operand, just like the operators you know in BASIC. In PAL, the operators are: + Add values - Subtract values * Multiply values ! Boolean OR values & Boolean AND values ^ Boolean exclusive OR values > Shift left argument to the right by the number of bits given in the right argument < As above, but shift left. All these operators take 16 bit values, but some of them would be silly to use with large values. It would be silly to multiply by a number greater than 32767, or to shift by a number greater than 15. Multiplication that creates a number that can not be held in 16 bits will produce an ILLEGAL QUANTITY error from PAL. The remaining operators don't give such errors, since overflow is often quite legitimate in the realm of the signed two's complement arithmetic the 6510 uses. The following examples show that you can combine terms with operators as you please. You should remember that a PAL expression is evaluated left to right as it is encountered. For example, the result of "5+4*3" in PAL is 27, since the expression is evaluated as "(5+4)*3". In BASIC, the value would be 17. If you had wanted the order that BASIC gives, you could have tried "5+(4*3)", since the parentheses alter the order of evaluation. You may have noted that certain 6510 addressing modes are expressed by putting the expression in parentheses. This might cause a conflict with the parentheses used to change the order of evaluation in an expression. Fortunately, since PAL evaluates left to right, you need never begin an expression with an open parentheses. The ordering you might obtain from doing this is already the natural ordering PAL gives you. 4.3 Modifiers Quite often you wish to do some special things to an expression to make it fit what the 6510 wants for an operand. Quite often, for example, if an instruction takes a one byte operand, you might wish the upper (most significant) byte or the lower (least significant) byte. It is quite common to do this when manipulating the 16 bit registers; you have to do them one byte at a time. To help you do this, PAL expressions can have modifiers placed upon them. There are three modifier characters: "<", ">", and "!". These characters can only be placed at the from of a complete expression that is to become am operand - you can not place them on subexpressions in parentheses. The "<" modifier makes the result of the expression the Page 17 PAL 64 Manual 4. Expressions lower byte or "half" of the 16 bit value generated. In many ways, "" modifier works like "<" but gives you the upper byte or half of the 16 bit value. Using ">expr" is similar to "expr>8", which shifts the expression right eight bits. You will find use of these operators quite common, normally with immediate mode addressing and with certain pseudo-ops. 4.3.1 Forcing Absolute Addressing As mentioned above, PAL will turn the addressing mode of an instruction into a zero page mode if it can. In rare cases, this could have bad consequences. Normally a shift to a zero page mode causes no harm to the program, since the operation performed by the zero page instruction is the same as that of the absolute instruction. The exception is in the case of indexed addressing modes. The zero page indexed modes pretend that the machine only has an eight bit address space - that is to say, 256 bytes. This means that if you take the zero page base 250, and index it off with, say, a register containing the value 20, you will address the byte at location 14 rather than the one at 270. You might run into this problem inadvertently with a sequence like: TABLE = $100 LDA TABLE-1,X PAL will generate a zero page instruction here, which is probably not at all what you want. You can force PAL to use absolute addressing modes by putting the "!" modifier on your expression. In this case: LDA !TABLE-1,X will give the desired result. 4.4 Sample Expressions Here are some sample PAL lines with expressions to show some of the uses of the expression evaluator. The program doesn't do anything. START LDA TABLE-1+(TABLEN*2) STA $8000 LDA #>START-1 LDA #SIZE>3;SHIFT RIGHT 3 MEANS DIVIDE BY 8 LDA #-12 CMP #12 ^ $FFFF + 1;SHOULD BE SAME AS -12 SBC #"A"-"O";DIFFERENCE BETWEEN A AND O LDA TABLE+(ENTRY*ENTSIZE)+OFFSET;A TABLE ENTRY STA SCREEN+(LINELEN*LINE)+COLUMN;A SCREEN POSITION CODELEN = * - START;HOW MUCH CODE SO FAR LDA #CODELEN;PUT HALVES IN REGISTERS JSR FANCY;SUBROUTINE Page 18 PAL 64 Manual 4. Expressions STRING .ASC "YOUR NAME HERE" STRLEN = * - STRING 4.5 Uses and Errors You now should have some idea of how to form a PAL expression. You can use the complete power of the expression evaluator in the operand of any expression. In addition, you will read about several other places where an expression can be used. Be sure to take full advantage of this ability. Never calculate out the value of an expression by hand and fill it in for PAL. If you do this, you'll just have more work figuring out what to do if one of the parameters of the expression changes. At the same time, make sure you use labels as much as possible. A good assembler program will see almost no constants in the operands of instructions, unless the constant is really what is desired. A number of errors can pop up while using expressions. Check the appendix on error messages if you run into one. Most of these will be SYNTAX errors, of which there are ten different types. Page 19 PAL 64 Manual 5. Pseudo-ops 5. Pseudo-ops Even though you should now have a reasonable understanding of how to put together a program, you will still find you can do very little without the use of pseudo-ops. These pseudo-ops are so named because they appear in assembler statements in the same place as the op of a real machine instruction. They are not real ops, though, and don't normally generate machine instructions. In PAL, there are two kinds of pseudo-ops. The first kind consists of those made from special symbols. The second kind all have mnemonic names just like ops, but they all begin with a dot character. They will be treated one at a time. For each pseudo-op, the syntax will be given along with a description o how to use it. First, the special character pseudo-ops. 5.1 = Syntax: label = expr The equals pseudo-op can be used to assign a value to a symbol, just like in BASIC. The difference is that you may assign a value to a given symbol only once. Any symbol may normally only be defined in one place, either by being on the left hand side of a statement or by means of an equals. Equals, like all once-only symbol assignments, is performed only on pass one. If you attempt to redefine a symbol with equals, you will get a REDEFINITION error. 5.2 _ Syntax: label _ expr The assignment and equals pseudo-ops are very similar. The assignment pseudo-op (_) can be used, however, to assign to a symbol that already has a value, and thus to change that value. Assignment is done on both passes, so a symbol can be assigned, changed and changed back. It is generally a good idea to use the assignment pseudo-op on a symbol in all places where it is assigned if it is used at all. Since other forms of symbol assignment only operate on pass one, you might get a nasty surprise on pass two when a symbol has the strange value given it by a _ back in pass one, immediately after it appears to have been set in the source by equals. Some examples: VALUE _ 100 ;QUITE SIMILAR TO EQUALS COUNT _ COUNT-1 ;DECREMENT A SYMBOL CURRENT _ * ;SET A VARIABLE TO THE CURRENT PROGRAM COUNTER 5.3 *= Syntax: *=expr Page 20 PAL 64 Manual 5. Pseudo-ops The "star equals" pseudo-op is quite useful. Just as it appears to do, it sets the program counter, which is known in expressions as star. Although it need not be given a label on the left hand side, it usually is, since this op takes on many functions, including reserving blocks of space and assigning blocks of symbols. 5.3.1 Program Origin The first use of *= is to set the origin of the program you are assembling. You must tell the assembler where you want the program to run. You do this by means of *=. As you saw in the first sample program, we set the initial program counter, or 'origin' to $300 (?). You can use *= as the first statement in your program to set the origin wherever you like it. This is one use of *= that does not usually get a label on the left. You can also use *= to jump around in memory assembling code at various places. You may only do this when your object is being output in two very special manners, however. 5.3.2 Allocating Blocks You use *= to allocate a block of memory inside a program for a table or scratch area. To do this, you simply bump the program counter by the amount of space needed for the table. For example, to leave a table in memory of 256 bytes with a label of TABLE on it, try: TABLE *=*+256 You will note that *= breaks the normal convention requiring a space after the pseudo-op. This is done so that uses of *= will look more like assignments. They still appear separated in the listing. You should note that when *= is used, the symbol is assigned to the value of the program counter before the program counter is changed. You can leave smaller amounts of memory with *=, although if the amount being left is only one or two bytes, the use of .BYTE and .WORD, both described later, is recommended. 5.3.3 Blocks of Symbols Quite commonly, you will wish to assign symbols to various places in a continuous area of memory, with space left according to the size of the object that the area pointed to by the symbol will represent. You will wish to do this in areas completely outside your program, including special data areas, and most importantly zero page. Most programs require an assortment of locations in zero page that must be labelled. You use *= to assign these labels in the same means that you allocate blocks. For example, say you wanted a symbol called COUNT to represent a one byte area, POINTER to represent a two byte area, and FLOATING to represent five bytes. You would do the following: Page 21 PAL 64 Manual 5. Pseudo-ops *=$16 COUNT *=*+1 POINTER *=*+2 FLOATING *=*+5 Using this method, you could insert symbols as desired, or stick them on the end, and not worry about the order. Some assemblers force the operation to be done by means of something like the following: COUNT = $16 POINTER = COUNT + 1 FLOATING = COUNT + 2 in this case, the length of the area represented is on the next line, and changing things around is difficult. You must also remember that FLOATING has a size of five if you wish to add something to it. You can use this to assign almost all of your pool of zero page or other memory storage. Be sure to reset the program counter before you assemble any more code, however. You should note that due to lack of space in PAL to provide differently, when you assign a symbol by putting it on the left of a *=, it gets the value of the program counter before it has changed, but the listing gives the value after it has changed. This may cause some confusion while reading listings. 5.4 .BYTE Syntax: .BYTE expr,expr,... The .BYTE pseudo-op is used to actually place one byte values into code at the current pc location. It takes as operand a string of valid PAL expressions delimited by commas. As many as will fill the PAL input line buffer may be used, or as few as one may be used (no comma). Expressions may be of any type, with modifiers as desired (note: "!" does nothing). The result of the expression must be a one byte value, or an ILLEGAL QUANTITY error will result. This means you will want to use the "<" and ">" modifiers when dealing with two byte values like addresses. A one byte value is one in the range 0-255 or $ff80-$ffff. The high values are accepted because they usually indicate the negative numbers from -1 to -128. This allows the line ".BYTE -1" to be valid. .BYTE is of use in defining tables and values such as jump tables and pointers. It can also be used to sneak in instructions like the BIT instruction, via this common 6510 coding trick: .BYTE $2C ;absolute BIT instruction LABEL LDA #-1 ;hidden load instruction 5.5 .WORD Page 22 PAL 64 Manual 5. Pseudo-ops Syntax: .WORD expr,expr,... The .WORD pseudo-op is similar to .BYTE except that it enters a two byte value for each expression given. The 16 bit value is placed in the code in the standard low,high format. ".WORD VALUE" is the same as ".BYTE VALUE". 5.6 .FILE Syntax: .FILE devnum,"filename" The .FILE pseudo-op is used to chain in the next file in a sequence of source files, each of the BASIC source type. In the above syntax description, devnum is the peripheral device to load the file from, and filename is the file name of that device. The closing quote is optional. The use of .FILE causes a direct chain to the following file. It can thus be used to sequence through a series o source files on disk or tape, allowing very large programs to be assembled. (In fact, PAL has been used to develop such programs as POWERtm, CBM 64 and Atari Checker Kingtm and Atari Microchesstm). In addition, PAL is us used (naturally) to assemble itself. Say for example you had your program in two files. The first would contain the SYS line to call the assembler, and the second would be all assembler. Assuming the second were on drive zero, and called "BLAT", the last line in the first file would be: .FILE 8,"0:BLAT This assumes your disk in on unit 8 of the peripheral bus, of course. Such chains should be terminated with the .END pseudo-op, although there are clever ways to do it with .GOTO. 5.7 .IF Syntax: .IF expr:statements The .IF is used for conditional assembly. It takes an expression, and evaluates it on both passes. If the expression is non-zero, the code after the .IF on the same line as the .IF is assembled. Usually this will consist of a .GOTO to do further branching. This extra code on the line will follow a colon ":" as usual. This is one of the reasons why the multiple statement feature of PAL is supported. There is a fair bit o power in the use of conditional assembly. For example, with .I, .GOTO and symbol assignment, it is possible to set up assembly loops. You should note that although .IF only tests for non-zero, other tricks can be performed to do different kinds of comparisons. Shifting an expression to the right by 15 bits, with ">" will cause the result to be one if the original expression was negative, and 0 if it was positive. This is because the topmost bit in a sixteen bit value is one if the value is negative and zero Page 23 PAL 64 Manual 5. Pseudo-ops if it is positive. This means you can compare two values with .IF by subtracting them and testing if the result was negative or positive. Use of .IF is normally restricted to keeping two different versions of a program. Say, for example, that you wanted to assemble a program for both 80 column CBMs and 40 column CBM 64s. One thing you would do is have a symbol called something like LINELEN which you would assign to 80 or 04. There would be several other variant symbols, and probably even sections of code that would have to differ from version to version. If you set up a variable called something like COL80, and assign it to 1 if on the 80 column machine and 0 of the 40 column, you can do the following: 1000 .IF COL80:.GOTO 1050 1010 ;CODE FOR 40 COLUMN MACHINE 1020 ..... 1040 GOTO 1100;BRANCH AROUND 80 COLUMN CODE 1050 ;CODE FOR 80 COLUMN CBM 1060 ..... 1100 ;COMMON CODE You could use conditional pieces of code to define symbols or load special symbol tables with .IF. That way you can change from one version to another just by changing one symbol. This is how the different versions of PAL are made. 5.8 .GOTO Syntax: .GOTO expr The .GOTO pseudo-op (so named so it can be renumbered with the RENUM of POWER) causes an unconditional transfer to the line number which is its argument. This line number may be an expression, allowing for a computed .GOTO. This line number will be taken to be in the current source file (ie. if you have multiple source files and use .FILE, you may not jump between them) but it may be at any place in the file, after or before. This allows you to set up loops with the use of .IF and symbol assignment to decrement a symbol. Try for example: 10 SYS700 20 .OPT P 30 COUNTER _ 5;HOW MANY LOOPS 40 LDA COUNTER+$8000 50 COUNTER _ COUNTER - 1;DECREMENT IT 60 .IF COUNTER:.GOTO 40 70 .END Normally, .GOTO is used only with .IF. 5.9 .GTB Syntax: .GTB This pseudo-op stands for Go To BASIC. It takes no Page 24 PAL 64 Manual 5. Pseudo-ops argument, and causes a transfer to BASIC at the point in the source it is encountered. BASIC statements following are executed by the interpreter. Return to the assembler is done by a SYS to a special entry point in the assembler. This entry is located in a special table of jumps near the start of the assembler. You can find this address by subtracting 6 from the address found in the vector you use to call PAL. For example, you can return to PAL with "SYSPEEK(701)*256+PEEK(702)-6". It should be noted that the use of BASIC is somewhat limited, and certain statements that would disrupt the operation of the assembler should not be executed. Notably among these is the INPUT statement, or anything that writes into the BASIC input buffer ($200), beyond the first 9 bytes. You may, however, use the GET statement. Control should never be given to the user, as damage may result. In general, you can use this to print out stats or do special I/O setups in the middle of an assembly. While BASIC code is running, PAL's zero page variables are swapped out into the BASIC input buffer in page two, so you may not manipulate them. You can't call any PAL subroutines either. 5.10 .ASC Syntax: .ASC "ASCII string" This pseudo-op is used to enter ASCII strings into the object stream. It is required due to a deviation in the syntax of PAL from the MOS standard. This standard directs that strings inside quotes in a .BYTE pseudo-op be entered as strings. To allow consistency in the expression evaluator, PAL does not allow this, as any extra characters in a character constant in an expression are ignored. .ASC (for ASCII) puts the quoted string in the text for you, and can be easily put in sequence with .BYTE instructions in translating from the MOS standard. The first quote is required, but the trailing one may be left off unless spaces are required, or something else like a comment or another statement follows on the line. 5.11 .SYS Syntax: .SYS expr The .SYS takes a standard expression as an argument. It acts like the SYS command of BASIC. A JSR is done to the given address on each pass. An undefined symbol is an error on either pass. Your subroutine is called with the assembler in its normal mode, which is to say that most of the zero page used by BASIC has been swapped out to 2 page so that zero page memory can be used by the assembler. The swap routine, documented with the jump tables at the end of the program, can be used to get them back, but this means that internal assembler routines, such as the expression evaluator cannot be used if this is done. You must thus normally be Page 25 PAL 64 Manual 5. Pseudo-ops cautious about what operations related to BASIC and BASIC associated locations are done. You are in a position to call other assembler subroutines, such as the expression evaluator, and this command essentially allows you to generate your own additional pseudo-ops. 5.12 .STM Syntax: .STM expr This is used to specify a lowest address for the symbol table. The symbol table normally grows down from the top of memory pointer on the CBM 64. (This can be changed by means of a special .SYS you can code) By default, the symbol table minimum is set at the start of an assembly to point to the end of memory used by BASIC programs and variables. You may want to set it higher if you are chaining with .FILE or using buffered object output. (.opt o) If you have an at-sign function coded, you could use this to do things like peek and return a good symbol table minimum. Should the symbol table grow below the minimum you set, a SYM TABLE OVERFLOW error will occur. This is a fatal error. 5.13 .SST Syntax: .SST device,secondary address,"filename" Symbol table files may be saved and loaded with peripheral bus storage devices such as the COMMODORE disk unit. .SST is executed on pass one only, and saves the symbol table as generated to that point. The first argument is the device number of the storage device. For the disk, this is typically 8. The secondary address is any valid sequential file secondary address you are not using for other purposes on that device. For the CBM 64 disk, values in the range 2-14 are usually good. The file name is as would normally be given on an open statement in BASIC for that file. Normally, for the CBM 64 disk, this requires a ",S,W" be tacked on after the end of the file name to specify a sequential file to be used for write. It is often advisable to put an ":" in front of a CBM 64 disk filename, as usually a program will be assembled to its output file more than once. This pseudo-op is also used on the process of generating sorted listings of the symbol table of a program. This is done by creating a symbol table file with a .SST statement on the last line of the source program. This file can then be used as input to the symbol table lister. 5.14 .LST Syntax: .LST device,secondary address,"filename" This is the companion pseudo-op to .SST, as it will load up and enter into the symbol table the contents of a symbol table file saved by it. This is executed only on pass 1. It Page 26 PAL 64 Manual 5. Pseudo-ops should be noted that at present, duplicate symbols are not checked for, all that happens is that the newly added symbols will replace any counterparts since they are found first in a symbol lookup. Symbol table overflow is also not currently checked for, but will of course be detected by the addition of any extra symbols in the normal fashion after a .LST You should find .LST to be a very useful tool in both large and small projects. As your use of the CBM 64 increases, you will build up a set of symbols that refer into the CBM 64 ROMs and the CBM 64 zero page. you should keep these definitions in one file and write them to disk with a .SST. Then, any time you are writing a quick or a long program, you can load in this symbol table and have access to all these locations by name instantly. You can keep versions of this symbol table file for different ROM versions of the CBM 64, and this way change your program from one version to the next quite quickly. On the PAL disk, you will find the symbol table file that PAL uses, so that you can write routines that deal with PAL zero page. This file also has a number of definitions for internal CBM 64 routines you will find useful. 5.15 .END Syntax: .END device,"filename" This pseudo-op is actually optional on most source files. The assembler will insert a .END with no arguments if it comes to the natural end of a source file. The .END actually causes a .GTB after the pass two cleanup, so that you may put in your own termination code in BASIC, including printing of statistics and actually calling your code at the right entry point if desired. .END also takes optional arguments. These arguments, as shown in the syntax description above, are of the same format as those of .FILE. If the argument is present, the assembler will do that .FILE at the end of pass 1 only, reseting its pointers to begin pass 2 at the same address in that file as the first line after the SYS that called the assembler, ie. this file specified should be the first file in the assembly chain. This simplifies chaining of long source files. One creates a calling file that contains the SYS to call the assembler, chains through the other files with .FILE, and returns to the original with .END. On pass 2, .END acts as though it had no argument. 5.16 .OPT Syntax: .OPT option,option,... The .OPT pseudo-op stands for OPTion, and it allows you to specify the disposition of printed output and object code. Valid options are: Page 27 PAL 64 Manual 5. Pseudo-ops P - Print. This option specifies the assembly listing be output to the CBM 64 screen. All the P options specify printing to the screen in addition to the type specified, as the screen is rarely the slow part of a listing. Listings are formatted and tabbed despite the free format of the source. Regardless of P options, lines with errors, and lines containing .FILE specifications are printed on both passes. P# - Print to file. With this option you provide a PAL expression after the P which specifies a CBM 64 logical file number. Listing output is then sent out to this file in the same manner as PRINT# of BASIC. The file should of course be opened with an OPEN statement prior to the SYS call that starts the assemble. This allows printing to any normal file, such as one on disk, printer or tape cassette. With a typical CBM 64 printer on bus device 4, you would enter: 10 OPEN 4,4 20 SYS 700 30 .OPT P4 P=addr - Print to user routine. With this option specified, when the assembler wants to print a character it will JSR to the routine at addr where addr is a PAL expression. The character to be printed will be in the accumulator, with a zero sent when it is time to close the file. This allows the use of special routines to service private printing devices, such as those off the parallel port, or modems, etc. You can even specify P=$FFD2 which will cause everything to be printed twice! O - O options specify the object output. With no additional letters, this specifies object output to a special buffer kept just above the end of the BASIC scalar variable table. This is the memory area where BASIC arrays would normally be kept, and it uses the same pointers. OO - This means "Object where Origined" which means the object code will be written right into the memory it is meant to run in. This is generally useful for quick running and debugging, and allows complete freedom o movement of the program counter. Programs that run in sensitive areas of memory, or which cannot be fit with both source and assembler cannot be done in this way of course. This will probably be the method you use the most, as it allows quick assembly and testing of programs without going to disk. O# - Similar to P#, this sends object output to a peripheral bus file. The file is generally Page 28 PAL 64 Manual 5. Pseudo-ops expected to be like a CBM 64 disk program file once opened, however this does not have to be true. The file should be opened with an open statement before the assembler is called, and it will be closed if the assembly terminates normally. The file number is specified in the same way by the PAL expression after the O. The first thing written out to the file is the start address, so that if the file is a CBM 64 disk object file, it will be loadable directly as though it were saved by a save command. Note that this does not work to tape. Here is an example, with object output to a loadable disk file called BLAT on drive zero. 10 OPEN 2,8,1,"0:BLAT" 20 SYS 700 30 .OPT O2 40 *=$7000 50 ;code It should be noted that on the CBM 64, when you have a disk machine language program file, you must either load it with SUPERMON or stick a ",1" on the end of your LOAD command. For example, to load the above case you need: LOAD "BLAT",8,1 or else the program will load where BASIC programs go. O=expr - this option will allow a user routine for output with the same syntax as the P= command. Note that the object output routine must be somewhat more complicated, as the routine is called only once per assembler line. A number o symbols required for object output will be provided in a symbol table file with th assembler. This can be loaded off the disk with a .LST pseudo op. The key one to refer to is LENGTH, which contains the number of bytes per output, minus one. Thus if LENGTH is zero, one byte of code is to be output. Your routine must also check for two other values in length as special cases. The value $80 is used to indicate a request to open the object file, as the first object output is about to be done. The value $7F indicates time to close it. Otherwise the LENGTH value will be a low number from 0 upwards. Normally the object output routine should never be called with a value $FF (length = 0) as no object output is expected, and this is detected by the caller. The data to be output are stored in 2 areas. The first three bytes are in zero page, starting at the symbol OP, which contains the op code for instruction output. If more than three bytes are to be output (this comes from .BYTE, .WORD, and Page 29 PAL 64 Manual 5. Pseudo-ops .ASC) then the extra bytes can be found starting in page one at symbol OBJBUF. Usually you will index off OBJBUF-3, if you are using an index register to index the bytes you are outputing. your object routine, like your print routine, can use any registers and change any flags (except the decimal flag) but must be wary of zero page usage, as the BASIC zero page values are swapped out to 2 page when these calls occur, and the assembler is making more extensive use of the zero page area. N - You may wish at times to cancel previously set output options. The N option resets all output options to nil, as they are set at the beginning of the program. You must restate any options you wish to turn on or remain on. for example, to turn off printing, but keep object going to file #2, one can say: .OPT N,O2 and use: .OPT P,O2 to resume that printing. 5.17 .BAS Syntax: .BAS O This pseudo-op allows you to easily produce programs that combine BASIC and machine language without all the hassles that that task normally entails. With .BAS you can make a program that consists of a BASIC program followed by a machine language one in memory. Such a file, when on the disk, can be LOADed and RUN like any other program. You must use .BAS at the front of your assembler program. Your may start off your assembly in the normal fashion, defining symbols and loading tables etc. Once this is done, including a line with the .BAS pseudo-op on it, generally, with no argument. The lines that follow the .BAS should be normal BASIC except as explained below. When you are finished the BASIC program include an "END" statement all by itself on the last line. This will tell the .BAS pseudo-op that the BASIC is finished and assembler should resume. After the END you may continue with your assembler program as usual. In this case, however, the program counter ("*") will already be set to just beyond the end o the BASIC program you provided, were it to be loaded where a BASIC program normally sits. The above procedure will produce a BASIC program and a machine language program together in memory. Naturally, you will wish to call the machine language code at some time from within the BASIC. To do this, use the SYS statement as you Page 30 PAL 64 Manual 5. Pseudo-ops would expect, but instead of providing a numeric address, give a PAL expression in quotes. PAL will figure the value of the expression and write out the correct decimal number after the SYS when it output the BASIC bytes to the object file. You may thus have calls to assembler routines throughout your BASIC program, and they need only refer to PAL symbols. This way you can create combined programs without worry over numbers or arrangement of code. The following example shows how you might use .BAS to create a simple combined program. 10 OPEN 2,8,1,"0:MIXED" 20 SYS 700 30 .OPT P,O2 40 OUTPUT = $FFD2 50 ;NOW INCLUDE BASIC 60 .BAS 70 PRINT "HELLO THERE" 80 PRINT "I WILL NOW PRINT YOUR NAME" 90 SYS"PRNAME" 100 PRINT:PRINT "I DID IT" 110 END 120 ; ASSEMBLER RESUMES 130 PRNAME = *;DEFINE CALLED LABEL 140 LDX #0 150 LOOP LDA NAME,X 160 JSR OUTPUT 170 INX 180 CPX #NAMELEN 190 BNE LOOP 200 RTS 210 ; 220 NAME .ASC"YOUR NAME HERE" 230 NAMELEN = *-NAME; FIND LENGTH You can have as many lines with special SYS codes in them as you like. This allows you to build complex BASIC programs that call machine language routines whenever they need speed and power. In this case the object code was written to a disk file. When this disk file called "MIXED" is loaded, it can be RUN and the BASIC will run and call the assembler. The BASIC line numbers will remain the same. You should note that since we have a combined program, there is machine code in memory right after the BASIC code. This means that you can not make changes to a combined program once the conversion is done. You must make all changes on the source that contains both the BASIC and assembler code. When PAL places a number after the SYS inside the BASIC it leaves 5 bytes since a number could be as big as 5 digits. In most cases, numbers will be 4 digits. To take up the extra space, PAL puts a colon after the 4 digit number. You should only have to worry about this if your SYS routine starts reading bytes from the BASIC source the same way the SYS700 that calls PAL does. If you provide an argument of any kind to the .BAS Page 31 PAL 64 Manual 5. Pseudo-ops pseudo-op, ie. ".BAS O", it will cause the assembly to take place for the area of memory immediately after the source program instead of to $0801. If you use the ".OPT O" mode of object output, the code will be placed in memory where it is supposed to run without destruction of the existing program. In this case, you may use the POWER "TEST" command to look at and run the mixed program. The POWER "BACK" command will restore the old source. In this way you can write a mixed program, assemble it, test it and go back to modify the source without ever going to disk. It should be noted, however, that if you SAVE the program while in TEST mode that you can not load it back under normal conditions, for it is meant to run in a different area of memory from most BASIC programs. Without the POWER commands listed above, you may test the output of a mixed program in one of two ways. In the way shown above, you write the object code to a disk file. This disk file can then be LOADed and RUN. You may also use the ".OPT OO" mode of object output and the mixed program will be written right on top of the source. If you do this, you will encounter problems because the BASIC portion of the mixed program will not have the line number list chains properly set up. (Both the LOAD command and the POWER TEST command set up these chains.) You may still use the program if it contains no line number references, as in GOTOs or GOSUBs. You may also SAVE it and LOAD it if you have tape. Fortunately, you may also issue the command: SYS 42291 and this will repair the line list chains noted above. It's best, however, to have POWER in place and to use the TEST command, which was designed for this purpose. The .BAS pseudo-op does not work with RPAL described in the appendix, for such programs cannot be relocated. Page 32 PAL 64 Manual 6. Error Messages 6. Error Messages PAL has various error messages, which are issued during either pass. If an error is detected, the name of the error is printed, preceded by four stars. After the error message, the erroneous line is printed on the screen regardless of set printing options. It also prints out any activated printing channels. In addition, SYNTAX errors are accompanied by a digit printed before the four stars which indicates what type of syntax error has occurred. There are 10 different syntax errors, and the number for each is listed below. Some error are "fatal", which is to say they abort the assembly completely if they are encountered. Fatal error messages are preceded by a line of exclamation points (!). The assembly stops after the message is printed. When an error occurs, the first byte of those generated by the erroneous line is changed to a zero, which is the 6510 BRK instruction. Thus, if you try to execute a program that had an assembly error, a breakpoint will reset the machine or call the monitor if you pass through the bad line. Naturally, however, some errors will garble the program so much you should not even try to execute it. One type of error that is not detected by PAL is the "phase" error. This error should never normally occur, but can be caused by funny operations with conditional assembly or error during .BYTE and .WORD pseudo-ops. A phase error occurs if the assembler's idea of where the program counter should be differs from pass one of the assembly to pass two. A phase error will cause many labels to be out of phase with the actual code, and thus completely garble the code. If you wish to detect phase errors, you can use a little trick with .IF. A line of the form: PHASE .IF PHASE-*:PHASE ERROR will do the job. Normally, PHASE will always be the same as *, the program counter, and the extra line will never be assembled. If the program counter does get out of phase with symbols though, the result will be non-zero, and the extra statement will be assembled, giving a SYNTAX error which you can recognize. MESSAGES SYNTAX - This error is preceded by a digit as stated above. Those digits and their meanings are: 0) Label not valid on null statement. (Encountered on a line with just one string and no spaces on it.) 1) Invalid op code. 2) Invalid address mode - the mode given is not recognized as any valid mode. Page 33 PAL 64 Manual 6. Error Messages 3) Unrecognized operator in expression. (Some funny character is in an expression.) 4) Unbalanced parentheses or brackets. 5) Invalid expression term - an invalid character in an expression, or a quoted character term with no character in it. 6) Missing comma. A comma was expected by a pseudo-op. 7) Invalid pseudo-op. The .XXX string given was not recognized as a pseudo-op. 8) Symbol does not start with a letter. A symbol was expected but a non- alphabetic character was found. 9) Op code not valid with address mode. You can not use the given address mode with the given instruction. ILLEGAL QUANTITY - Your expression returns a value that is beyond the limits allowed for this instruction or pseudo-op. Something in the expression may be creating a value larger than 65535. OVERFLOW - The line input buffer used by PAL to parse your line has overflowed. Shorten your line by splitting it into two, or using temporaries to simplify the expression. BRANCH OUT OF RANGE - A relative branch has been attempted to a location more than 128 bytes from the program counter. The 6510 can not do this, and you must recode the branch to a closer location. REDEFINITION - An attempt has been made to redefine the value of a symbol without the use of the symbol redefinition operator. UNDEF'D STATEMENT - A label used in an expression is not defined. This can also occur if a null expression is given where a non-null one is expected. REVERSAL - An attempt has been made to assemble code at a location lower than the last location code was generated at. This error does not occur if object code is going directly to memory by means of OO, or if you are outputing relocatable object. This is a fatal error, as are all that follow. SYM TABLE OVERFLOW - You have attempted to add more symbols than there is room for in the symbol table. Reduce the minimum with .STM or break your program up into chunks to provide more memory. OUT OF MEMORY - There is no more room for object code in the buffer area (.OPT O mode) to grow. Output object to disk or use some other means. Page 34 PAL 64 Manual 6. Error Messages UNDEF'D STATEMENT - A .GOTO has been made to a statement that does not exist in the current program. (Just like in BASIC) Unlike the previous error of this name, this one is fatal. DEVICE NOT PRESENT - The peripheral you have tried to access is not on the bus, or does not respond. IEEE - some other error has occurred on the peripheral bus or with some CBM 64 device. The error name refers to the peripheral bus used on most Commodore computers. DISK - An error has occurred during the use of the CBM 1541 disk unit. The error message and numbers sent by the CBM 1541 disk will be printed before the error message. Page 35 PAL 64 Manual 7. More Notes 7. More Notes POWER provides a special feature for use by PAL owners. The instant phrase and instant subroutine features of POWER that are entered with REM"A=HELLO type statements may also be done with semicolons when using PAL. Thus: 10 ;"P=PAL has the same effect as 10 REM"P=PAL Power also provides the TEST and BACK commands that are designed to work with the .BAS pseudo-op. Please see the description of that pseudo-op for details. (If you don't have POWER, don't worry about these features.) 7.1. Using PAL with Tape PAL can be used by people without disk systems, although i is not as convenient. The .LST and .SST ops will not work with tape units, but .FILE and .END will. You can thus chain through files on tape if you must. The files must be recorded twice, or you must have a .SYS or .GTB routine before the .END to allow the rewinding of the tape unit. Normally however, PAL will work well if you are working on a short program that can be entirely in memory. (Over 1K on a 32K machine.) You can edit, assemble and test without ever touching a mass storage unit. (This is how you do a short program even if you have disks - it's a lot faster than any other method on any assembler.) If you must, you can even write an object output routine that will output your object in some form that is acceptable to tape. (Hexadecimal, for example.) You will have to write a loader to load the program in later, of course. You can also write .SYS routines to do symbol table operations if you must. Because of PAL's 4K size, it can even be used by owners of original 8K pets provided they have upgraded their ROMs to a newer BASIC. When PAL finishes an assembly, it prints the upper and lower bounds of code generation on the screen. You will see the form of the line on your first execution, which is of the form "]address-address". The second address is one byte beyond the last byte generated. This range can be used if you want to save directly generated output with the machine language monitor, SUPERMON. 7.2. Advantages o PAL Page 36 PAL 64 Manual 7. More Notes One of PAL's main advantages over other assemblers is its convenience. With PAL, you can modify, assemble and test in a quick sequence without any interaction with disk on a short file. Assemblies of programs up to a full 1K in size can be assembled in around ten seconds in this way. The CBM assembler, which must go to disk, takes 50 seconds for this, plus the time required to load the assembler in, run it, load the loader, run it, execute your program and then reload the source for more changes. With PAL, you use an environment and editor you don't have to learn, and you have the calculator power of BASIC at your fingertips. You can use (and in fact, should use) PAL anywhere you would use a mini-assembler. There is no more typing, but you are dealing with a full assembler, and can easily make additions, changes, or deletions in your programs without worrying about addresses. In addition, the .LST and .SST features allow you to work quickly on programs without having to define all kinds of symbols each time. By making a table of your most commonly used symbols, such as CBM 64 zero page locations and subroutines and saving the symbols with .SST, you can access them quickly in a short program with .LST. You will also want to use .LST with large programs, because it takes much less time to load in a symbol table than to assemble one each time. If your programs grow in size, PAL allows them to by providing chaining with .FILE. Even when chaining from the disk, PAL is faster than other 6510 assemblers the author has seen. Future plans for PAL include a sophisticated macro package (using the single quote character for macro substitution.) One of the biggest advantages of PAL is the .BAS pseudo-op. This allows convenient combination of BASIC and machine language programs, a facility provided by no other assembler. 7.3. History of PAL PAL was written in the summer of 1979 to provide a tool for the development of POWER. Development was first on the PET/CBM line of computers and the program has now been moved to the CBM 64. For most of its early life, it was used only by a small number of PET users. It has been used, in combination with POWER, in an introductory assembler course at the University of Waterloo, in Ontario, Canada. 7.4. Problems PAL reads in BASIC source. As you may know, such source is "tokenized" so that BASIC keywords only take up one byte in memory. PAL expands these tokens for you, so you need not worry about them under normal conditions. One problem you may run into, however, is that you can not use a question Page 37 PAL 64 Manual 7. More Notes mark in a comment. The CBM 64 will turn any question mark into the token for PRINT, and PAL will expand it out as PRINT when it reads it back. 7.5. More Examples Here are some more sample PAL programs to explain use of some features. Example of chained set of files: The first file is called "FILE1. 10 OPEN 2,8,1,"0:OUTPUT" 20 SYS 700 30 .OPT O2 40 ;code 50 .FILE 8,"FILE2" Here is "FILE2" 10 ;code 20 ;more code 1000 .FILE 8,"FILE3" And finally "FILE3" 10 ;lots of code 1000 .END 8,"FILE1" The .END statement brings you back for the second pass. Here is a program that would list to the printer on device 4: 10 OPEN 4,4 20 SYS 700 30 *=$5000 40 .OPT P4 43 SCREEN = $400 44 LINELEN = 40 ; LENGTH OF SCREEN LINE 50 LDA #" "+128 60 LDX #0 70 LOOP STA SCREEN+(5*LINELEN),X ; PUT WHITE SQUARE ON SCREEN, STARTING LINE 6 80 DEX 90 BNE LOOP 100 RTS 7.6. Detailed Example Here is a detailed example program with comments on each line. 10 OPEN 1,8,1,"0:OBJECT" - Opens object file on unit 8, drive 0 to file number 1. 20 OPEN 4,4 - Opens printer on unit 4 to file 4. Page 38 PAL 64 Manual 7. More Notes 30 SYS 700 - Calls assembler. 40 .OPT P4,O1 - Print to file 4 (printer), put object to file 1 (disk). 50 *=$5000 - Program is to run at hex address 5000 60 OUTPUT = $FFD2 - Kernel routine that prints character in accumulator. 70 READKEY = $FFE4 - Kernel routine like GET, gets key from keyboard. 80 ; - Blank comment line. 90 STOPKEY = 3 ; character returned when stop key is hit. - You could also type the STOP key in double quotes. 100 GETKEY JSR READKEY - Gets key from keyboard into accumulator. 110 BEQ GETKEY - If 0, no key was read. BEQ branches if result was 0. 120 CMP #"@" - Check to see if the key was an at-sign. 130 BEQ WASAT - If it was, go to code at WASAT. 140 CMP #STOPKEY - Check for break key. 150 BEQ ALDONE - If it was, go to quit routine. 160 JSR OUTPUT - Print the character if it was not special. 170 JMP GETKEY - Get another key. 180 WASAT = * ; routine for at-sign - Note use of assignment to star to set label. 190 LDX #0 - Load the X register with zero. 200 OUTPLP LDA MYNAME,X ; get character in name - Note indexing and labelling. 210 JSR OUTPUT ; output character 220 INX - Bumps X register further into MYNAME area. 230 CPX #NAMELEN - Check to see if X has reached the length of the name. 240 BCC OUTPLP - BCC branches if the X was less than NAMELEN, unsigned. 250 JMP GETKEY - Otherwise, we can go back. 260 ; 270 ALDONE RTS 280 MYNAME .ASC "Your Name Here" - Puts the text of your name in memory. 290 NAMELEN = *-MYNAME - Calculates the length of your name into symbol NAMELEN. 300 .SST 8,4,"0:QSTAB,S,W" - Save symbol table for later printing. 310 .END - Normally not needed unless you want something done after assembly. 300 ?"HI FOLKS" - BASIC again. Page 39 PAL 64 Manual 7. More Notes 7.7. On Your Way You are now ready to program on the CBM 64 with PAL. There is still a lot to learn, though, including what areas of zero page are safe for use and what handy routines the CBM 64 has. Jim Butterfield's (another PAL user) memory maps are a real life-saver in this area. They can be found in many magazines such as the Commodore Canada Transactor, and in books on the CBM 64. Many magazines like COMPUTE!, MICRO, The Transactor, The TORPET, and Commodore: The Microcomputer Magazine will have valuable references for you. Page 40 PAL 64 Manual Appendix A APPENDIX A Pal Environment PAL parses its lines into a buffer starting at $100 in CBM 64 memory. All operations on lines are done in this buffer, with the Y register pointing into it as an offset from $100. Printing is also done from this buffer, although comments are not placed here. The buffer is terminated with a zero by the parser, and this zero is followed by a semi-colon and an address if there is a comment. (The address points into BASIC code where the comment lies.) Symbol EXPPOS has as its value the offset into the buffer where the operand field starts. Symbol LABELPOS contains where the label field starts. Storage in the buffer is in ASCII, rather than CBM 64 internal form. Assembly of a PAL line takes several steps. First the line is parsed. Then, the instruction field is checked for an op-code or a pseudo-op. If it is a pseudo-op, that is processed by special routines. These routines put whatever code they generate into 3 bytes starting at OP, and remaining bytes go at OBJBUF. If an op-code is found, it, the address mode, and expression are decoded and turned into 6510 machine code starting at OP. Routines are then called to print the line if need by, and then object output routines place the bytes where they are set to go. When this is complete the whole thing starts again. Several symbols were noted above that are used by PAL in zero-page. You will find the following of note: COMPOS - the position in the buffer of the last comma found. Zero if none. PASS - pass counter. Negative one ($FF) if pass 1, zero if pass 2. OP - the first object byte, where the OP is stored. NEWLO, NEWHI - following op, the next two bytes of object output, and also where results from EVAL are put. LENGTH - the number of object bytes to output for this line, minus one. i.e., zero indicates one byte, one indicates two, etc. Special values are used with user routines. See .OPT O= PC - a two byte value with the current program counter ( * ) in it. OLDLO, OLDHI - EVAL also puts its result in these two locations. OBJBUF - the page 1 buffer where extra object bytes can be placed if more than 3 are generated, as is done with .BYTE, .WORD, and .ASC. Page 41 PAL 64 Manual Appendix A USER - the page 1 indirect jump vector that is used when an at-sign is encountered in an expression. When the user routine is called, the Y register will point to the at-sign. The value calculated by your user routine should be placed in locations NEWLO and NEWHI before returning via an RTS. This can be used (and in fact was once a standard) as a way to include full BASIC expressions inside PAL ones. This takes work and some detailed inside information on the workings of the BASIC expression evaluator. From inside a user routine, you are free to call PAL routines described in appendix B, although EVAL should not be called. See "GETTERM" in that section. LINEVEC - a special vector to place the address of code that is to intercept PAL processing of a source line. To set up the vector, place the address of your code here. Add the two bytes and "EOR" with $A5. Place this in the check byte described below. For full details, see the NORMENT entry point description in Appendix B. LINEVCHK - check byte for LINEVEC. Page 42 PAL 64 Manual Appendix B APPENDIX B Internal Routine Vectors PAL has a number of vectors to allow you to use its internals. Several routines are defined for use with .SYS and user functions. In addition, .OPT allows printing and object output to go through user routines, allowing customization of the package. The vectors are listed below. They are all at the very front of the assembler. To find their addresses, you should look at the PAL call vector at locations 701 and 702 which points just beyond these vectors. The address pointed to by 256*PEEK(701)+PEEK(702) is represented as PAL in the table below. ERROR - PAL-27 - This is the error printing routine. You JMP to it with the error code in the X register. ERROR codes start at zero and go up, in order according to the way they were listed in this manual. CHKUND - PAL-24 - This routine will check the undefined symbol flag (UNDFLG), and signal a non-fatal undef'd statement error if it is set. Usually called after calling the expression evaluator. Null expressions set the flag also. SWAP - PAL-21 - This routine swaps the zero page used by PAL with that used by BASIC. If in the PAL operating environment, a call to SWAP will restore the BASIC environment, and another call reverses this. The swapped out zero-page is kept in 2-page, in the BASIC input buffer. PAL calls SWAP almost immediately upon entry, and calls it again before restoring control to the user. It is also called for .GTB and .FILE/.END operations. SYMBGET - PAL-18 - This routine will read in a symbol from the PAL input buffer ($100) and store it in the symbol table. The Y register should point into the buffer where the symbol is expected to be found. A 'REDEFINITION' error can occur if the symbol already exists. This is useful if you wish to write .SYS commands that can define symbols. You should NOT do symbol definition on PASS 2 unless you know exactly what you are doing. You should thus check the PASS counter and make sure it is -1 ($FF), indicating PASS 1 before you do symbol operations. (It will be zero on PASS 2.) EVAL - PAL-15 - This is the PAL expression evaluator. It evaluates an expression in the input buffer starting at where the Y register points when it is called. In the case of a .SYS, the Y register points just after the address expression when the routine is called. You may thus INY the Y register past whatever delimiter you used, and call EVAL to get a new value. The result will be placed in NEWLO and NEWHI, as well as in OLDLO and OLDHI. Any modifier used will be in TRUNC, and the variable UNDFLG will be non zero if an undefined symbol or expression was encountered. EVAL leaves the Y reg pointing just after the expression each time, so it can be Page 43 PAL 64 Manual Appendix B called again and again. Note that functions are NOT in the proper environment for calling EVAL, since they are called from within EVAL itself. To call EVAL from within a function would require saving and restoring OLDLO, OLDHI, DEPTH, TRUNC, UNDFLG, and OPERAT on the stack. You should thus use "GETTERM", described below, for getting arguments to at-sign expressions. With EVAL and EVALST, you can easily code your own pseudo-ops with .SYS. GETTERM - PAL-12 - This routine fetches and evaluates a single expression term, starting in the buffer one byte past the Y register. A term can be an entire expression if it is surrounded in brackets. This is mainly for use inside at-sign user functions, as it can be called immediately after the at-sign has passed control to your routine. A single term can be any of the items listed in the main documentation for the assembler. This routine leaves its result in NEWLO and NEWHI, as is expected for an at-sign routine. In fact, if you set the USER vector to call this routine and return, the at-sign ends up doing nothing in an expression. NORMENT - PAL-9 - This gives the entry point in the main loop of PAL processing that you can use to enter after you do any of your own processing. When PAL is ready to process a line of code from source it first checks to see if the user has set up a special vector for it to call first. This vector is called LINEVEC. It checks to see if the vector has been set up properly by adding the bytes of the vector and exclusive oring with $A5. This result is compared with the byte LINEVCHK. If they are the same, it is assumed the user has placed a routine for processing PAL lines in a manner different from the usual. A JMP indirect is made through the vector to the user routine. The user routine gets control after PAL has read in the source line and parsed it, so it must call routines to do so if it wishes to act on the source. If the user routine wishes PAL to continue as usual, it should JMP back to the NORMENT entry point. This vector is left mainly for use by the author in adding features to PAL at a later time, even if it is burnt into ROM. Normal users should use the .SYS pseudo-op to do their own work. USERENTER - PAL-6 - This vector actually has a JSR SWAP in it, and is the user re-entry point for SYSing to after executing code in BASIC from a .GTB. After doing the swap it fall through to: ERRTRY - PAL-3 - This is the main startup point for each line of assembly. When error processing is finished, it transfers here. If you encounter your own errors, you should transfer here after printing the message unless the error is a fatal one, in which case you should call SWAP to restore the BASIC environment and leave on your own. Page 44 PAL 64 Manual Appendix C APPENDIX C PAL Memory Maps The symbols listed above can all be found in a symbol table file "PALSYM", which comes with disk PAL, that can be loaded with .LST. (This file contains several other symbols as well which are not supported.) For those with tape, they are: UNDFLG $45 COMPOS $46 PASS $48 OP $4B NEWLO $4C NEWHI $4D LENGTH $4E PC $4F,$50 OLDLO $52 OLDHI $53 OBJBUF $15B USER $159 LINEVEC $2BA LINEVCHK $2B9 Page 45 PAL 64 Manual Appendix D APPENDIX D Converting CBM/MOS Assembler to PAL Differences between PAL and the standard assembler are few, but there are some, and you will need to know them to convert programs. Here is a list of differences between the MOS standard and PAL: (1) PAL uses double quotes around character constants because this is the way the CBM 64 BASIC editor works. Single quotes are used in the MOS standard. (2) In the MOS standard, ASCII strings are included in source with the .BYTE pseudo-op. You can enter strings like: .BYTE 'HELLO',13 In PAL, you must use .ASC to enter such strings. If you use strings in a .BYTE statement, only the first character will be included. (3) Most MOS standard pseudo-ops are supported, but .OPT has an entirely different syntax in PAL. PAL does not provide paginated listings, counting on either the CBM 64 printer or a user print routine to do this. The MOS assembler only has "=", "*=", ".BYTE", ".WORD", ".END", and ".OPT". It also has a ".PAGE" pseudo-op that makes a listing go to the top of a new page, which is not supported in PAL. (4) PAL expressions may be much more complex than MOS assembler expressions. No parentheses are allowed. MOS assembler expressions evaluate left to right, just like PAL, but have a poorer set of operators. The MOS assemblers includes the ability to include octal numbers, by putting an at-sign in front of the number. You can arrange this by writing an octal input function for the at-sign user function of PAL. Normally, however, there is no call for octal numbers in 6510 assembler, so you need not worry. One in fact wonders why such an anachronism exists in the MOS standard. (5) PAL labels may be up to eight characters long, MOS ones only six. (6) PAL has a large number of extra pseudo-ops not included in the MOS standard. If you use them, you may have trouble moving your program around. (7) In the MOS standard, no spaces are allowed in the body of an operand or expression. The first such space delimits a comment. Thus one does not need a semicolon to indicate the start of a comment in the MOS assembler, unless one is writing a comment line. Be sure to insert semicolons before any comments in a MOS assembler line before using PAL. (8) PAL allows accumulator addressing to be specified for Page 46 PAL 64 Manual Appendix D shift instructions by leaving a blank operand. For MOS standard programs, you must use the "A" addressing mode convention. If you have a program source developed with the Commodore assembler, conversion is easy. First you must load the source file with the CBM mini-editor, and quit the editor so that you now have a PAL type source file in BASIC source format. If you have some other form of source, conversion into PAL format may be difficult. Either the XEC command of POWER, if you have it, or the CBM mini-editor may help you there. Once you have a MOS standard source file in memory some minor changes must be made. First, PAL uses double quotes (") around characters and strings instead o single quotes ('). You will have to convert all single quotes in expressions to double ones. It is handy at this point to have some search and replace tool to work with. There is one in POWER, and public domain ones can be found in many user club libraries. You must next search for all .BYTE statements that have strings of more than one character in single (now double, you hope) quotes. PAL does not support this feature of .BYTE, so you must convert these statements to .ASC or combination .ASC/.BYTE statements for use by PAL. Next, you must check the use of all pseudo-ops. .OPT syntaxes differ, and file chaining or inclusion will be different. Other assemblers may have special non-standard pseudo-ops just like PAL does, and you may have to duplicate what they do or delete them. Other assemblers may also not signal errors when two byte values are used where a one byte value is required, and you will have to fix this as well. If your assembler differs a great deal from the standard, like Peter Jennings' Micro-ADE, you will have to write a conversion program. (The author had to do this once.) If it has the same instruction format as PAL, but different pseudo-ops entirely, like Carl Moser's MAE or the APPLEtm Pascal assembler, you may be able to get away with manual conversions. Page 47 PAL 64 Manual Appendix E APPENDIX E Extra Files Some extra files come on your PAL disk. "SYMPRINT" is a program to list symbol table files in sorted order on a peripheral bus device. Load and run the program to see how it works. As noted above, the file "PALDEF64", containing definitions of PAL symbols, is on the disk. You also get the relocating loader, described below, in various forms. A copy of SUPERMON by Jim Butterfield and Bill Seller is included on the disk. This is public domain. There is a BASIC program called SUPERMON.I which explains the operation o this program. In addition, you will find the source to the PAL relocating loader, which you may use but not distribute to the public in source form. It will give you an idea of the nature of a medium sized PAL program. The source for the FLOADER, in "FLOAD.PAL" shows the use of the .BAS pseudo-op. The Rev. Jim Strasma of TPUG is a PAL user, and he has been kind enough to provide an MAE to PAL converter and a PAL unassembler. These are public domain, but are placed on the disk. Thanks to Jim. Unfortunately, there is no documentation at this time. There may be other programs on the disk which you may wish to play with, as people are always creating new interesting ways to use PAL. In addition, other users of PAL will no doubt from time to time be making interesting programs that you may come upon. Hope you enjoy them. Page 48 PAL 64 Manual Appendix F APPENDIX F The Relocatable Object PAL Quite often it is desirable to have a program that you can load and run anywhere in the CBM 64's memory. Any normal 6510 program will, however, contain JMPs, JSRs and data references to within the program that are absolute and can not be moved about. A program containing these instructions can only run in the piece of memory it is intended to run in. Normally with PAL, this is not a problem, since all you need do to make the program run in any location you desire is to reassemble it with a different starting location. If your program is short, this can be done quickly and easily right in memory, so there is little need to do anything else. There are still reasons for wanting to be able to relocate your program without assembling it again, though. If your program is long, it might take some time to assemble. (PAL itself takes two minutes on a standard CBM with a disk drive.) This is too long to wait just to move code around a bit. If you want a program that just grabs a piece of available memory, you will not be able to predict where that memory is in advance, and thus need something that can move your program. Most important, though, is the case that arises when the person who wishes to move the program does not have the source. You might wish to give a program out to people without giving them the source files. If you do this, normally you would have to provide versions of the program to run on machines with all the different memory arrangements that exist and to suit everybody's taste as to where the program should sit. This is almost impossible to do. Fortunately, a version of PAL exists that outputs the object file in a form that a simple program, called the loader, can use to relocate the object anywhere in memory. This version of PAL is identical in every way with the normal version, with the exception that it outputs object code in a different manner. It is expected that the average user will develop a program with the normal PAL, and then assemble it with the relocatable output version to produce the final form. This version of pal, called RPAL, is slightly larger than PAL, and it is not expected that anybody will burn it into ROM. RPAL is provided in relocatable, ready to run form (of course), in a file called "RPAL". It can be loaded the same way normal PAL is. SYS 700 works to call this version as well. Setting up object code so that it can be relocated is not as easy a task as it seems. This is because some instructions and references must be relocated while similar ones must not. For example, if you had a JSR (Jump to SubRoutine) to a CBM 64 ROM subroutine, the address used would not change no matter where your program is running. On the other hand, a JSR to a routine inside your program should be changed as your program moves, for the subroutine itself will move. Page 49 PAL 64 Manual Appendix F Things get more complex than this, however. You might want to call a routine from a jump table by pushing its address minus one onto the stack and doing an RTS. To load the address you might have to do something like this: LDA #). You should note that this means the expression "LABEL>8" is no longer the same as the ">LABEL" expression using the upper half modifier. The plus operator will produce a relocatable result if one of the two operands is relocatable. The addition of two Page 50 PAL 64 Manual Appendix F relocatable objects should signal an error, but does not. Subtraction produces a relocatable result if one of the operands is relocatable and the other is absolute. An absolute result will arise if both operands are relocatable, as the difference between two relocatable values is the same no matter where the program is loaded. Naturally, if both operands of either of these two operators are absolute, then the result is absolute. In addition, the negation operator (unary -) will produce a relocatable value if the value being negated is relocatable. Use of the expression modifiers "<", ">", and "!" does not affect whether an expression is relocatable. As noted above, special attention must be paid with "<" and ">" because the whole value being truncated must be left in the object file. You should not use ">"> and "<" in any place that does not generate a one byte value. If you really wish to generate something like ".WORD