Help with c code (bit reversal)

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.

I believe, its a double name (two persons’ names or maybe a place and a person?) It may be well Dutch. Some systems in the Netherlands were prominent examples (I think). I really have forgotten the name, as it doesn’t turn up often and it’s also, let’s say, “on the outskirts of my expertise.”
(I find it quite difficult to find any references on things like this on the Internet, lately, if you do not know the exact term. I’ll have to look up some old files, where this may be included. I remember a discussion about this, we had on the old G+ Vintage Computing community.)

Is it a nickname? Than it’s not that important. Otherwise it should be easy to find or maybe someone else knows.

The Reverse Assembler worked on Mac (emu on emu).
Output on HiSpeed punch took ~5 seconds
Output on LoSpeed TTY took 5 seconds per instruction/line. So extremely slow.
Mode 1 looks like a disassembly list.
Mode 2 like a run.
The output punch is a sympolic tape for the PAL III assembler and in an unknown binary format.

The decmate-ii rom disassembly is very interesting.
Obviously 8 bits (not bytes) are splitted up onto 2 ROMS
and 2x4 bits on another ROM make 12 bits.
I don’t have 3 ROMs but 8, but I do have 3 RAM chips.

Can anybody explain that, is that plausible in my case and how to easily merge bits from different ROMs?

/ DECODED AND DISASSEMBLED BY CHARLES J. LASNER.

/	LAST EDIT:	02-DEC-1991	02:00:00	CJL

/	MAY BE ASSEMBLED WITH '/J' (PAL8 '/F') SWITCH SET.

/	THIS IS THE CODE  USED  IN  THE DECMATE II PRIMARY CONTROL ROM.  IT RESIDES IN
/	THREE 2716 PACKAGES  KNOWN  AS  E113,  E114, E115.  THE THREE ROMS ARE ENCODED
/	INTO  A 12-BIT IMAGE  OF  AN  ENTIRE  FIELD  IN  THE  PARTICULAR  ORGANIZATION
/	ILLUSTRATED BELOW.  FOR ALL  ROM  CONTENTS:  0.X=BIT X IN THE SPACE 0000-3777,
/	4.X=BIT X IN THE SPACE 4000-7777.

/	E113:	0	1	2	3	4	5	6	7

/	BIT:	0.0	0.1	0.2	0.3	0.4	0.5	0.6	0.7

/	E114:	0	1	2	3	4	5	6	7

/	BIT:	4.0	4.1	4.2	4.3	4.4	4.5	4.6	4.7

/	E115:	0	1	2	3	4	5	6	7

/	BIT:	0.8	4.8	0.9	4.9	0.10	4.10	0.11	4.11

/	THIS IS THE ASSEMBLY OF THE RELEASED ROM SET KNOWN AS 358E2, 359E2, 360E2.

/	WHEN THE DECMATE II IS FIRST POWERED UP, ROM CONTROL IS ENABLED FOR ALL DIRECT
/	(IF)  AND  INDIRECT  (DF)  REFERENCES  TO CP MEMORY, THUS THE  CPU  STARTS  AT
/	ROM-BASED ADDRESS CP07777.  THE ROM CODE MOVES A LOADING PROGRAM  TO PAGE ZERO
/	OF  THE CORRESPONDING RAM IN FIELD ZERO OF CP MEMORY, WHICH IS  THEN  STARTED.
/	TO ACCOMPLISH THE INITIAL MOVE OF THE LOADER, THE DF CONTROL IS CHANGED TO RAM
/	WHILE RETAINING IF CONTROL IN THE ROM.

/	THE LOADER MOVES THE BULK OF THE ROM CODE TO CP FIELD SEVEN AND THEN STARTS IT
/	THERE.  ...

The full disassembly is here, but it’s very long. Well documented, but some few parts are assumptions.

By coincidence I found that there’s a new version of the Mac emu (but I think only for MacOSX, so I can’t use it) which doesn’t need conversion for DECtape.
I found again the 2/3 encoding (I mentioned before) which should be the most common encoding for BIN files (but mainly used by OS/8). Probably it’s the same as the encoding above, 3 bytes are written in 2 words

aaaaaaaa          ccccaaaaaaaa
bbbbbbbb          CCCCbbbbbbbb
ccccCCCC

I think it’s mainly used on text files. Maybe only on some ROMs or ROM sections (after the empty bytes ?)
The only notable external tool is PUTR (DOS only). That should be able to convert an ASCII file this way. I’ve tried it yesterday, the result was not as expected. I think the input file was not plain ASCII and maybe I’ve chosen a wrong disk format or switch.
Input 023 0750 30 077 , output 0.2. .0.5. .3.0.0.7. .0.3. .2.3.0.
I would need it to be converted the other way anyway.

