Skip to content

no382001/pdp-11-40-emulator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

106 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PDP-11/40 Emulator

A PDP-11/40 emulator and a small compiler (oneshot) for a C-like language targeting it.

Milestone: ED (an early version of the the standard Unix text editor) runs on bare metal via paper tape.

Next: Running Unix itself.

CI

Table of Contents

Emulator

Emulates the PDP-11/40 processor with:

Instructions: MOV, ADD, SUB, CMP, BIT, BIC, BIS, CLR, COM, INC, DEC, NEG, TST, ASL, ASR, ROL, ROR, SWAB, ADC, SBC, MUL, DIV, ASH, ASHC, XOR, JMP, JSR, RTS, RTI, SOB, all branch instructions (BR, BNE, BEQ, BPL, BMI, BCC, BCS, BVC, BVS, BGE, BLT, BGT, BLE, BHI, BLOS), TRAP, EMT, IOT, HALT, WAIT, RESET, SXT, MARK, condition code ops

Addressing modes: Register, register deferred, autoincrement, autodecrement, index, and their deferred variants

Devices: Paper tape reader/punch, teletype (TTY) with interrupt support

./pdp1140 [OPTIONS]
  -f FILE         load program from file
  -a ADDR         load address (octal/hex)
  -r ADDR         run address
  -u              unlimited cycles
  -t FILE         paper tape input
  -p FILE         paper tape output
  -i FILE         TTY input
  -o FILE         TTY output
  -d              debug output
  -m              dump memory on exit

Oneshot Compiler

Compiles a C-like language to PDP-11 machine code. A non-optimizing BCPL inspired language made for throwaway bootstrap code. Hence 'oneshot'.

Types: word_t, byte_t

Statements: variable declarations, const, assignment, deref assignment (@addr = val), if/else, while, return, function calls, inline assembly

Expressions: arithmetic (+, -, *, /, mod), bitwise (&, |), logical (&&, ||), comparison (==, <, >), dereference (@), casts, function calls, strings

Literals: decimal, octal (0o777), character ('a')

./1shot.pl [-i FILE] [-o FILE] [--ast|--checked|--ir|--resolved]

Example:

word_t main() {
    word_t x;
    x = 42;
    return x;
}

Inline assembly:

[mov(0o177566, r1), movb(65, at(r1))]

Memory Layout

Program structure:

0o177776  +------------------+ <- initial SP (highest address)
          |    (stack)       |
          |   (grows down)   |
          |                  |
          |        v         |
          +------------------+ <- SP (current stack pointer)
          |                  |
          |   (free space)   |
          |                  |
          +------------------+
          | string literals  |
          +------------------+
          | user code        |
          +------------------+
load addr +------------------+
          | _start:          |
          |  mov #0o177776,sp|
          |  jsr pc,main     |
          |  halt            |
          +------------------+
          | ...              |
          +------------------+
          | interrupt vectors|
0o000000  +------------------+ (lowest address)

Stack frame (per function):

 higher addresses
         ^
         |
0o177776 +------------------+
         | arg N            |  4+2*(N-1)(r5)
         | ...              |
         | arg 2            |  6(r5)
         | arg 1            |  4(r5)
         +------------------+
         | return address   |  2(r5)  (pushed by JSR)
         +------------------+
         | saved r5         |  0(r5)  <-- r5 points here
         +------------------+ <- r5 (frame pointer)
         | local 1          |  -2(r5)
         | local 2          |  -4(r5)
         +------------------+ <- sp
 lower addresses
         |
         v

Calling convention:

  • Arguments pushed right-to-left
  • Return value in r0
  • Caller cleans up arguments
  • r5 is frame pointer, saved/restored by callee

Building

make

Running ED

# uses stdin and stdout for default i/o
# oneshot will compile the absolute loader
# the emulator will load the bytecode at 020000 and start running there
# the absolute loader will start reading tapes/ed.abs and load it into memory
# then when its done, jump to the start address of tapes/ed.abs, you should see a *I printout
./oneshot/1shot.pl -i programs/absolute.1 | \
./_build/bin/pdp1140 --load-addr 020000 --run-addr 020000 --tape-in tapes/ed.abs -u -m

I just got this running, the first real bare metal paper tape program that runs and actually does something, but i have no idea what the keybindings are. You can switch modes, if you mess around. Your terminal will be blocked if you run this, as I'm reusing the pipes and selecting on raw inputs to use as teletype interrupts.

What's Missing for Unix

Memory Management

  • No MMU (Memory Management Unit) - Unix requires kernel/user mode separation and virtual address translation
  • No segmentation registers or page tables
  • No memory protection (supervisor vs user mode)

Missing Instructions

  • MFPI/MTPI (move from/to previous instruction space)
  • MFPD/MTPD (move from/to previous data space)
  • SPL (set priority level) - partially handled via PSW writes
  • MTPS/MFPS (move to/from processor status) for 11/34+ compatibility

Devices

  • No RK11/RK05 disk controller
  • No RL11/RL02 disk controller
  • No TM11 tape drive
  • No line clock (KW11-L) for scheduling interrupts

Other

  • No separate kernel/user stack pointers
  • No previous mode tracking in PSW
  • Bus error handling is minimal
  • No UNIBUS map for 18-bit addressing

About

A PDP-11/40 emulator and a small compiler (oneshot) in Prolog for a C-like language targeting it. It can currently run bare-metal ED from paper tape.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors