P(i)DP-1 code and LLMs

44 views
Skip to first unread message

Norbert Landsteiner

unread,
Oct 7, 2025, 8:16:37 AM (3 days ago) Oct 7
to [PiDP-1]
I understand that it may be tempting to relate to LLMs as a tutor for PDP-1 code, but there are some caveats. Namely, I doubt that an LLM, especially if it was initially trained on modern code (i.e., mostly Python) that features a clear separation of code and data, to be able to "reason" about multiple levels of indirections, not to speak of self-modifying code.
However, failing to reason about this while dealing with a system that supports unlimited steps of indirection may result in "halt and catch fire" code. (Any location used for a lookup, which has the i-bit set, results in another lookup, which in turn may result in circular references.) – Some of this may be also relevant to assemblers and disassemblers.

Here is what I'd deem an essential test for any LLM's fitness for purpose, regarding indirection:

Q: What does this PDP-1 program do?

4/
szs i 10
lac i 12
law i+3
jmp i+4
law i-7762
lio i 14
dio i 11
lac i+5
adc i 15
dap i 13
hlt

start



A (not to be provided to the LLM):
If sense switch #1 is high (on), the program halts at loc 16 with -3 in AC
(via indirect jump to addr. in 4, which in turn resolves to 16 at addr. 10; i-7762 = 16),
else, we are caught in cirular indirections, while trying to load MB for "lac" at loc 5.


04   szs i 10      /skip if ss #1 not zero
05   lac i 12      /load indirect loc 12
06   law i+3       /load -3 into ac
07   jmp i+4       /jump indirect loc 4 = "szs i 10"
                   / => lookup at loc 10 (= next instr.)
10   law i-7762    /i-7762 = 10000-7762 = 16
                   / => resolved jump target
11   lio i 14      /points to loc 14 (here from lookup at 12)
12   dio i 11      /points to loc 11 (here from lookup at 5)
13   lac i+5       /points to loc 5  (cirular reference!)
14   adc i 15      /points to loc 15 (here from lookup at 11)
15   dap i 13      /points to loc 13 (here from lookup at 14)
16   hlt           /end


(The instruction codes at addresses 10..15 are actually irrelevant, we are only interested in the address part and the i-bit.)


Lookup paths (resolving MB):


04   szs i 10      /ss #1 not zero --+               (10)--->+
                   /                 |      circular   |     |
05   lac i 12      /lac (12) ->------|-----+  <--+     |     |
                   /                 |     |     |     |     |
06   law i 3       /ac := -3 <-------+     |     |     |     |
                   /                       |     |     |     |
07   jmp i 4       /jmp (4) ->-------------|-----|-----+     |
                   /                       |     |           |
10   law i-7762    /law 16                 |     |   #16# <--+
                   /                       |     |     |
11   lio i 14      / +---->(14)->----+     |     |     |
                   / |               |     |     |     |
12   dio i 11      / +<----(11)<-----|-----+     |     |
                   /                 |           |     |
13   lac i 5       /                 |    (5)--->+     |
                   /                 |     |           |
14   adc i 15      / +<----(15)<-----+     |           |
                   / |                     |           |
15   dap i 13      / +---->(13)->----------+           |
                   /                                   |
16   hlt           /end <------------------------------+


Notably, this is static code and none of this involves self-modification, which afforded some capaibility similar to a theory of mind. (This may pose some problems regarding object persistence, as it introduces mutability.)

What about this variant, where we first modify the instruction code at loc. 06 ("dac 3" -> "law i 3") and then the address part at loc 05 ("lac i 6" -> "lac i 12"), before we actually start?

4/
szs i 10
lac i 6
dac 3
jmp i+4
law i-7762
lio i 14
dio i 11
lac i+5
adc i 15
dap i 13
hlt

m, lac (law i
dip m-11
lac (12
dap m-12
jmp 4

const
start m


If we were to be nasty, we could also do things like,

m,  law 7100
    sal 6s        /now 710000 or "law i"
    dip m-12
    ...

At least, modifying an address part, which is used for indirect lookup, is a rather common operation…

E.g.,

m0,  lac (mo0-1    /initialize object references, see end of code
     dap ox        /(ready for pre-increment loop)
     lac (mo1-1
     dap oy
     ...
     law i nob     /number of objects (as count up)
     dap \v1       /set up iterations of main loop

ml,  idx ox        /iterate over objects and their properties
     idx oy

ox,  lac .         /load current object's X coor
     add (200
     dac i ox
oy,  lac .         /load current object's Y coor
     add (400
     dac i oy
     ...
     lac i ox
     lio i oy
     dpy
     ...
                   /end of main loop
     isp \v1       /index v1 and skip, if positive (i.e. zero)
     jmp ml        /redo, if not done
     
     ...

    constants      /inserts values for expressions
                   /'mo0-1', 'mo1-1', '200', '400'
    variables      /reserves loc for 'v1'

/object table (list of lists)
/located just after end of code (not part of the tape)

nob = 8            /number of objects

mo0 = .            /X coors (for each object)
mo1 = mo0+nob      /Y coors
mo2 = mo1+nob      /some other property
mo3 = mo3+nob      /ditto
mo4 = mo4+nob      /ditto

    start



Fun fact: I once stumbled over an old US Air Force coding guide (sorry, I failed to archive the source), which explicitly limits code to a maximum of 2 levels of indirection.
I'm failing to see what 2 levels may be required for and would advise against more than a single level (as anything beyond this starts to become confusing and error-prone). But, apparently, there were applications that would require this.
(I guess, without such a deliberate limit, we could set up an entire state machine, just based on the i-bit and forwarded lookups. But this is certainly nothing we would want to even attempt, provided we wanted to persist with sanity.)

Best,
Norbert

Norbert Landsteiner

unread,
Oct 7, 2025, 8:49:14 AM (3 days ago) Oct 7
to [PiDP-1]
Essential correction regarding the last sample code:

     law i nob     /number of objects (as count up)
     dac \v1       /set up iterations of main loop

"dap" wouldn't work here, since this wouldn't make this a negative number (with the instruction part remaining as-is) and we want to initialize a negative number for a count-up loop! (As we want to iterate from –<nob> to, but not including, zero for a total of <nob> iterations.)
Well, not confusing "dac" and "dap" is probably the most essential piece of PDP-1 coding… :-)

Best,
Norbert

Oscar Vermeulen

unread,
Oct 7, 2025, 1:32:49 PM (3 days ago) Oct 7
to [PiDP-1]
I refuse to read your explanation before figuring this out but I need one bit of help, just one bit...

>>  adc i 15

adc?

Please end my suffering on this one thing...

Kind regards,

Oscar.

Oscar Vermeulen

unread,
Oct 7, 2025, 1:52:34 PM (3 days ago) Oct 7
to [PiDP-1]

I cheated and replaced adc with some other instruction. I think adc must be a typo? Then single-stepping the code and adc itself does not matter. Only its address bits. It's infinite indirection! How evil.


...now I read your post... yes, hmm. I'll gather the output of the LLM if anyone finds it fun. They (Claude and ChatGPT with the PDP1.md) got off the plot very quickly (eloquently though). 
But my own brain also intuitively refused the cold hard logic of infinite indirection.

This was fun though!

Kind regards,

Oscar.

Norbert Landsteiner

unread,
Oct 7, 2025, 4:23:27 PM (3 days ago) Oct 7
to [PiDP-1]
> I refuse to read your explanation before figuring this out but I need one bit of help, just one bit...
>
>>  adc i 15
>
> adc?
>
> Please end my suffering on this one thing...

Oops. I'm currently deep into 6502 code. I guess, we may deem ourselves lucky that there isn't a "clc" in front of this…
So make this "add i 15", please. (But, as already pointed out, the instruction code doesn't matter, just the address part and the i-bit.)

Sorry,
Norbert

Bradford Miller

unread,
Oct 7, 2025, 6:58:57 PM (3 days ago) Oct 7
to Norbert Landsteiner, [PiDP-1]
I’ll bet some employers would fire anyone who tried to run this sort of thing. It can burn out the core plane!

--
You received this message because you are subscribed to the Google Groups "[PiDP-1]" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pidp-1+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/pidp-1/06a30e7d-1eb1-4091-80fc-5ebaf234a86an%40googlegroups.com.

Norbert Landsteiner

unread,
Oct 8, 2025, 5:59:43 AM (2 days ago) Oct 8
to [PiDP-1]
There may be truth to "halt and catch fire"…
(Just think of all the amplification circuitry that comes with core memory and code like this hammering the same lines again and again. This should be quite the stress test, when run over a longer period of time.)

Bradford Miller

unread,
Oct 8, 2025, 9:24:11 AM (2 days ago) Oct 8
to Norbert Landsteiner, [PiDP-1]
Given the 1 drew about 2kw of power in it’s normal configuration (could be more with additional memory racks), I’m actually surprised it didn’t have one of those big emergency power off switches near the front panel, common to computers of the time.

Reply all
Reply to author
Forward
0 new messages