Help with c code (bit reversal)

The SBC6120 (I have one, or at least, the newer SBC6120-RBC edition) uses a slightly unusual hack to map the PDP-8’s 12-byte word into two octets (8-bit bytes). I thought it packed all the bits into the lower 12 bits of the 16-bit word, leaving the upper four bits unused. pdp2hex suggests that it stores 6 bits per octet. However it’s done, the GALs on the board decode the data into the format that the Intersil processor likes.

As to the pdp2hex code, I couldn’t get it to compile even with -std=gnu89. It’s very MSVC / DOS-centric code. As the old (unhelpful) joke says, if I were trying to get there, I wouldn’t start from here.

There may be arcane ways to do this involving xxd (which can dump bytes to binary digits) and rev (which reverses lines of text). The great thing about PDP-8 binaries is that they are quite small, so even the most heinous shell script won’t take any time to process them.

1 Like

In another SBC tool called bindump there’s a detailed description.

A papertape is only 8 bits wide and the 12-bit word is splitted up into 2 “frames”
The upper two bits of the first frame aren’t empty but describe the frame.
Frame type 0+1 (address) are normal 12 bits.
Frame type 2 leader trailer
Frame type 3 field settings.
Most tapes have only one segment .

<leader> <data> <trailer> <EOT>

but a few (e.g. FOCAL69 with the INIT segment) are
<leader> <data-1> <trailer-1>/<leader-2> <data-2> ... <trailer-n> <EOT>

I think I read about that on DEC manuals, too.
There are 3 different paper tape formats BIN, RIM and ASCII (all 8 ch.).
On emulators, the papertape BIN format is probably the most common one used (for single files). Leader and trailer with 16x80h and includes a checksum. I did it that way.
I think the SBC mainly or only uses disk images.

I don’t know all BASIC dialects and maybe there are issues with file import, RAM space etc.
Luckily, the pdp2hex works on win 32bit. I will tomorrow try to write as BIN.

I will tomorrow try to rewrite it as BIN

What is “BIN”?

It’s a DEC PDP/8 paper tape format.

-Gordon

Got it. Thanks Gordon.

I think BIN is here plain binary, to write to an EPROM, as not having leader and trailer.
I managed to reverse the bits with pdp2hex. I tried all my ROM combinations.
An 8K file was outputted as 2 files, surprisingly each 32 KB with large gaps (different on some files and different amount of bytes, Some might be lost, illegal instructions?).
Then I have merged the 2 output files, needs word merging and low bytes first. Originally I assumed byte merging and high byte first.
I then have read the files on a hexeditor with my predefined, selfmade character sets found on different sites, mainly wiki, to obtain different sixbit encodings.

Very exciting when first opening a file and convert it.

The first ~2 files mainly showed numbers instead of characters, what was new. Also interesting.

Then I had a very good feeling, just when watching a new design of the character output. It’s different if you have spaces, @, lowercase characters etc.
I found 1 or 2 strings like MAY, but obviously just a coincidence.
I have ~8 files and ~8 different character sets. Very time consuming to check thousands of bytes for a 3 character mnemonic which could be aligned in any direction incl vertically.
Then I found many 3 character words next each other, separated with spaces looking like mnemonics, but didn’t make sense.

