Ruud's Commodore Site: MP-assembler Home Email


What is it?

MP-Assembler is an assembler to be used on the PC to assemble source code for the 6502, its compatible successors, and other CPUs. MP stands for "Multi Processor": At the moment it can assemble 6502, 65C02, 65816, 6800, 6809, 8088, Z80 and My TTL CPU opcode. The special feature of this assembler is that you can mix all opcodes in one and the same file This comes in handy when assembling programs for the C128 (6502 and Z80) and the MMF-9000 (6502 and 6809).

The story

Today a lot of assemblers exist for the 6502, Z80 etc. and each claims to be better than all the other ones. But when I started to write this one in 1988, there wasn't one available as free/shareware on the PC, AFAIK. There were some available for the C64 but here I encountered a problem: I wasn't able to handle large source codes because the C64 simply lacked the needed memory. At that time I already was thinking about replacing the drive of the 1541 with an hard disk and thus a big change of the original system ROM was needed. Much more memory and a bigger screen made me to decide not only to use a PC instead but also to write my own assembler.

The used syntax is based in the first place on the assembler Hypra-Ass for the Commodore 64, published in the German Magazine 64'er in october 1984. But in the meanwhlie I accepted syntax used by other assemblers as well.

I don't think my assembler is better the other ones. I used to say: "It has one major advantage: you get the source code with it! So if you don't like or miss certain features, you simply change them or add ones of your own.". But nowadays most assemblers are open source. Knowing the assembler through and through the advantage for me is that I know where and how to change and/or add things more quickly.

My assembler is a multi pass assembler. My assembler needs at least three passes. Please hav a look at the next example:
.eq L1 = L2 + 5
.eq L2 = L3 + 8
.eq L3 = 18
At the first pass L1, L2 and L3 are known but L1 and L2 cannot be evaluated because the value of L3 for L2 is unknown at that moment and the value of L2 for L1. At the next pass L2 can be calculated but not L1 yet. At the third pass L1 can be calculated as well. If there is nothing dependent of L1, we are in luck and there were just three passes needed. But if you expand the above example with L4, L5 and L6, at least six passes are needed.
How does my assembler know that it needs more passes? It counts all errors encountered during a pass. Not being able to calculate the value for L2 is such an error. At the end of the first pass there are at least two errors. After the next pas it will be at least one. A decreased number of errors is valid reason enough to continue. The moment the number of errors is the same as the previous pass, the assembler knows nothing can be done anymore and it stops assembling.

There exist two and even one pass assemblers but they are limited or IMHO they use one or another trick. I just kept it simple because a speedy computer will undo the disadvantages of more passes.

Last thing: I started writing this assembler using Turbo Pascal 3, went throug version 4, 5, 5.5, 6 and 7 and then I switched to Free Pascal Compiler. But some time ago I decided that it should be able to run on old machines as well and so I decided to go back to TP7.

Using the assembler

     = the extensions ".A65", ".Z80", ".ASM", etc. may be omitted

The assembler files

The only three things the assembler asks from you is the processor name and a begin and an end mark, .ba and .en in this case. For the rest you are absolutely free to write it in the way you want. You can define more then one begin address but be warned: it is your own responsibility to take care of not overwriting previous assembled code!
To help you to streamline your application you have a lot of compiler directives at your disposal:
.ap Filename    = APpend a file to be assembled as well
.as $xxxx $yyyyy
		= only ASsemble the given range
.ba $xxxx       = Begin Address of the code or data. More then one .ba may be
.by [$]aa, [$]bb, [$]cc.....
.by label1, label2.....
                = define a number of BYtes. You can use fixed values as well as
                  labels or text (added later, other assemblers allowed it, therefore).
.co This is comment
                = COmment to be displayed on the screen during the last pass
.dw $xxxxxxxx	= define a number of Double Words
.ec		= Enable Comment the in final super file for debugging
.ei             = End If: end of conditional programming
.el             = ELse: part of conditional programming
.en             = ENd of file. All text, code or data behind this mark will be
.eq OwnLabel1 = $xx
.eq OwnLabel2 = $xxxx
.eq OwnLabel3 = OwnLabel2 + 1
                = EQuals, define your own label. Values can be changed.
.fb [$]xx, [$]yy
.fb "c", [$]yy
.fb label, [$]yy
                = Fill Byte: fill a range of length [$]yy with the same byte. A
                  character, a fixed value or a label can be used as input.
.fd [$]xxxxxxxx, [$]yy
.fd "c", [$]yy 
.fd label, [$]yy
                = Fill Double word.
.fi Filename    = use a binary FIle as base for your own binary. Can be used to
                  write patches over original binaries.

.fu [$]xx,$yyyy	= fill the buffer with a byte up to a given address
.fw [$]xxxx, [$]yy
.fw "c", [$]yy
.fw label, [$]yy
                = Fill Word.
.ie		= If Else: part of conditional programming
.if label       = IF: start of conditional programming.
.ma Name        = define a MAcro.
.me             = Macro End
.oo		= stOp support of Overlay files
.ov		= support of OVerlay files, so double label names won't cause an error
.pa 	= same as PAth in MS-DOS
.p	= processor type like p6502, pZ80, pTTL
.rb $aaaa       = Readdress Begin. Following code will be assembled as if it
                  was situated at address $aaaa.
.re             = Readdress End
.ta             = translate given text to ASCII (default)
.tp             = translate given text to PETSCII
.tw "This is 'TEXT'"
                = TeXt, first char+$80 (for Commodore)
.tx "This is 'TEXT'"
.tx 'This is "TEXT"'
                = TeXt
.ty "This is 'TEXT'"
                = TeXt, last char+$80 (for Commodore)
.tz "This is 'TEXT'"
                = TeXt, first and last char+$80 (for Commodore)
.uf 	= Use File, include a file at this point
.uu filename    = Use external Unit as source for the used macros
.wo $aaaa, $bbbb, $cccc.....
.wo label1, label2.....
                = define a range of WOrds.
; Here you can place comments  
                = remark
 here you can place
  several lines
   of comment
                = speaks for itself IMHO
org $xxxx	= begin address, same as .ba
I'm working on a Pascal Compiler that uses this assembler to generate the executables. This can mean that I implement features and directives that are not mentioned yet in this document.

The produced files

.BIN   = binary to be used for programming EPROMs etc.
.LST   = text file with complete listing of statements and resulting code
.SUP   = text file, same as ASM file but after all macros, Use Files, etc. have been processed
'mp-asm.log' = log file


Remark: most browsers aren't familiar with the A65 extension and will ask you whether to open or save it. If you download this example, you can assemble with "MPASM test6580.a65".

C000.asm is a very small but working code. It writes the character 'A' in the top-left corner of your C64 screen. ".ba $C000" means that the program starts at $C000 / 49152. The PRG should be loaded on a C64 with LOAD "C000",8,1. SYS 49152 will start the program.
Warning: be aware of the space in front of the opcodes! If there isn't any form of white space in front of an opcode, the assembler will treat it as a label. And as it won't recognise the operand as opcode, the assembler will end with an error.

C001.asm will display the alphabet on the screen. Notice the place of label L1. Also notice that, although it is quite small, the program is hardly readable.
C002.asm is the same program but made more readable. The most important difference are the lines with comment. How small your program is, comment it! If it isn't for your self, do it for others.

test6580.asm is a test file used by me to test almost all features of the assembler. It also explains the use of most directives. If you have questions, just drop me an email.

The future

In an older I said that I dropped implementing 8088 code. But I changed my mind. I started to create my own Pascal Compiler, one that outputs macros. An assembler then has to turn these macros into binaries. Obvious targets are the various Commodore computers with a 6502 (-ish) CPU. But I want to go a step further by creating a Pascal OS, one that can run on 8088 machines like the IBM PC/XT and the various Commodore PC10/20s. But then I had to find an assembler that could handle my macros. I decided that it would be better to let my assembler support the 8088/8086 as well. I'll think about the V20, 80186, 80286 and better. The V20 has a good chance, including its capabilities to run 8080 programs, but for the others: the higher the number, the lesser the chance.

The source code.

The source code is freeware, just drop me a line and it will be sent to you.

Having questions or comment? You want more information?
You can email me here.