I have to try more software on PDP8 paper tape or even PDP11 emulators/tools.
I also found a PDF with another ASCII table.
‘A’ should be octal 0104, B 0204… , 0= 0003, 1= 0103.
The PDP-10 should have a slightly other encoding.

DECtape has another encoding 11:1

Have a look at this example from the manual for the PAL-D assembler for the PDP-8:

Mind the note on the 6-bit trim here:

(Source: http://www.bitsavers.org/pdf/dec/pdp8/software/DEC-08-ASAB-D_PAL-D_ProgRef.pdf)

The character encoding is the same for PAL-D and FORTRAN on the PDP-8:

Mind that there are really just a few collisions with the 6-bit trim applied (namely with characters at the end of this table, starting with “@”.) “6-bit trim” really means, we ignore the first, leading octal digit.

1 Like

P.S.: Generally, for anything regarding the PDP-8, have a look at the “Small Computer Handbook”:

http://www.bitsavers.org/pdf/dec/pdp8/handbooks/SmallComputerHandbook_1970.pdf

Yes, this is the standard encoding for text, A=1. And usually there’s only one column (last 2 digits of the word). This ASCII representation is displayed on the output of the online emu and I also have added this character set on my conversion table for my hex editor.
I’ve checked this on all my ROM combinations but as I haven’t found any useful text, I want to try other encodings.
My decice can’t display ASCII, except for E, F, _. So this is just for a disassembly export to a printer.

I found a 1998 toolset called dumprest by David Gesswein with c codes for both ways of the 2/3 encoding. Originally, this is for dumping or restoring a td8e tu56 DECtape file via serial port from original hardware.
There are 3 different DECtapes, I assume this is for 12 bit.
I first tried to output that on stdout instead of ttyS17, but that didn’t work.
So I’ve started to change the code.

I want to read 3 bytes and output as 2 words. I use dumptd8e.c
The input file is ‘dat’. (Was a test code as output).
The output file is that, someone enters.
Leader and trailer has to be removed.
The DECtape header byte 1 / block flag must be FE in hex (instead of DECtape\n in ASCII.
After that there has to be the checksum probably before each of the blocks (129 words each) as hex bytes 3 and then 2. The calculation is different than usual. Maybe I have to remove that.
I somehow have to mix both files. Count 128 is the amount of blocks.

file: dump (buffer 200 (serial, amount of bytes? in dec?), tmp 0, later a for loop)

count = -1;
   block = 0;
   byte = 0;
   while(!terminate) {
      c = ser_read(fd,(char *)buf,sizeof(buf));

receive, but reads 2 words, buffer 3, tmp 2, later if and while

count = 128;
   block = 0;
   readsz = 0;
   while(!terminate) {
      if ((rc = fread(temp,2,2,in)) < 2) {

The serial read in c is different than fread (error when replaced: too few arguments to function fread).

Although I have both codes, it’s difficult for a beginner to replace the right stuff.
Snippet 2 has 2 different variables and I have to read 3 bytes instead of 2 words.
Both files have just one file opened and non of them closed, user has to CTR c to stop the serial traffic.
I have to rewrite it from scratch, properly open and close 2 files etc.
Will take many, many hours for a beginner. Not sure if I will be successful.

Hum, if this is just a 7 segment display, the program may use the usual BCD codes for this?

Yes, the display has a BCD encoding (forming one word) but it’s very complicated. 4 Locations, each with a different address, one has 4 digits and can just display octal values. 3 can display decimal and/or octal values, 2 of them can display special characters and 2 other ones work together. There is a table in the manual ,but I assume it’s not stored as table in the ROM.

E9 7777
*F9 999

I also mentioned that on my other thread
Help reading EPROM (Intersil IM6654A) and analyze firmware - #4 by mainframetom
A new fact is that the 3 digit decimal position in fact holds a value of 4 digits.

I can only read and write to the display of the attached PLC CPU card (which has the same style) so at least the addresses are different.

But I’m mainly searching for the mnemonics, being printed out. If I found these, I will be sure to have the correct ROM merging and then also the right PDP code.

I think, I even have found the location at 2000o the 3 character words are surrounded by @, but the 3 characters are wrong. DIV sounds plausible but isn’t a mnemonic. The @ seems correct.
So either another encoding or even encryption. I’ll now try to write the c code for the 2/3 encoding. I would need a program, searching for text while scrambling bits and bytes in all possible combinations.