On one file (one of my recent combinations, 2 pairs of 4 ROMs, byte merged, I found many strings and values, that can’t be coincidence:

_TEST, $GET, UHR (German for clock, it’ a German device), CAL (calendar or calculator?), TEX", <FLD<, K5=SUM, TYP, UPD, CRC, c@B@D@@@A (display ?), and the like. Unfortunately, my device doesn’t show texts in the display except E and F.
The beginning AC2/7FF (as text) could be a checksum. At the end also CR$ and LO and some bytes.

But most of interest again mainly 3 character strings next each other, this time making sense, but not my mnemonics.

PLU (plus), DUP, LFT (left), DIV, KIT, TMP, I N T, and several more.

I still have to do more research and check for PDP-8 code and text in 2 columns.

I have powered up my device with the EPROM board removed to check if the single EPROM puts out an error message, but there was just garbage. So obviously the 6100 code is on the 8 ROMs, as recently assumed due to the memory size and location.
But I assume most contents to be data. Maybe 90%?
The device has its own instructions, up to 14 bits. The main purpose is that one can enter lines of code. Although not executing these instructions itself, it can check for syntax or other errors or wrong values. It also accepts input as decimal and converts them to octal.
I also wonder why there are 2 different styles of EPROMs. I think the Intersil EPROM can directly read/write 12 bit words? At least completely different to program and also accessed within the device.

For more info about the device and my earlier attempts read this thread

The final ROM with the many strings (bit reversed) turned out to have the most plausible PDP-8 code. The problem is, almost no instruction is really illegal and so accepted. Someone has really check all PC and register contents. The strings are correct in emulators, too.
I did it with the file with the empty bytes removed. And then also want to try it with these bytes remained.

But I did some mistakes.
I wondered why the disassembly goes only up to 7577.
Most notably, I replaced the empty bytes (FFFF, not accepted) with NOPs (70 00) and inserted them as hex bytes instead of an octal word.
And by mistake I had reversed all bits again.

-I have one file mistitled, but it wasn’t correct anyway.
-pdp2hex needs as input file the bin file (with leader and trailer) but in 8.3 file format. I think uppercase characters and suffix .BN
-the output files must be in 8.3 style, too, otherwise some files were overwritten and there’s just 1 file instead of 2.

After pdp2hex and merging, a leader and trailer must be added and the checksum again corrected.
I used 3 computer systems. Win 32 bit, 64 bit and linux.

The empty bytes section (in the merged file now just 1 section) starting at 6000-6077 octal. I think a RAM section. So makes sense to be empty.

I also tried my recent file without bit reversal with the fixed NOPs. Both, starting at 0 and 200, has no plausible code like disk i/o.
I have checked my 2 earliest ROM combinations, too. Both files running soon into the empty bytes section. One did a HLT a bit earlier.
My second file, and the first byte merged one, is interesting. Directly after the empty bytes, there’s a loop of reading at 2000. Exactly where the 3 character words looking like mnemonics are located. Needs a further look and longer run.

Emulator WINEIGHT was not much of use on my recent files. Didn’t know many special instructions (incl 6120 mode). The MacOS emu has some more, like 7755, a combined instruction, elsewhere illegal. So I have to check all emulators. Best is still the commandline pdp8emu.

Here’s the beginning of a trace run with pdp8emu. The first words (at least 10-17, maybe 0-177) are auto indexing values, mainly jump addresses (+1) and not instructions. On left the PC, comments by pdp8emu

[0000] IRQ,DLY,IE=0,1,0 L/AC:0/0000 MQ:0000 IR:0103 AND 0103   ;AND operand with AC, ZP 0103
[0001] IRQ,DLY,IE=0,1,0 L/AC:0/0000 MQ:0000 IR:6257            ;
[0002] IRQ,DLY,IE=0,1,0 L/AC:0/0000 MQ:0000 IR:6706 LFGR       ;TM8-E: Load Function Register
[0003] IRQ,DLY,IE=0,1,0 L/AC:0/0000 MQ:0000 IR:0677 AND I @@77 ;AND operand with AC, Indexed Current page @@77
[0004] IRQ,DLY,IE=0,1,0 L/AC:0/0000 MQ:0000 IR:4601 JMS I @@01 ;Jump to subroutine Indexed Current page @@01
[6260] IRQ,DLY,IE=0,0,0 L/AC:0/0000 MQ:0000 IR:1564 TAD I 0164 ;Add operand to AC, Indexed ZP 0164
[6261] IRQ,DLY,IE=0,0,0 L/AC:0/4104 MQ:0000 IR:7303 CLL CLA IAC BSW;Clear L, set AC to 0100
[6262] IRQ,DLY,IE=0,0,0 L/AC:0/0100 MQ:0000 IR:1725 TAD I @@25 ;Add operand to AC, Indexed Current page @@25
[6263] IRQ,DLY,IE=0,0,0 L/AC:0/3010 MQ:0000 IR:0535 AND I 0135 ;AND operand with AC, Indexed ZP 0135
[6264] IRQ,DLY,IE=0,0,0 L/AC:0/0010 MQ:0000 IR:6437 SRCD       ;DP8-EAEB: Read Character Detected
..
[6270] IRQ,DLY,IE=0,0,0 L/AC:0/6317 MQ:0000 IR:6425 SGTT       ;DP8-EAEB: Transmit Go
..
[4621] IRQ,DLY,IE=0,0,0 L/AC:0/0000 MQ:0000 IR:6777 SDRD0      ;TD8-E: Load Data Register into AC, Unit 0
..
[0114] IRQ,DLY,IE=0,0,0 L/AC:0/0000 MQ:0000 IR:6200            ;
[0115] IRQ,DLY,IE=0,0,0 L/AC:0/0000 MQ:0000 IR:0113 AND 0113   ;AND operand with AC, ZP 0113
[0116] IRQ,DLY,IE=0,0,0 L/AC:0/0000 MQ:0000 IR:7755 UNKNOWN!   ;**Unknown**
..
[0106] IRQ,DLY,IE=0,0,0 L/AC:0/0000 MQ:0000 IR:6635 RCNO       ;CR8-E: Read Conditions out to Card Reader
..
[0112] IRQ,DLY,IE=0,0,0 L/AC:0/0000 MQ:0000 IR:7700 SMA CLA    ;Skip on AC < 0, Clear AC

following a long loop, probably waiting for input (key or import ?)

Instructions starting with 6 are for external communication (IOT, some aren’t included in many tools/emu, especially for the 6100, same for WINEIGHT)
Instructions starting with 7 are main instructions mainly to work with the values of the AC and MQ registers. As there are many combinations, not all are implemented everywhere.

0: 0103 is probably a jump address, also after an IRQ.
1: 6257+1=6260 is a jump address called at PC 4. The emu is running over it.
2: 6706, TM8-E is the magnetic tape
6261: A combined instruction including BSW = Byteswap =reversing the 6 bits. So at least here are bits reversed. Maybe just for strings, tables etc? As everything is already reversed, some parts are reversed to normal again?
6264: DP8-EAEB is the TTY full duplex communication.
0106: I don’t have a card reader, might be a different 6120 device?

Maybe I’m completely wrong, but it’s surprising that the bit reversal makes so much sense. First, the longer plausible strings. And now also instructions, locations etc.

1 Like

In a PDP/8 the upper words of core are used for the bootloaders. The disk one can start at 7600, so ending an image at 7577 (ie 7600-1) may be prudent if you want to keep the disk bootstrap code in core.

-Gordon

I don’t know about the exact (memory) configuration of my device (how do I find out?).
I have 8 KB ROMs (0-7777) Is 7600 of ROM location the same as RAM location? Relocation is always possible.
My device is not a PDP/8, doesn’t have any disks and no OS/8. 768 words of (buffer) RAM, next to the RAM cartridge.
The remaining 200 words is exactly the amount of empty bytes at 6000-6177.
When having illegal instructions there, a disassembler doesn’t accept them but I think continues with the upcoming words and so the file is too short.
After having replaced the correct NOPs, the disassembler puts out the full amount of ROM code 7777.

Not sure about other stuff like checksums. The device can read out the checksum of the attached PLC, not sure about its own. At least it handles error codes on both.
The PLC has code of it own. Maybe the RAM cartridge as well. Up to 4 RAM/EPROM cartridges can be combined (in the PLC) with jumpers.
Btw, the PLC can handle up to 512 i/o cards with 8 or 16 bits, also combined. These are identified with plastic coding plugs.

8 KB papertape for code is very long. Usually these are much shorter and don’t reach into those locations. Maybe it’s even handled as disk image or else, but I don’t think so. Probably no header.

My experience is with a real PDP-8/a which had 16KW (words of 12 bits) or core memory and writing my own emulator to run inside the PiDP8 device…

There is no MMU and the PDP-8 has a 12-bit address bus plus a 3-bit extension register to allow it to address 8 banks of 4KW or 32KW of core.

So ROMs may be 8-bits wide but each one only using 6 bits, so 2 ROMs side-by side to make up the 12-bits?

8K is 0x4000 in hex or 020000 in Octal, so that’s 2 fields of 4KW - quite a large ROM, but 8KW programs were not unusual - I have ran DECs “8K BASIC” on my units which feature floating point support. (I loaded it from ‘tape’ which was a disc image of the tape I sent via the serial port into a real PDP/8… But even that tape image had a hole which preserved the bootstrap region. BIN format tapes have an address then data,data,data, etc. then address, … and the BIN loader works out when a tape byte is a address or data byte (or end) and does the appropriate thing.

-Gordon

1 Like

Thanks Gordon! My device obviously has a different setup. I have to read again docs about the PidP8 and 6100.
And about a BIN/RIM reader. If included on the 6100 or maybe on the 9th ROM. Maybe my file is not in BIN papertape format.
My file is 8 KB (not KW) and so is 2000h. With leader and trailer 2024h.

I did again mistakes.

When replacing the empty bytes with NOPs on my first 2 files, I only did that on one of the two sections each, as these are separated unlike the 4+4 merged file.

Even worse, on my very first file (ROMs 1-8) I missed, I think 60 bytes somewhere in the middle of ROM 1. So almost everything was wrong. I don’t know how this could happen. Luckily, all my later combinations have the correct length, except one.

After having fixed my files with the correct octal NOPs and length, I have checked 4 files again on all emulators/tools and also did the bit reversal. My first file missed 256 words at the end after bit reversal. So I removed these and inserted both NOP section at their correct locations.

My 2nd file runs into the empty bytes section. Both when starting at 0 or 200. So this is definitely wrong (except if this is intended, the section later overwritten on a run or when starting at a different address). On a real PDP-8, the address (and loader) would be toggled in. The reset vector is (usually) at 7777.

The 2 recent word merged and bit reversed files (and file 1) have interesting runs. At PC 0 there’s directly an indexed jump instruction, so not running over the code that aren’t instructions but index variables. And the other code also looks very plausible with some new IOTs obviously for TTY and tape i/o.

The first file with and without bit reversal is now again plausible. Both strange, the bit reversal and the file with 2 empty sections.
I still have to search for characters and data sections.

Reading more about the 6100 CPU, I found that at word 5, 6 and 20-77 these RAM locations are reserved for debugging (ODT) which is hardwired.
Most files (except the one with bit reversal) running into these locations (5,6) at least when starting at 0.

There is no reset vector as such, although some models have a small ROM on-board and an auto-boot facility.

To boot a PDP-8 from “cold”, you’d key in a small bootloader at 7756 - this is the RIM loader, then run that from 7756 and load in the BIN bootloader via tape. The BIN loader typically lives from 7645 and puts a jump instruction at 7777 to it’s start, so it’s easy to use.

All being in magmatic core it stays there unless overwritten, so for the most part, keying in 7777, LoadAddress, Init, Run was the way to load in new tapes.

Tapes are 8-bit format. The RIM and BIN loaders read 2 bytes to assemble a 12-bit word (data or address, depending on the top-bit)

-Gordon

Mystery of empty bytes section solved (I guess).

I have 8 ROMs. 1KByte each, makes 2000h =1000 words (7777o).
As said and shown on photos, I have 3 RAM chips, 256 words each=768 words.
256 missing words are exactly the amount of the empty bytes.
I can’t have a memory location of 7777 with that few RAM but 7577.
I still wonder why there are 2 empty sections and not just one at the end.

Not sure if the complete ROM is copied into RAM (all at once).
Also still unclear the 9th undumped ROM which I think is labeled ROM 0 (hard to read).
And that is the only one organized as words. It’s possible that that has the only PDP8 code
and the other ROMs just data. But the location on a different board would be weird.
I assume that that is for interaction with the PLC or maybe has checksums, or ASCII conversion or else.
It’s also possible that only one (or 2 or 4) ROM has code. At least one has to have code.

So instead of inserting NOPs, I have to remove all of them.
I have to check all my combinations again.

Another possibility: Paper tapes have 8 channels and I have 8 ROMs. Maybe one channel/bit or word is splitted up onto each ROM?
I found similar on a disassembly of the decmate II ROM.

The binloader should reside at 7625 (not 7645). But on my case it should be elsewhere. I haven’t found any contents of BIN/RIM loaders. I haven’t checked the HiSpeed loader.
I also have to search for checksums.

If you have the code to implement your function, converting that to a lookup table is trivial, and chances are the table will be smaller than the code, especially if you restrict it to 6 bits and handle the other two separately, eg return (n&0xC0)|rev6[n&0x3F];

I guess, everyone has a comfort zone, esp. when it comes to doing something “brute force” in an unfamiliar and poorly understood language.
Mind that

 (n&0xC0)|rev6[n&0x3F]

is quite a complex expression, if you’re not familiar with C or similar languages.

Personally, I’m feeling comfortable with a loop.
E.g. (use any type you want, here using int for generality),

int rvsOctet(int x) {
    int r = 0;
    int i;
    for (i = 0; i < 8; i++) {
        if (x & (1 << i)) r |= 1 << (7-i);
    }
    return r;
}

I also considered asking ChatGPT. But I think it would take many many more years for a KI to be helpful to all the problems. Currently just fed by the web.

I found some tools in hexeditor Okteta. Also including bit reversal. But no plausible code either.

I have read again the manuals of my device and found some new facts.

-The default size of the RAM card, even of the PLC is just 256 words.
So I have 8+1 ROMs and 2 different kinds of RAM on both devices each. The on-board RAM might just be a buffer. And the card on my device acts more like a disk.
The main system ROM and RAM is that of the PLC. I have more details, and my device has more control about that, than on its own (eg registers, display).
-There’s a regularly signal interaction when attached to the PLC (triggered by that) to make sure it’s still attached. Resides at 7700-7777 (on PLC?). Maybe the 9th ROM has something to do with that.
-There are 2 functions to search the written code on the RAM cartrige for address instructions and for a specific functional unit. That works without a PLC, but needs a cartridge and a TTY attached.

As my device has a syntax check and can disassemble, the mnemonics must be stored and their condition codes. The longest one is SONST and must be stored somewhere somehow.

The PDP8 CPUs have to simulate the instructions of the PLC (at least on that). I now focus on those instructions and on the function my device has. Registers are maybe just on the PLC.

The Festo instructions are very simple and these are stored as 6 digit commands. And stored/displayed reversed. But not sure how and where these are stored in PDP8 style.

654321
xyabcd

.WENN ESB FEL  (Wenn Eins-Signal an Fehler)
0      1  0077
 DANN LOE ANZ  (dann lösche Anzeige) 
0      2  0050

This is a typical set of 2 commands. If signal 1 at error flag, then delete display (of the PLC).
The digit on the left can be bit 0 or 1. 1 eqals the keys Außerdem and sonst (furthermore, else).
Digit 5 is the instruction 0-7. (0 signal, 1 signal, delete, set, load, with content, with address, as decimal). The other 4 digits are either a functional unit, an address or decimal value.
An if condition can, I think just read a 0/1 signal from different units. The longest command has 4 mnemonics but still 6 digits

;WENN ...       (furthermore, if)
1
 DANN LAD ZAL 07  ;then load counter #7
0      4   3  007
      MDZ     123  ;with decimal 123 (converted to octal)
0      7      0173
      MIV     ZSK  ;with 0.1 sec clock 
0      5      0031

There must be a conversion routine somewhere. The display can show decimal and octal values + E, F, _ etc encoded as 8 bit BCD 2/3/3 bits. In the manual there’s a table, but I think it’s not stored as table.
And what about condition codes? The only allowed instruction with the display is delete.

How is all this usually stored on other computers? Any other suggestions how to go further? I’m still stuck on the right ROM merging. The PLC has 4 pairs of 2.

This looks much like a microded instruction set.
I.e., we have an istruction “LAD” and the first octal digit of the operand specifies a mode, here “3” for a counter, the rest of the oprand specifies the source/target (counter 7). Mind that digit posions may matter, e.g., there are only 7 counters and they are always given in the last digit, but for code “4” (in place of “LAD” = 7), the argument would always be in the second-last digit, etc. (Expect binary patterns for microcodes, they may be well be allowed to be combined into a single instruction for a respective group. Hence dedicated digits for arguments.)

Regarding conditions, I do not see a clear pattern in your examples. (Is it “0” for a first “WENN” [if] and “1” for “;WENN” [else if] – possibly with further increments –, followed by any number of “DANN” [then]instructions prefixed by “0”? But how do we switch back to a new, first “WENN”?)

Instruction registers are usually on a CPU, but the 6100 has only it’s own one.
Strange, that an instruction consisting of 1 bit+1Byte+1 octal word. When storing as words it has to be 2 words.

Counters have a maximum of 77 (octal). These are 3 digit decimal counters stored at 30xx-3077 running up or down (can be changed).
But I think the last 4 digits are stored as one word (in order, reversed) as it also can be an address or even decimal values (stored as octal).

The question about the conditions is a good question as both .WENN and DANN starting with 0. And you can add any number of instructions. You can also use OR and (neg) brackets (which have one fixed instruction each). Otherwise it’s an ‘and’.
Else is SONST, and starts with 1, same as ;WENN (furthermore).
Each line of SONST also starts with an 1. And when there’s a 0 you have a new .WENN instruction.
I think it also depends on the instruction. A …(then) delete display can’t be an if condition, so has to be then. You can’t just delete the display but need an if condition first.
Reading for a 0 or 1 signal can just be an if condition. The rest is 0 then or 1 else. If there’s an if condition with 1, then it has to be ;WENN.

And of course a user should only enter valid code.
For complicated, nested code and code segments, there are pointers and maybe flags, but all on the PLC.
On conditions without brackets, the device uses the disjunctive normal form.
All code can be drawn as ladder logic.

0 .WENN
0 (and)
010001 or
0 …
0 DANN
1 SONST
1 … (and) still SONST

0 .WENN

I have to carefully check the dec-ii-rom disassembly.

This somewhat reminds of a kind of instruction layout that was somewhat popular on large one-of-a-kind systems in the 1950s (I forgot the name for it), This came with a very stringent and systematic design, where each instruction started with an array of bits, specifiying if it is an condition, what kind of condition it is, if it is negated, what kind of instruction it is, etc (this could be up to 10 bits). This is somewhat like reducing this to the bare minimum, by making it always a condition and having just a bit for the branch, we’re in.

(Zemanek’s “Mailüfterl” would be an example for this, see https://norbertkehrer.github.io/mailuefterl.html.)

I assume that this is the design for all PLCs. Not sure about the recent ones.

I haven’t checked the dec-ii disassembly, yet.
Instead I found a dec papertape called reverse assembler and other tools.
After having loaded this papertape, you can read another one and the result will be printed out.
I couldn’t manage to load both papertapes on the online emulator and don’t know how to enter the settings. I tried to input the 2nd tape as BIN and text file and tried all settings but it won’t read it.
I have to try this on the Mac Emu or SIMH.

I’m interested in the name of those large systems. I only found stored-program computer. Or is it a German term? In Germany they would maybe just titled Rechenmaschine, maybe a patent.