IBM 1410 FPGA: Wrong Wrong Length Record

The vast majority of errors noted by the tape diagnostic T020C related to wrong length record errors, particularly when a tape operation writes from the last character of storage (39999 in my current 40K implementation), usually starting at location 39990.

The current FPGA from the ALDs implementation does not create an error stop, it simply writes until it has written the character at location 39998 and stops, with a wrong length record (WLR) error – with one less character written than the diagnostic would expect, as well. (Then, subsequently, the read operations in the tests also generate WLR because they are expecting 10 characters, but only get 9).

Part of the problem is that various documents describe what should happen in such a case differently:

Diagnostic T020C (1964):

  • The diagnostics do not expect an WLR when writing from the last location in core storage or reading into the last location in core storage. (A WLR would presumably occur when reading into the last location of core storage if the record extends beyond that character.)

A22-0526 (no suffix) 1963

  • Addressing: During execution of an instruction, no address must be decremented past 00000 or incremented past the highest valid address. This includes operations that act on data in a single position only; such operations will be executed but, after the operation the associated address register will contain an address beyond one of the limits and the system will stop and signal an error.
  • Tape: WLR is never set on a Write or Unit control operation, unless the record is of zero length, i.e. the character at the start is a Group Mark with a Word Mark.
  • Tape: Read to End of Core ($): Reads until the last storage position is filled.
  • Tape: Write to End of Core (X): Writes until the last storage position is encountered. [ed: to me this is a little vague: does it mean that the last character storage position is written from, or not?]
  • Console I/O: WLR is never set (I have not yet tested this)

A22-0526-3 (1961) and A22-0526-2

  • Addressing: If an operation increments addresses, 59998 is the highest position (assuming a 60K system) that can be referenced or in which data can be read or inserted as the result of an instruction. If 59999 is addressed in an incrementing operation, the system will stop and signal an address check. There are two exceptions: 1. A manual console operation; that is display and alter. 2. Data may be read from or inserted into 59999 without causing an address check in the execution of a read or write “to end of core” I/O instruction.
  • Tape: WLR (W-U) Never set (unless record is of zero length and first character written is GM/WM)
  • Tape: Read to End of Core ($) and Write to End of Core (X): read/written until the last core-storage position is encountered. (Notice that this older document does not specifically differentiate between the read and write behaviors)

The ALDs for my machine in these areas are all dated 1962.

Because this issue is unlikely to cause operational issues, I expect to “table” it for now and revisit it later. It may be that ECOs were required to change the behavior to what is expected in the diagnostic.

UPDATE: This turned out to be very easy to fix. At first I tried all sorts of things to try and control the setting of the Internal End of Transfer Latch by inhibiting setting that when the channel Wrap Condition was asserted — but that led to an address check as the 1411 CPU tried to fetch the next higher location, instead of wrapping around to location 0.

So then I decided that I would just make a change to the ALDs on pages 13.71.05.1 (E Channel) and 13.66.09.1 (F Channel) to suppress the MC_DISCONNECT_CALL to the TAU while the E2/F2 register was still full. That worked — even better than I expected. Not only did that cause it to write out the last location of memory, it also caused the Wrong Length Record status to go away as well.

That left me with ONLY ERROR 17 on the E channel. The F Channel had ERROR 17, but also errors 20, 23 and 70, which seemed odd. But otherwise, both channels read and write tape just fine.

Error 20 occurs when a tape mark is read, and the diagnostic expects that the CPU will also set the CONDITION status for the I/O operation, but it was not setting the CONDITION status.

IBM 1410 FPGA: From USB Serial to UDP over Ethernet

Seeing that some of the problems that I had identified with the Tape Adapter Unit (TAU) implementation could be or might be traceable back to the fact that I was using a 115,200 bps serial over USB to communicate between the 1410 FPGA implementation and the PC side support program, I decided to look at alternatives.

  • I2C would be too slow, and I would need some kind of intermediary like a PIC or Raspberry PI to talk I2C and then something else, like TCP/IP or UDP to talk to the PC side.
  • SPI, at 10Mbps would probably be fast enough, but also would need an intermediary.
  • I could use an embedded soft processor, like a MicroBlaze, on the FPGA. That would probably work, but would take up a lot of resources on the FPGA, and I was concerned that the Xilinx XC7A100T might not have enough for all of the things I might want to do, especially with a TCP or UDP stack added in. I did do a little playing with Microblaze a few years back, and found the development process somewhat cumbersome: it would considerably lengthen all of the place and route everytime I made a change.
  • Understandably there do not seem to be any direct TCP implementations in VHDL or Verilog that I could find.
  • I found three different implementations of UDP, two in VHDL and one in Verilog that I decided to test.

Two of the UDP implementations were on opencores.org. They were old, apparently done as a research project, and it was not apparent how to configure it to work on my hardware, so I quickly abandoned those. Plus, it took opencores.org three months to grant my request for a user ID.

Next I looked at the UDP implementation from Alex Forencich. At the time, it was located at https://github.com/alexforencich/verilog-ethernet, however, that one has apparently been superceded by one at https://github.com/fpganinja/taxi — however this latter one seems to no longer include a UDP stack. This UDP implementation looked promising, however there were a couple of issues for me. Firstly, it used a generation process using cocotb. When I tried to do that, it did not work well for me. So, I ended up doing what it would have done to figure out what files I actually needed.

The second issue with this UDP implementation from Alex Forencich was that it was not directly complatible with the physical ethernet interface (PHY) on my Nexys4 development board. It is set up to interface with an MII layer, however, my Nexys4 PHY uses an RMII layer. I tried a couple of approaches to resolve this issue. The first was to see if the Ethernet MAC at https://github.com/chasep255/Nexys-4-DDR-Ethernet-Mac would work. It provides an AXI interface to the Ethernet MAC on the Nexys4 board, but also uses RMII. There was something important I cleaned from this latter project however: how to build a test bench to send and receive Ethernet packets, which I used quite a bit.

In the end I found a free MII to RMII v2.0 interface layer IP from Xilinx. While not available in the latest versions of Vivado, it was still there in my older versions of Vivado, and while not supported by Xilinx, it works fine in Vivado 2023.1, and I would expect it will continue to function OK in later releases as well. And, worst case I could also do a development board upgrade to something that has an Ethernet interface using MII.

It took me quite a bit of futzing around to get Alex Forencich’s UDP layer working as it was in Verilog, and I need to interface to it with VHDL. Also, the example/sample logic just does a UDP echo, and it took some time and testing to figure out how to separate out sending and receiving UDP packets.

Once I had it working, it was not tremendously difficult to integrate it into my 1410 FPGA logic. I chose to continue to use a stream UART-like interface that is as close as possible to what I had for an actual UART, so that only minimal changes were required in my existing state machines. I did need to expand the intermediary output related FIFOs from 8 bits to 9 in the logic, however, to carry a “flush flag” so that, for example, when the 1410 needed to send a UDP request for a tape operation, it could force the UDP layer to send the packet even though it was not full. Everything else remained essentially the same as when I was using a serial port.

I now use the UDP implementation for TAU related packets going both ways, to and from the FPGA, for lamp data going from the FPGA to the PC and for sending memory images (“core loads”) from the PC to the FPGA. I did find that I have to throttle the lamps some and not update them as fast as I’d like – the speed of the C# code and Windows updates are a limiting factor. I even found that on tape writes I had to add what kind of corresponds to a tape stop in the inter-record gap, to add a delay when writing so that it does not overwhelm the PC (which leads to lost packet(s) and a program error). I also added some delay when the PC is sending data back to the FPGA for tape reads so that it does not overwhelm the FPGA UDP stack.

With those changes, it can now reliable write and read tape records, though some tape related problems when running diagnostic T020 remain unchanged:

  • Error 17, caused by a test of the ability to do an erase operation to write a long interrecord gap over a bad stretch of tape.
  • Errors 39, 41 and tape I/O operations resulting in Wrong Length Record Status. The problem relates to what happens when writing a record that goes to the end of core storage (with no Group Mark + Word Mark) and reading records that go to the end of core storage.
  • In one of the later tests a read tape to end of core is executed, in odd parity. The tape data is in odd parity as well. However, the operation generates a data check, and core storage from 39990 to 39998 (for a 9 character record) are all asterisks from what the 1410 sees as an invalid parity.
  • On Channel 2 / F Channel, errors 20, 23 and 70 which seem to relate to problems when a tape mark is encountered after writing one and backspacing over it.
  • T020 starts by trying an overlapped write on each tape drive. If it finds one that is ready, the result is a 1410 error stop, I think on an “R” I/O status branch instruction, with only 1 byte transferred to the PC.

IBM 1410 FPGA: TAU Not So Fast

In May of 2024, I turned my attention to Tape I/O. On a real IBM 1410, this I/O would be routed through an IBM 1414 I/O Synchronizer (Model 1, 2 or 7, also known as Tape Adapter Units (TAUs). However, there were two issues with that for me. Firstly, I do not have ALDs for the TAU. Secondly, because the TAU expects to interface with a real tape drive, and I don’t have any, the timing would not work. Fortunately I soon discovered that the IBM 1410 channels don’t actually care about the timing – they are driven by the MC_TAPE_READ_STROBE and MC_TAPE_WRITE_STROBE signals from the TAU.

It took me from mid May 2024 to mid July 2024 to design the logic, test, and work out bugs to the point where I could load diagnostics from the diagnostic tape and they would run. This was a significant milesone!

Testing revealed several problems when running the first tape diagnostic, TU20:

  • Error 17. This error happens because my setup ignores erase requests which write long inter record gaps (IRGs), and the diagnostic expects to see different times (measured in a timing loop) when reading a record with a normal IRG vs. one after an erase with a long IRG. This is not a “real problem”.
  • Many errors displayed for reads and writes which involve the end of memory. The writes write records only through location 39998 before an internal and of transfer stops the transfer, and then the reads aren’t as long as expected, either.
  • Errors 39 and 41, which involve writes which try to read one character past the end of memory.
  • Problems with data transfer between the FPGA and the CPU using the serial port. There seemed to be data being lost during the lasts tests where 1000 records are written and read back twice causing the diagnostic to fail. This created a “crisis of confidence” of sorts – I need reads and writes to be reliable.
  • Data transfer between the FPGA and the CPU was much much slower than on a real machine – intolerably so – essentially a “non starter” with respect to much further progress.
  • The copy of T020 that is on the tape is set up to assume that the machine has overlapped I/O. Unfortunately, because of a bug in the FPGA of an unknown origin, the 1410 hits an error stop. This requires resetting the machine, changing the “TAD” at location 1004 to a 1 to suppress testing the 2nd channel, and then restarting at location 2000.

Not having confidence in reading and writing, and with the slowness of PC <-> FPGA transfers was a big concern. So, in August 2024 I began researching to see how I might use Ethernet instead of the 115,200 bps serial over USB that I had been using. That is the subject of the next post!