PDP11 Assembler
PDP11 Assembler
This text describes how to assemble PDP11 files on Linux.
MACRO-11 assembler, linker, disassembler for Linux
There are several ways to create object binaries for PDP11 on Linux. I have tested these tools that form a nice tool set for handling PDP11 assembler files on Linux:
- Macro-11 Assembler, see https://github.com/andpp/macro11 (written in C)
- Macro-11 Linker, see https://github.com/andpp/pclink11 (Written in C++)
- PDP-11 Disassembler, see https://github.com/caldwell/pdp11dasm (Written in C)
All tools did compile without any options by just executing make
on them.
To assemble an existing MAC-File just execute
macro11 hello.mac -o hello.obj -l hello.lst
Resulting files:
-rw-r--r-- 1 dennis users 2217 2. Mai 13:55 multiecho.mac
-rw-r--r-- 1 dennis users 202 2. Mai 13:56 multiecho.obj
-rw-r--r-- 1 dennis users 4539 2. Mai 13:56 multiecho.lst
After a file was assembled, it needs to be linked. Linking means that references are relocated and resolved.
pclink11 multiecho.obj /MAP /STB /A /T:<desired target address>
The linkage process creates the executable as .SAV file. Also, a MAP file and a STB (symbol table) file can be created.
-rw-r--r-- 1 dennis users 512 2. Mai 16:45 multiecho.STB
-rw-r--r-- 1 dennis users 1024 2. Mai 16:45 multiecho.SAV
-rw-r--r-- 1 dennis users 335 2. Mai 16:45 multiecho.MAP
The SAV file is an executable. I guess it can be executed with the Operating system RT-11. For now I just disassemble the result.
pdp11dasm multiecho.SAV
This creates a .das
File:
-rw-r--r-- 1 dennis users 21342 2. Mai 16:47 multiecho.SAV.das
Using bare metal code without linking
The steps above even can be done in an easier way.
If the code is written for a PDP11 without any Operating System, the link step is not required.
The assemble step then ca be done with option -e AMA
. This
creates absolute addresses only in LST file result. No further
relocation / linking is required.
To copy the opcodes from the LST file to a target machine, I have
created a tool called all2deposit
. It creates a output file
that can directly read in into a SIMH PDP11 simulator.
TODO: Also add code to load opcodes into a real PDP11 machine.
Programming tools, docs and helpers
- ASCII Table: https://www.alpharithms.com/ascii-table-512119/
- IMHO Best PDP11 Assembler Tutorial site - https://www.chibiakumas.com/pdp11/, it even has tutoral videos https://www.youtube.com/watch?v=sk5Y26Qb1Ow
- PDP (and many others) simulators in JavaScript/Browser https://www.pcjs.org/machines/dec/pdp11/1170/
- Online calculators that can convert to/from octal
- PDP11 Assembler Tutorial - https://programmer209.wordpress.com/2011/08/03/the-pdp-11-assembly-language
- PDP11 Architecure at Wikipedia - https://en.wikipedia.org/wiki/PDP-11_architecture
- The PDP-11 archives at metalab.unc.edu - http://www.ibiblio.org/pub/academic/computer-science/history/pdp-11/
- ODT - https://en.wikipedia.org/wiki/On-line_Debugging_Tool
- Handling Traps - http://docs.cslabs.clarkson.edu/wiki/Developing_for_a_PDP-11
- PDP11GUI IDE for PDP - http://retrocmp.com/pdp-11/simh-telnet-console?id=71:pdp11gui-tutorial&catid=36
Octal numbers
An octal number like 177560 or 377 looks confusing at first sight. All numbers in context of PDP11 are octal numbers; in documentation, manuals and example code. Macro11 could take also hex and decimal numbers and more, but it is better to stay on the tradition here.
Conversion on octal numbers
It is easy to do the conversion, if we use binary representation as intermediate format.
From hex to octal and octal to hex
Example 0xff (which is 255 decimal):
0xff = 1111.1111 binary = 11.111.111 = 377 in octal
This means while hexadecimal numbers group 4 bits to a digit in range 0..F, octal numbers group 3 bits to a digit in range 0..7.
Example 200 octal (which is 128 decimal):
200 octal = 10.000.000 binary = 1000.0000 = 0x80
Byte values
Each byte occupy 8 bits. Highest value possible in 8 bits is 377 octal=0xff.
Lets assume we have two bytes 012 015
This will be in PDP11 word (reversed order, due to little endian):
015 012 = 000.001.101 000.001.010 = 00.0001.1010.0000.1010 = 0x01A0A
The two bytes 012 015 will NOT result in an octal word 015012. The result is:
015 012 = 00.001.101 00.001.010 = 0.000.110 100.001.010 = 006412
From words to bytes, more examples
031061 = 0.011.001 000.110.001 = 0011.0010.0011.0001 = 3231 hex 032063 = 0.011.010 000.110.011 = 0011.0100.0011.0011 = 3433 hex
Because 31,32,33,34 are ASCII codes, the two words represent probably these characters “1”, “2”, “3”, “4”
Add
add.mac
TITLE Add two numbers
.IDENT "V00.00"
STACK = 0x600
.asect
.=1000
.text
start:
mov $STACK, sp
mov #100, r1
add #100, r1
.end
./macro11 add.mac -o add.obj -l add.lst
add.lst
1 000000 000000G 060000 000000G TITLE Add two numbers
000006 000000G
2 .IDENT "V00.00"
3
4 000000 STACK = 0x600
5
6 .asect
7 001000 .=1000
8
9 001000 000000G .text
10 start:
11 001002 016706 000000G mov $STACK, sp
12 001006 012701 000100 mov #100, r1
13 001012 062701 000100 add #100, r1
14
15 .end
15
@0/176377 700
@1000/016706 0
@1002/000000 16706
@1004/177777 0
@1006/000000 12701 # mov ...,r1
@1010/177777 100 # = #100
@1012/000000 62701 # add ...,r1
@1014/177777 100 # = #100
@1016/000000 0 # HALT
@1006G # run the code
001020
@R1/000200 # Get result from R1
Write character ‘B’ to console
Example from: https://en.wikipedia.org/wiki/On-line_Debugging_Tool#Example
TITLE B to console
.IDENT "V00.00"
.asect
.=1000
.text
start:
movb #101, @#177566
jmp @#1000
halt
.end
assembles to:
1
2 000000 000000G 000000G 000000G TITLE B to console
000006 000000G
3 .IDENT "V00.00"
4
5 .asect
6 001000 .=1000
7
8 001000 000000G .text
9
10 start:
11 001002 112737 000101 177566 movb #101, @#177566
12 001010 000137 001000 jmp @#1000
13 001014 000000 halt
14
15 .end
15
Execute the program, needs to be interrupted with HALT switch.
@
000000
@1000/177777 112737
@1002/041604 102
@1004/177777 177566
@1006/041620 137
@1010/137377 1000
@1000GBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB...