Problem With Random Macro

129 views
Skip to first unread message

MICHAEL GARDI

unread,
Oct 28, 2025, 7:37:36 PMOct 28
to [PiDP-1]
I've been teaching myself PDP-1 assembler and to that end have coded an implementation of Bresenham's integer based line drawing algorithm. It seems to be working OK but to really test it out I wrote a program to generate random end points and draw lines between them in a continuous loop. To generate the random coordinates I "borrowed" the random macro from Retrochallenge 2016 Computer Space Simulator code. (Note the identical code is in Spacewar 3.1 which is where they got it ;-) That is where I started having problems. Random with a starting "seed" of zero would immediately converge on 0 and only produce zeros. With a non-zero seed it would produce a small set of numbers (say 3-20) before settling into a repeating loop of those numbers. According to this article:  "Anatomy of a Random Number Generator" this code should produce 261,654 distinctive values before repeating. So I wrote a small test program.

STARS

/ Create a random number.
define random
lac ran
rar 1s
xor (355670
add (355670
dac ran
term

100/
go, random / Generate a new random number.
cli    / Clear IO.
scr 9s / Move low 9 bits into high 9 bits of IO.
sal 9s / Move remaining 9 bits into AC high part.
dpy-i / Plot the point. Don't wait.
jmp go

ran, 716243
start go

The stars are being plotted exactly as the Computer Space code did by treating he 18 bit random number being produced as two 9-bit numbers for the x and y coordinates. I assembled and ran this through the Web interface and this is the result:stars.jpg
Good distribution but there are only 18 static "stars" which tells me they are being repeatedly refreshed. There should be many, many stars with old stars fading out as new stars are plotted.

The only theory I have is that the add instruction is not handling the carry overflow correctly. From the linked article:

That is, there’s also a pecularity to the addition, which introduces a bit of extra variety: Using one’s complement, a) we have to adjust for minus zero (777777 → 000000) and b) we have to adjust for any overflow in the sign position by an extra increment (as may be observed in iteration #6).

emulation of one’s complement addition (18 bits)

function adc(value) {
    ac = ac + value;
    // check overflow of sign bits (to bit 18)
    if (ac & 0o1000000) ac = (ac + 1) & 0o777777;
    // correct negative zero
    if (ac == 0o777777) ac = 0;
}

thus

     101000111110011011  //  507633
  +  011101101110111000  //  355670
  = 1000110101101010011  // 1065523

but

  adc(
     101000111110011011, //  507633
     011101101110111000  //  355670
  )
  => 000110101101010100  //  065524

OK. I've probably said too much.

Thoughts?

Mike


Alen Shapiro

unread,
Oct 28, 2025, 8:02:10 PMOct 28
to [PiDP-1]
Hi Mike,

I've been trying to document issues with the available C -> PDP1 cross compiler and have run across an issue that may be related to how the simulator handles "shift" instructions across a 16-bit boundary. I've not been able to isolate the issue away from the compiler yet as there's a more fundamental issue with initializing integers larger than 12-bits. Just in case this is relevant the code I'm playing with shifts 3-bits (07) up from the low bits, up to the high bits and then back down again. Here's the C Code:

#define THREE_BITS 07

bits = THREE_BITS;
pdp1_puti(bits, OCTAL_BASE);
pdp1_putc(NL);
for(i=0 ; i < 5 ; i++) {
bits = bits << 3;
pdp1_puti(bits, OCTAL_BASE);
pdp1_putc(NL);
}
pdp1_putc(NL);
for(i=0 ; i < 6 ; i++) {
pdp1_puti(bits, OCTAL_BASE);
bits = bits >> 3;
pdp1_putc(NL);
}

pdp1_puti(bits, OCTAL_BASE);
pdp1_putc(NL);

which gives this output:

0
07
070
0700
07000
070000
0100000

0100000
030000
03000
0300
030
03
0

Looks like shifting up into the 16th, 17th, and 18th bits loses 2 out of the three bits but shifting back down again gains back one of the bits.

Might this be related to your random function misbehaving?

Regards,
--Alen

MICHAEL GARDI

unread,
Oct 28, 2025, 8:14:27 PMOct 28
to Alen Shapiro, [PiDP-1]
I’m not sure  I see a connection to my issue Alen. If I had to guess your issue could be related to arithmetic vs logical shifts. What op codes are being generated under the covers? 

Mike




--
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/166d0b36-8931-496f-94c3-0f0868829f57n%40googlegroups.com.

Bill E

unread,
Oct 28, 2025, 8:34:54 PMOct 28
to [PiDP-1]
Interesting. I assembled the same code using macro1 as installed by the distribution. Works fine, I see points uniformly distributed over the entire screen.
Here is my source and rim, try the rim.

Bill
stars.mac
stars.rim

MICHAEL GARDI

unread,
Oct 28, 2025, 8:50:46 PMOct 28
to [PiDP-1]
Thanks for doing that Bill. Your rim works the same as mine when loaded through the Web interface. Yes there is and even distribution of stars but there should be hundreds of starts plotted not just 18. random should generate 261,654 unique x/y positions and not just repeat 18 positions.  

Mike

Alen Shapiro

unread,
Oct 28, 2025, 10:46:34 PMOct 28
to [PiDP-1]
It's doing "SAL 3" for the left shift loop and "SAR 3" for the right shift loop. Both seem to not properly handle the high-2 bits (b17 and b18) which could easily affect the distribution and count in pseudo-random functions.

L52: L53:
law -2 law -2
add 0130 add 0130
dac 0100 dac 0100
law -2 law 8
add 0130 dac 0101
dac 0101 lac.i 0100
lac.i 0101 dac 0100
sal 3 jsp pdp1_puti
dac.i 0100 law -2
law -2 add 0130
add 0130 dac 0100
dac 0100 law -2
law 8 add 0130
dac 0101 dac 0101
lac.i 0100 lac.i 0101
dac 0100 sar 3
jsp pdp1_puti dac.i 0100
law 63 law 63
dac 0100 dac 0100
jsp pdp1_putc jsp pdp1_putc
law -1 law -1
add 0130 add 0130
dac 0100 dac 0100
law -1 law -1
add 0130 add 0130
dac 0101 dac 0101
law 1 law 1
add.i 0101 add.i 0101
dac.i 0100 dac.i 0100

Bill E

unread,
Oct 29, 2025, 6:51:09 AMOct 29
to [PiDP-1]
I do get hundreds, many hundreds of stars on the display. Here's the lst for the assembly. I'd compare it to yours, check that the opcodes match.
Also, shift works as documented. It DOES NOT shift the high bit in the ac. Check the description in the original PDP-1 Handbook.
Bill

stars.lst

MICHAEL GARDI

unread,
Oct 29, 2025, 12:52:58 PMOct 29
to [PiDP-1]
I should mention that I resolved this issue but don't know why. I switched to the native Pi environment and re-assembled my programs with macro1_1 and ran them through the GUI interface and they worked. I had been exclusively working through the Web interface and via VNC. In the process I rebooted the pi a couple of times. The weird part is that when I switched back to Web/VNC the programs worked there too! Go figure. Sorry for the wasted bandwidth. Big thanks to Bill for his help.

Mike

MICHAEL GARDI

unread,
Nov 13, 2025, 2:49:39 PMNov 13
to [PiDP-1]
I think I have found the root cause of this issue. I had jumped back into programming the PDP-1 and to my dismay the problem with random returned. I would only get a small number of random numbers before they started repeating. I have been basing my code on the excellent material in the Ironic Computer Space Simulator blog entries. When I compared what I had with the code samples from the ICSS one thing that I noticed is that at the end of all of their programs they included the pseudo ops constants and variables.  As in:

. . .
/insert constants and variables, end of program

constants
variables

start 4


So I tried this and voila everything started working as expected for me. When I look up why this might be so I got:

In PDP-1 Macro-1 assembly language, the constants keyword (or more commonly as a pseudo-instruction, simply constants) is used to inform the assembler that a specific block of memory should be treated as containing data constants rather than executable instructions. 
This declaration helps the assembler properly organize the object program, ensuring that data is placed in the appropriate memory segments and handled correctly during the assembly and loading process. The final object program tape includes distinct blocks for instructions and for constants. 
The constants keyword is part of the original PDP-1 Macro assembler's method of program organization, which, along with the variables keyword, was used to manage memory segments in a single-pass or two-pass assembly process. 
So Macro-1 uses it to help organize memory in the object program.  I guess without it memory could end up in either a valid or invalid state, hence the inconsistent behavior I was seeng.
This is a big relief for me and a tip for all of you out they starting to write PDP-1 Assembler.
Mike

Matthias Barthel

unread,
Nov 14, 2025, 5:31:38 AMNov 14
to [PiDP-1]
thats was also my mistake in my first programs. the most important line is "start XX" ! 

MICHAEL GARDI

unread,
Nov 14, 2025, 7:14:26 AMNov 14
to Matthias Barthel, [PiDP-1]
No Norbert Landsteiner shared this with me:

Regarding your post on the random procedure and it working with the 
CONSTANTS directive:
This is an important concept of the Macro assembler:

Whenever the CONSTANTS keyword is encountered, any previously assembled 
code is dumped onto a data block on tape and memory is allocated 
in-place for any newly gathered constant expressions. While usually put 
at the end of a program, this can be anywhere and may be also used 
multiple times. Meaning, a program can continue after this, but you'll 
have to jump around this constants block.

The VARIABLES directive works the same, just for locations that should 
be reserved for variables.
Finally, START does the same, but doesn't allocate any space, instead, 
it provides an address (implicitely defaulting to 4) to jump to, once 
the program has loaded.

What all these 3 directives have in common is that they are flushing the 
buffers and force the object code to be written to tape as a data block.

So, I guess, it may have been about the actual value for "ran" not being 
written to tape, as there was nothing causing the buffers to be flushed? 
I guess, any of the three directives should do the trick, but any 
program should really end with START. 


--
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.

Bill E

unread,
Nov 14, 2025, 8:06:54 AMNov 14
to [PiDP-1]
Native macro and macro1 both have virtually zero error checking. Forget one detail, you get a bad binary with no notice at all.
The errors I have had:
The first line absolutely has to be a comment. If you put code there, it becomes the comment.
Setting an address, such as 100/ must be on a line by itself. Anything after the / is actually a comment. You can always do 100, instead.
If you have any constants, you absolutely need the 'constants' directive at the end of your program, just before the 'start', see next. Forget it, your constants get put where you don't want them.
The last line has to be a 'start nnn' or you again will get a bad binary.
Finally, spaces and tabs are not the same, just to confuse everything. Spaces are just separators. Tabs are 'start a new instruction in the next location', just as if you had started a new line.

I still fume over things like that, if it looks the same, it should work the same. I've ranted about that in makefiles for ages. That one caused me a lot of pain. I was copying code from a listing, saw something like: 'rcl 6s and (nnn sza'. Ok, entered it that way. Program didn't work. Look at the listing, hmm, that instruction is gibberish. Well of course the original had to have had tabs, totally invisible in the listing.

Bill

Norbert Landsteiner

unread,
Nov 14, 2025, 3:34:29 PMNov 14
to [PiDP-1]
For a change of perspective:
Macro was ported over from the TX-0, meaning this is 1950s software and must be one oft the earliest symbolic assemblers, ever.
And it is entirely agnostic of the instruction set (there's a directive to purge the predefined symbols and you get a blank late to work with.)
It's amazing, what it does, like macros, cascading definitions, even macros within macros, etc.
Compare this to a 1970s assembler, like the original MOS cross-assembler for the 6502, and this is still way ahead!

On the other hand, yes, it was written for a rather restricted community and everybody would have read the manual. But it's also a bit unfair to expect this to work just like any assembler written 50+ years later.

It's actually amazing, how few restrictions, there are:

1) a program starts with the title, which will be also the header for every page of a printout
2) you have to choose on your own, where to include CONSTANTS and VARIABLES (but you can do so at multiple locations)
3) you can't have storage instructions (i.e., CONSTANTS, VARIABLES) inside a macro (which is only logical)
4) It doesn't auto-flush the internal buffer at the end, so a final START is mandatory (but you'll need to define a start address anyway, because of the binary loader).

And that's actually it. Otherwise, it's mostly free-form.
(Compare this with quirky modern requirements, like a magical "main" function in C. If I come from Algol, how am I supposed to know this? Or, the other way round, if I come from C, how am I supposed to know that an Algol program is supposed to start with PROGRAM? Obviously, this is all crap! ;-) And the handling of storage instruction is actually rather simple, if we compare this to the handling of malloc in C.)

Yes, the use of TAB as a non-white space character is quirky from a modern perspective, but, I guess, it kind of makes sense, if you're writing this on paper (i.e. a Flexowriter), and a line per instruction would have been quite wasteful and forced you to look at miles of paper. And don't forget, none of the modern conventions (like white-space agnostic code formats) existed at that time, rather, there would be a prehistory from the Whirlwind, etc., things, we have no idea of.

I still think, even with the more obvious restrictions, like a symbol is just up to 3 characters (but may consist of any anum chars) in the original incarnation, given the circumstances (like this is all working on a 4K machine), it's an amazing piece of software!
(We may feel privileged that we have still access to this.)

Best,
Norbert

Bill E

unread,
Nov 14, 2025, 5:55:12 PMNov 14
to [PiDP-1]
Yes, it was a product of its time, not arguing that. But, this is now, getting on to a half-century later. There is no reason unless you're an absurd purist to stick with it. A nice cross-assembler with error checking, long names, etc. isn't unreasonable. Angelo has made some progress in that direction, and there are probably more. I just haven't looked yet.
Bill

Norbert Landsteiner

unread,
Nov 14, 2025, 10:33:03 PMNov 14
to [PiDP-1]
I consent entirely to this.
Notably, there were soon other assemblers that built on Macro and most of them are also backward compatible (i.e. can assemble Macro code). The most advanced was, I believe, Midas. (At least, its authors must have been pretty convinced that anything touched by it will be instantly turned into gold. ;-) ) And, I think, the long-lasting family of PAL assemblers also originated on the PDP-1.

We're using Macro mostly, just because there's already an implementation in C of it, but, TBH, there isn't really any other reason for this. Other, it's a historic monument and a rather remarkable antiquity. (And, if you want to feel like Steve Russell, you can still do so!)

The only thing I'm worried about is reinventing Midas or PAL and then naming this "Macro", as well, as this can only result in confusion. If we're able to come up with a new cross-assembler, we should also be able to come up with a new, unique name for this.

Best,
Norbert

Angelo Papenhoff/aap

unread,
Nov 15, 2025, 6:30:48 AMNov 15
to [PiDP-1]
Well, try my cross-assembler, monas (or more properly μονάς), it's in the pidp1 repo. I thought about calling it monad, but i wanted "as" to hint at the assembler, so i picked the nominative singular. "one" + "assembly" -> μονάς. macros are done with m4 for simplicity.

Bill E

unread,
Nov 15, 2025, 11:23:54 AMNov 15
to [PiDP-1]
I'm wondering if a good solution would be  a preprocessor for macro that handles some of the issues and adds some convenience features. This would preserve macro compatibility but hide
some of the warts. Maybe my next project.
Here's what I would implement:
Include files like cpp provides
A visible delimiter character, e.g. ral 6s; sma, which would convert the ';'  to a tab to make macro happy
Allow long names, mapping them into generated short names. If using macro1, it would make use of its longer names
Some better error reporting
Possibly even use cpp itself with some glue code?

The downside, of course, is that any code that makes use of this functionality has to be processed by it to get real macro.

Any comments?
Bill

R Clark

unread,
Nov 15, 2025, 11:59:53 PMNov 15
to [PiDP-1]
I think a program that is more of a lint type application would be more approriate.  It would point out the errors and then you fix your program so it will work properly with Macro. That way you program stays true to the '60s, yet you have a modern checker to help keep the quirks straight ... I assume that is/was the goal when the PiDPs were created -- program like the late 60s....  Just my two cents ... I mean five cents now.

Bill E

unread,
Nov 16, 2025, 7:28:16 AMNov 16
to [PiDP-1]
That's more or less my idea now.
Just checking for the first line not being code and having a constants and start check would eliminate many newbie mistakes.

However, there are 3 things that I really want that can be added that after preprocessing would be valid macro:

Use ';' to mean <tab>, would be converted to an actual tab by the preprocessor.

Add include files. This would be done as what macro would consider a comment, //include filename at the beginning of a line. Yes, I know multiple files can be handled now, but you have to know
what a particular program needs to be assembled with, not ideal. This one would be valid macro even without preprocessing, just not functional.

Add the ascii equivalent of text and character, ascii xxxx, achar xl or xr to put the ascii char in bits 2-9 or 10-17. Like it or not, we don't live in a flexo world now, and doing useful things with text means ascii. Having to manually enter ascii character codes is tedious and error-prone. The preprocessor would replace with octal values, just as text does for flexo values.

Macro1 is already not fully compatible with macro, adding longer names, an 'or' operator between syllables, e.g. ral 6s ! sza, use of ~ or \ to mean overstrike, etc., so clearly others have decided
strict compatibility for the sake of purity isn't worth the pain.

I did implement flexo<->ascii conversion in my DSC2 and SCS socket IOTs, so the ascii directives aren't critical when using those, but for anything else, they would be very useful.

Bill

MICHAEL GARDI

unread,
Nov 16, 2025, 10:09:31 AMNov 16
to [PiDP-1]
Just out of curiosity Norbert, what did you use to assemble your Ironic Computer Space Simulator? It has to be 2000+ lines of code, right. What steps did you take to prepare ICSS to run on the Computer History Museum PDP-1?

Mike



Norbert Landsteiner

unread,
Nov 17, 2025, 2:21:37 PMNov 17
to [PiDP-1]
Oh, this is a rather unspectacular story.
I used macro1.c, the version that used to come with simh, via the terminal. And I had a Perl script, which took the rim-file and converted it into something my web-based emulator could run, i.e., encoding it base64 and packing it into a JSON-like structure. And then, reload and see.
Editing was done in BBEdit on a Mac. I'm very gracious for having an UI editor that allows for multiple views into the source file. Which *really* helps with longer files, so it wasn't a problem having this all in a single file. (Not sure, what would have been, if all there was to write and edit this all had been a Flexowriter.)
Not having any any debugging tools wasn't really a problem, as well, since I'm more the stares-at-source-when-there-is-a-problem person. Meaning, I never got warm with debuggers and started a career in professional web development, when all there was for debugging was a JavaScript prompt. So I'm fine with that.

(A bare metal program won't throw an error, anyway, and a program that is mostly a visual feedback loop will give away where it hangs pretty easily. If this would have been about a language compiler, this may have been a different story. – Similar applies to another RetroChallenge project regarding the Atari VCS/2600 and the fun of "racing the beam". Video games are really great projects for bare metal programming, because of their inherent organisation around a visual feedback loop, so, even without great development tools, there's immediate feedback for what the program is doing or not and where it may go astray. Highly recommended for a first ambitious project!)

As for the CHM, well, I never was there. (Austria is really kind of on the other side of the planet.) This was all Ken Sumrall's doing. As far as I remember, at that time, he had to drive to a storage warehouse for the paper taper punch, some 1 or 2 hours from the CHM. (Watching CuriousMarc's, AKA Marc Verdiell's, videos, there seems to be a paper tape punch connected to a PC just in the next room, nowadays.) So, one day, quite out of the blue, there was an email saying, "hi, see this" – and, actually, that bit of video, which is linked at the project blog, is all ever saw of the program running on the PDP-1.
(At that time, Ken Sumrall and Lyle Bickley were really my bridge to the CHM and the PDP-1 restoration team and those who related things.)


Best,
Norbert

Norbert Landsteiner

unread,
Nov 17, 2025, 3:21:57 PMNov 17
to [PiDP-1]
However, there is a much more spectacular story about me and the CHM PDP-1.

Back in 2015, I was at the hight of my Spacewar sleuthing career: I had rediscovered the "Minskytron hyperspace" and how this all fit together (a patch to patch), the very thing I had been looking for from the very beginning, found that curious version with the "twin sun" and the "Needle" in the center and everything else plotted relative to it (as it turned out later, by D.D. "Monty" Preonas, while working on what became the version for two displays) and what this was meant to mean and do, and discovered some on-screen score display, nobody seemed to know about, similar to, but also different from the one of Spacewar 4.8.
So I proudly put this all together in a modified version of Spacewar 4.2, which can be found as "Spacewar 2015" on my website.

Notably, this was never intended to be run by the CHM, but – and I only learned about this post mortem – Lyle Bickley and Ken Sumrall liked this quite a bit, extracted the encoded rim-file from the website, punched a paper tape of it and were actually discussing using this for the CHM demos.

So, there's something to be known about the CHM PDP-1: namely, the decoding of the display brightnesses seems to be off. As some may know, the display brightnesses are encoded in 3 bits, 0-7, but are actually denoting a range in ones' complement, as +3…-3 [is it -0 or -4?]. The positive range, 0…3 seems to be ok, at least 0,1,3 seem to be working as intended, but the negative range is, well, weird. If we risk a look at the source code of the version they run at the demos, Spacewar 1F (see the use of the macro 'dislis'), this uses other brightness values for the background starts (of the Expensive Planetarium) than the original game, some of which really shouldn't work. Conversely, a photo from the restoration effort shows an early running of Spacewar with quite a number of the background stars missing, as the brightness value isn't decoded correctly.

So, where were we? Well, with Lyle Bickley and Ken Sumrall suggesting to run "Spacewar 2015" at the demos (something, I wouldn't have supported), one day, Peter Samson and Steve Russell went to see "this Norbert thing." – And Peter Samson was quite appalled! Notably, I had unknowingly destroyed all of Peter Samson's contributions to Spacewar: Since this was coded for a standard display, an entire range of the stars of Peter's Expensive Planetarium was missing, and, as it turned out later, the Spacewar 4.8 on-screen scorer was by Peter Samson, as well, who took particular dislike in the version, I had unearthed, and had modified it accordingly to the version, we know today.
The gist of this is that I seem to be in the PDP-1 log, in association with some wonderful words like "bodge" and "bug"… :-)

And this was also the end of Spacewar 2015, as far as the CHM was concerned (which is, as indicated, probably for the better.)

Best,
Norbert

Reply all
Reply to author
Forward
0 new messages