Note: This is the repository for the first version of PDPy11. The latest version is available here: https://github.com/pdpy11/pdpy11.
PDPy11 is a compiler for PDP-11, written in Python.
License: MIT
- Python 2.7 or later, or Python 3.5 (may work on earlier versions)
- No Python modules required
- Any platform (Windows, Mac OS, Linux)
$ git clone https://github.com/imachug/pdpy11
Press green Clone or download button (it's above file list), press Download ZIP and extract the archive.
You can check the full docs as docs.md.
Read how to use Sublime Text build system and syntax highlighting here.
- Create
test.macfile with the following content:
MOV #2, R1
-
cdto the directory that containspdpy11(e.g. if you usedgit clone, don't runcd pdpy11afterwards) -
Run
python -m pdpy11 path-to/test.mac
This will generate test.bin file with the following content:
001000 ; the file is loaded from address 1000 -- the default address
000004 ; 4 bytes, or 2 words -- the size of the resulting code
012701 ; MOV (PC)+, R1
000002 ; .WORD 2
The header (4 bytes) is called ".bin header", sometimes "binary header".
To remove ".bin header", run python -m pdpy11 path-to/test.mac --raw, or add make_raw meta-command to the end of the file.
If you want to use .sav format, run python -m pdpy11 path-to/test.mac --sav (or use make_sav meta-command):
For example:
MOV #2, R1
make_raw
MOV #2, R1
make_sav
For debugging, you can enable .lst file generation by using python -m pdpy11 path-to/test.mac --lst. Here's an example:
.LINK 3000
HELLO = 2 + 2
WORLD: MOV #HELLO, R0
path-to/test.mac
000004 HELLO
003000 WORLD
Standard PDP-11 assembler syntax is used, i.e.:
Strings can be surrounded by ", ' or /. Literal strings can be joined together: "A" "B" is the same as "AB". <n> syntax can be used to put a raw character, e.g.: "A"<12>"B" inserts a newline between "A" and "B".
Registers: R0..R7, with SP = R6 and PC = R7.
Supported commands:
HALT,WAIT,RTI,BPT,IOT,RESET,RTT,START(code 12),STEP(code 16),NOP(code 240),CLC,CLV,CLZ,CLN,CCC,SEC,SEV,SEZ,SEN,SCC,RETJMP,CALL(as alias toJSR PC),SWAB,CLR(B),COM(B),INC(B),DEC(B),NEG(B),ADC(B),SBC(B),TST(B),ROR(B),ROL(B),ASR(B),ASL(B),SXT,MTPS,MFPSBR,BNE,BEQ,BGE,BLT,BGT,BLE,BPL,BMI,BVC,BHIS,BCC,BLO,BCS,BLOSEMT,TRAP,MARKMOV(B),CMP(B),BIT(B),BIC(B),BIS(B),ADDJSR,XORSOB,RTS
2 label types are supported:
- global (e.g.
ABACABA,TEST) - local (e.g.
1or0). Labels like1$(i.e. digit + anything) are supported as well
In addition to these 2 label types, meta-label . is supported, pointing to the beginning of current command, e.g.:
MOV #100, R0
SOB R0, . ; SOB 100 times and then continue
BR .-2 ; branch to SOB
To compile ("link") the program from another address (e.g. 0o3000), not the default 0o1000, use .LINK 3000 macrocommand.
To enable pdp11asm compatibility mode (NOT RECOMMENDED!), use .SYNTAX pdp11asm macrocommand.
To store a byte, use .BYTE n. To store a word, use .WORD n. To store N zero bytes, use .BLKB n. To store N zero words, use .BLKW n.
To insert a string, use .ASCII or .ASCIZ = .ASCII + .BYTE 0.
To set a variable, use: A = 7 or A EQU 7. Then you can use A instead of 7.
Example:
A = 7
.WORD A
MOV #A, R0
To insert another file, use insert_file "path-to-file" if it's a binary file or .INCLUDE "path-to-file.mac" if it's an assembler file. Notice: in pdp11asm compatibility mode, .INCLUDE works like .INCLUDE + .END (i.e. no code after .INCLUDE is compiled). To fix this, 1. don't use compatibility mode, or 2. use .RAW_INCLUDE path-to-file.mac (without quotes!).
Notice: if you define labels (or variables) inside included files, they're not visible in the main program. Add .EXTERN ALL line to the beginning of included file to "export" all labels that are defined in the included file to the main program and all other included files, for example:
main.mac
.INCLUDE "constants.mac"
MOV #1, @#SOME_REGISTER1
.INCLUDE "a.mac"
a.mac
MOV #2, @#SOME_REGISTER2
constants.mac
.EXTERN ALL ; same as .EXTERN SOME_REGISTER1, SOME_REGISTER2
SOME_REGISTER1 = 177714
SOME_REGISTER2 = 177716
If you want to include constants.mac twice (e.g. you're going to include it in every file that uses the registers, to show that it's a dependency), use:
constants.mac
.ONCE ; never compile code below twice, which would result in "redefinition of label" error
.EXTERN ALL ; same as .EXTERN SOME_REGISTER1, SOME_REGISTER2
SOME_REGISTER1 = 177714
SOME_REGISTER2 = 177716
Check docs.md for more .INCLUDE / .EXTERN / .ONCE usecases.
To repeat some code a few times, use:
.REPEAT 10 {
.WORD 0
}
The above is the same as .BLKW 10. You can use any commands or macrocommands inside .REPEAT.
It's quite possible that you're making a big project -- otherwise, it doesn't make sense to use such a big tool as pdpy11. pdpy11 has a special mode for projects.
-
Create directory
TestProject. -
Create
test.macfile insideTestProjectwith the following content:
MOV #2, R1
make_bin
- Run
python -m pdpy11 --project TestProject.
This will generate TestProject/test.bin file with the same content as we got in Compiling single file to .bin section.
Notice that we've used make_bin, but we didn't add --bin or --raw CLI argument. In a large project, you may have several outputs -- e.g., if you're making an OS, you may have a bootloader (< 512 bytes) and os (the kernel itself, the stuff bootloader loads). So you have to manually set which files should be compiled to .bin or .raw -- they are called "include roots".
An interesting point is that all external labels are shared between all "include roots". For example:
bootloader.mac
.EXTERN OS_LINK
OS_LINK = 100000
; load os
MOV #OS_LINK, R0
...
CALL @#160004
; startup
JMP @#OS_STARTUP
make_raw
os.mac
.EXTERN OS_STARTUP
.LINK OS_LINK
.WORD 0 ; some options for the processor macrocode,
.WORD 1 ; or some other constants that must be exactly
.WORD 2 ; at OS_LINK
OS_STARTUP: ; the code to be executed when the kernel is loaded
...
make_bin
The above project, when compiled, will result in two files: bootloader and os.bin, with OS_LINK and OS_STARTUP labels shared between them and all other .mac files.
Some other useful things added by project mode:
.INCLUDEnow works on directories: it includes all.macfiles inside the directory.- You can use
.pdpy11ignoreto set what files aren't included when.INCLUDEis called on directory and what files aren't checked formake_rawandmake_bin(i.e. which files can't be "include roots"). - You can run
.INCLUDEon files that have.LINK. This is the same as compiling the included file in raw mode and embedding the raw content to current file, like withinsert_file.