Thursday, April 27, 2023

A bit diverted training for volunteer work with the Cape Canaveral Space Force Museum


Most people think of the Kennedy Space Center in Florida, where the Apollo missions, Space Shuttle launches and many current rockets fly as a single monolith. However, that area is divided into two halves by a geographic boundary. One side is civilian and run by NASA, the other side is run by the US Space Force but also has private space companies operating from there. 

The barrier islands along the east coast of Florida, north of Cocoa Beach, includes the town of Cape Canaveral and north of that has the Cape Canaveral Space Force Station. To the west side of that island is the Banana river, which separate CCSFS from Merritt Island where NASA owns Kennedy Space Center. Merritt Island is in turn separated from the mainland by the Indian river on its west edge and of course the Banana river on the east side. 

NASA currently owns two launch pads from its facility, 39A and 39B, using one for missions such as Artemis and leasing the other to SpaceX. From those two pads they have launched a couple hundred rockets in their history. Cape Canaveral SFS has launched more than 8000 times from its many launch complexes on their side, and also leases some pads to SpaceX, Blue Origin, Relativity and other private firms. 

In addition to testing most of the defense department missile systems over the years, CCSFS supported the US Space Program up until the Saturn V based Apollo missions launched. The first Apollo missions flew from CCSFS, as did all the Mercury and Gemini flights plus the vast majority of all satellites soared from here. 

The museum has one part outside the security gates in the Port Canaveral area, Sands History Center, plus several facilities inside the perimeter. There are few ways to get a tour inside the secured area, but for most of the public, Sands History Center is the portion they see. 

Inside the military controlled area there is our primary museum location at Space Launch Complex 26. This is a blockhouse with two launch pads where the first US satellite, Explorer 1, was launched as well as a number of other missions. We also have an exhibit hall building adjacent. To the south we have SLC 5 & 6 where the first two crewed Mercury flights - Shepard and Grissom - took place. The blockhouse and pads are available for visits.

Quite a few rockets are stored for viewing inside Hangar C, which was in spite of its name the first hangar built on the Cape Canaveral missile range (the first two were at nearby Patrick Space Force Base south of Cocoa Beach). The latest artifact added to the collection is a major portion of the Titan missile that launched Gemini 5 with Gordo Cooper and Pete Conrad in the capsule. 

Just to round out the pads involved in the remainder of the crewed space program: SLC 14 launched the orbital Mercury missions include John Glenn's on an Atlas rocket. SLC 19 launched all of the Gemini missions atop Titan rockets. SLC 34 launched the early Apollo flights atop Saturn 1B boosters, but the only two crewed capsules there were the Apollo 1 team who perished in the fire atop the pad and the Apollo 7 crew. From that point forward activity moved to the Kennedy Space Center side on SLC 39A and 39B. 

After a long wait for a security clearance, I received my badge granting me access to both the Cape Canaveral and Kennedy Space Center. While my primary purpose in volunteering is to do restorations, historical examinations and visitor animations of the equipment in the museum locations, I decided to train for giving tours so that I could pitch in with scheduling pinches and know more about the museum.


Many of the docents leading tours worked for aerospace contractors, served in rocket related activities in the Air Force, or conducted launch activities at the Cape. They have a very strong background in the entire history of the missile programs whereas most of my prior knowledge was only about the crewed programs. 

I have quite a bit of studying to do on the evolution of rocketry, such as the German WWII V2 becoming Redstone, which became Jupiter-C and Juno, and so forth. There is a significant amount of reuse (with improvements) of engines, airframes and a number of competing programs across the various armed forces that I have to understand.

After training as a group, I am now shadowing the docents as they lead live tours for visitors, making sure I am ready to be tested and certified to lead my own tours. Once done, my activities at the CCSFM will be only a few days a month and I can devote the bulk of my time to vintage computer activities. 

Friday, April 21, 2023

Back from trip and cleaning up all the C code to run on the HPS side


Rather than wait until I had tested each chunk of functionality before adding to the code, I decided to work out the final version and write all the code. That includes quite a bit of error checking and recovery logic, in addition to the functions during operation. 

I wrote this in many small modules, which will be easier to debug. It also makes the program easier to read and comprehend. I am going to write some small test driver programs that take each module through its functions. 


I have the battery, buck converters, time relay and other parts needed to install the power circuitry that gives my board time to gracefully shut down, when the IBM 1130 or its power supplies stop supplying power. 


I have drawn the interface, which displays up to 20 file names, each up to 50 characters long, in a list on the screen. Buttons on the right move the cursor up or down the list, causing it to scroll as necessary when the SD Card contains more than 20 Virtual 2315 Cartridge image files. A bottom button selects the file name which is currently pointed to in the list, opens the file and loads it down to the FPGA side of the board. 

When the disk drive spins up and attempts to load the heads down on the cartridge surface, my program switches the FPGA into disk modeling mode, tells the drive electronics that the disk drive is ready for access, and switches the screen to a static picture of a disk cartridge. 

Later, when the operator switches off the drive, the head loading signal (pick) is turned off. My logic then commands the FPGA to go back to user interface mode, unloads the data from the FPGA side and updates the SD Card file image for any changed content. We are back at the starting point where the operator can scroll around to select a new disk cartridge to load into the machine. 


Sunday, April 16, 2023

Finalized and purchased components for supporting time for orderly shutdown of DE10-Nano


I decided that rather than supercapacitors that would get expensive for increasing numbers of seconds feeding 1.5+ amps to the DE10-Nano board, I would use a rechargeable battery system. This will allow me to support longer times if that proves necessary. 


The board I am using will be drawing nearly 2A from the 5V supply at peak times, which will add a noticeable extra load on the IBM 1130 power rail I attach it to. The 12VDC rail I was using only supplies 4A in total and there are demands on that throughout the computer itself. Even with the ratio of 5/12 for current draw, ignoring conversion losses, that would put a bit under 7/8A on the 12V rail, over 20% of the capacity of the supply that I would be adding. 

I therefore switched over to the 48VDC rail, which has more capacity and benefits from the reduction of the draw to a 5/48 ratio or around 1/5th of an Ampere. There will be a DC-DC Buck Converter to drop the voltage to the levels I need for the battery charging and to power the DE10-Nano board itself. 

For convenience in sourcing batteries with the ability to deliver a couple of Amperes for perhaps 10 seconds without damage to the cells, I chose to look for 12V rechargeable batteries as these are widely used in many applications. I only need about 100 mAH (milli Amp Hour) of capacity but to also meet the ability to deliver 1 Ampere without strain I instead will be buying something with single digit AH rating. 

That implies that I have a second DC-DC Buck Converter to take the battery voltage level down to the 5V that the board requires. This is 12V when only the battery is feeding power and rises to 13-14V when the charging circuit from the first converter is active because the 1130 is feeding 48V to us. 

Add in two diodes so that this converter is fed from either the 48V to 13+V converter or the 12V battery pack without back feed to the computer.  The first converter's power is fed to the battery and then diode 1 takes that voltage to the board. The first converter's power is also passed through diode 2 to the board. The second converter does have some voltage drop from the diodes, so we are seeing from perhaps 11.4V to 13.4V depending on whether it is battery only during a power failure or not. 


I chose to use an NPN transistor to pull the user button on the board to ground when the power from the computer is available. The pullup on the button circuit will make that register as digital 1 when the power has failed but 0 while we are driving the transistor from the first converter's 13-14V. 

A subprocess running under my application on the Linux system on the board will be polling that button's state. When it sees a 1, it will inject a command line to an attached shell that shuts down the Linux system gracefully. 

The gate of the transistor is fed from my converter output, before the diode that connects to the DE10-Nano board, so that it is driven while the 48V supply to the converter is active. The collector goes to the user key on the side that connects to the processor and has a pullup resistor. The emitter is hooked to ground. 

Tuesday, April 11, 2023

Planning orderly shutdown at power removal


The SD Card is a disk drive for the Linux system, as well as containing the various cartridge images that can be 'loaded' virtually into the disk drive. At any instant when power might drop, the system or the cartridge image file may have writes in progress such that with an abrupt stop, the state of the file or file system on the SD Card is corrupted. 

We want to protect against that by having all writes complete and the file system be closed out properly. This is done by issuing the shutdown command to a Linux shell prompt, usually via a terminal window. Shutdown -h now requests that Linux ask all tasks to politely but quickly stop, after which the system itself shuts down. 


It will take perhaps one minute for Linux to complete writes to the SD Card, then shut down. I must provide sufficient power to operate at least that long. I plan to install large capacitors that will sustain the supply for that period. 


I decided to hook up to the HPS side User pushbutton as it is a signal that I can poll easily to discover whether a power failure has occurred. A wire tacked to the high side of the physical switch needs to be pulled down to ground when there is no incoming power to the box (before the capacitors). A MOSFET transistor will do the job nicely.

My program will fire off a process that does nothing but loop watching the HPS User Key signal for it to drop to ground. If it does, the process injects the command shutdown -h now to a shell. 


The operator might have flipped the system power switch off, or pulled the emergency power off knob. The building power might go off due to a utility outage or tripping circuit breaker. Internal power supplies in the 1130 might trip their circuit breaker to stop the power delivered to my box. There are multiple possible scenarios but the solution to all is the same - loan temporary power and ask Linux to shut down properly. 

Sunday, April 9, 2023

Restructured the signal connections for the LCD module and the pick/hold to the HPS


The SPI capability in the Hard Processor System (HPS) side of the chip allows me to set any of four signals intended as slave select for the SPI protocol. I had been using the first two slave select lines to activate the LCD panel and touch screen chips respectively. 

Having the other two gives me a simpler way to control two more signals related to the LCD module - the reset line and the command/data signal. I set these to the other two slave select lines. By simply setting or clearing bits in a given location in processor memory, mapped to the SPI master 0 control register SER, lets me turn those two signals on and off.

The backlight wire is simply going to be wired permanently on, thus there remains one pin from the LCD module not yet connected to the HPS side and one other signal that needs to be routed to that same side.  These were connected as interrupt requests 


Having read the example code from Waveshare I see that I could simply poll the interrupt signal from the touch controller instead of setting up an interrupt handler and watch for the flag to be set in my mainline code. I don't really need to be doing anything while the User Interface (UI) is active except waiting for touches on buttons. 

There is a single available GPIO pin natively wired to the HPS side - on the LTC connector. I will hook that to the touch controllers interrupt request pin, then poll it in my loop to decide when there is a touch on a button on my UI. Once the drive is switched on and I have a virtual disk cartridge file activated in the SDRAM, I switch drive_ram on and stop paying attention to the UI. 

This opened up a clever way to make use of one more connection from the SPI logic. The SPI component on the chip is able to jointly control slaves with other SPI masters, making use of a contention signal. That is, if one of the other masters is activating a slave select and switching on its clock, it sends a contention signal that is an input to my SPI master. The master turns off its outputs, thereby allowing the other master to complete its transaction. We will call this SPIM0_ss_in_n and make use of that line.

The final _n in the name indicates it is inverted polarity, thus a 0 on the signal will force our SPI master to disable its outputs while a 1 on the signal allows our master to operate as it wishes. The signal from the disk drive, -pick/hold, is an inverted signal such that when the drive tries to lower the heads onto the platter, the signal switches to a value of 0. 

This fits my needs perfectly. When the drive is not active, -pick/hold is emitting 1, hooked to SPIM0_ss_in_n and that allows the user interface to communicate with the LCD panel and touch screen. Assuming we have selected and loaded a virtual cartridge file, when the -pick/hold signal goes to 0, it also blocks the SPI master. 

We can examine a bit on one of the SPI control registers that indicates we have seen the SPIM0_ss_in_n  signal go to 0 (i.e. -pick/hold went to 0 because the drive spun up and tried to load the heads). If we see that, we send the command to the logic in the Field Programmable Gate Array (FPGA) side of the chip to switch on drive_ram state. 

The result of these actions would be to illuminate the Ready lamp on the disk drive and allow the disk controller in the IBM 1130 to issue disk access commands to the drive. Later, when the drive is switched off by the operator, -pick/hold reverts to 1 and allows the UI to resume operation through signal SPIM0_ss_in_n

With these simplifications, I can drop the use of interrupt request lines and therefore have no need to set up interrupt handlers in Linux for my application. Everything I need to do from the HPS side application is controlled by reading and writing from the memory mapped control registers, accessible in user mode.

Modifying the Waveshare demo code to use for my GUI


When I bought the module that provides the 3" x 5" color LCD screen with its integrated touch system, it came with example code in C and Python for the processor board they designed for, as well as a way to fit it to Arduino. What they developed was very specific to the Pico (and Arduino) but I can modify it to leverage the library code for my user interface.

This code has routines to draw various geometric figures, characters and to identify the location of a touch on the screen. It also provides a routine to calibrate the touch positioning of the screen, saving those values for future use. There is quite a bit I don't need to use as well - drivers for an SD Card device on the module to allow it to display a bitmap image stored on an SD card, with all the FAT file system and other logic required to do that. 


The conversion consists of a few broad categories of work:

  1. Convert the hardware specific access to SPI and the GPIO pins to Cyclone memory mapping
  2. Adjust the header files to match those on the Yocto Linux system
  3. Remove the code that reads the SD Card and displays an image
  4. Resolving any incompatible library or system calls
  5. Integrating the interrupt from the touch device rather than polling as their code does

Saturday, April 8, 2023

Controlling the SPI link on the Cyclone V is fairly different from Arduino, Raspberry Pi and others


Although SPI on all those systems ultimately are controlled by setting bits and values in control registers, plus storing or fetching from other registers, the programmer has handy libraries that simplify this. On the Arduino the object SPISettings will define CPOL, CPHA and the clock rate - as well as what bit order a word is transmitted in. SPI.BeginTransaction() will actually configure and start the link with these settings. 

The Raspberry Pi Pico uses a call to spi_init to set the clock rate and assigned pins (the pins are fixed on the Arduino). spi_set_parameters is the call to control CPOL, CPHA and other parameters. Similar in nature but different from the Arduino. Both of these convert the calls to manipulating bits in control registers. 


The SPI hardware is controlled by hardware registers, much as are the others, but those registers are memory mapped to the 4GB address space such that they are set or read by fetch and store to memory locations. As I determine the frame size, CPOL/CPHA, clock rate and other characteristics, I have to set those bits/values in locations that map to the control registers.

Deviating from the practice of the other systems, where a general purpose IO pin is written to assert or release the 'slave select' line for a given remote destination, on the Cyclone V bits in a control register turn on or off the SS lines. Thus by storing into a memory location I cause the SS line to be controlled. 

The SPI system of the Cyclone V also has support for multiple types of interrupts, DMA operation and other sophistications that I won't need, all of them controlled by writes to the memory mapped control registers. 

Finally, writing from the Cyclone to the LCD module is done by storing data in a memory location. The status location tells me when the transfer is complete and I can pick up the returned word from that same memory location. The actual writing and reading will be very straightforward and clean, once I initialize all the memory locations to appropriate values. 

Crawling through documentation to discover the SPI link settings


The module was built with pins that fit onto a Raspberry Pi Pico board, thus the code examples are built for this. This includes a call to initialize the SPI link (spi_init) which sets the pins wired to the controlled devices, and the clock rate to be used. . 

However, there are important parameters for SPI beyond just the clock rate. The state of the clock when idle (CPOL) and the edge of the clock when the master output should be sampled (CPHA) are essential for successful communication. The size of the data being transmitted in bits is also fairly important. 

These would be defined by a call to set the parameters, but that is not included in the C or Python examples. Thus, these are the defaults that will be taken by the Raspberry Pi Pico and not clearly marked in the code. Since a Cyclone V or any other device may have different defaults, it is sloppy to not assert the choices explicitly. 


I then went to the Software Development Kit (SDK) documentation for the Pico to see what defaults are chosen for the SPI parameters. Not one word about this in the documentation. I know how to set the choices, but not what they are if I don't issue a set command. 


Nothing shipped with the module tells me the clock rate, CPOL, CPHA, bit size or any other factors other than the pins assigned to SCLK, MOSI, MISO and SS. One could always experiment, varying the parameters to see if they work with the module. One could run the example code and use a scope or logic analyzer to figure out the answers. You just can't learn it by reading anything I could find. 


The module maker did offer a wiki with the example code, a schematic for the module and datasheets for the two major chips used - LCD panel driver and touch screen interface. Neither of those chips use SPI protocol, but they were adapted on the module to be compatible. 

The LCD driver has a 16 bit parallel input, so there are four 7400 series chips that shift in the SPI bit stream to create the parallel signals for the LCD chip , as well as toggling everything to lock in the value and trigger the LCD chip. Using the data sheets for the 7400 series chips and the datasheet for the LCD panel driver chip, I determined that the CPHA value is 0 and the CPOL is 0, with a frame size of 16 bits. 

The touch pad interface chip has a clocked serial input that works properly with CPOL/CPHA of 0/0 however I see that the clock rate for talking to the touch pad chip is lower than the clock rate used in the example code for the LCD driver chip. Since my interface will not have rapidly changing output, I will write my code to use 2.5MHz for both, the lower speed I discovered. 


I had assumed that the example code would have instantiated an interrupt handler for the pen touch interrupt that comes from the LCD module, but in looking at the code they simply loop sampling the interrupt pin as if it were a pushbutton. That is an option for me as well. 

The user interface is only active when the drive is not read/in use. At startup or when the drive is off, we can just looping looking at the touch pin and act accordingly to update the UI on the LCD screen. Once the user selects a file, we will be busy for some time while loading the cartridge image into SDRAM by communicating with the FPGA, but generally we are looping.

When we see that the drive has attempted to load heads (pick signal) and we have successfully set up the cartridge image in SDRAM, we turn on the drive_ram signal in the FPGA and no longer need to worry about touch interrupts. When the pick signal turns off we are going to tell the user we are unloading the cartridge, suck the changes back through the FPGA to the image file, and then resume the user interface loop looking for touches. 

Friday, April 7, 2023

Starting to build the user interface code to control the LCD panel and touch screen


The provided examples aren't written for the module I bought, they are for similar modules but with some key differences. For example, the code believes it is controlling the LCD backlight intensity by sending numerical values to a digital to analog converter but my module has a binary control signal with the light either on or off.

I suspect there are going to be other differences as well, some that will need code changes to reflect the actual hardware I am using. The code mentions it is from an epaper demo project, but my device is an LCD panel and touch screen.

The code also assumes it will run on an Arduino or similar microcontroller, with pin assignments and include files for that environment. This too will require some changes to have this compile and run under Yocto Linux on the ARM based Hard Processor System of my board. 


As a result of the above issues, I will write (and debug) my own software to drive the module. The provided code, while not usable, illustrates the exact sequences of commands and data to be sent to the LCD module for various purposes. I can mimic those sequences to produce my desired results. 

Thursday, April 6, 2023

Coded up quite a bit of the Linux app, ignoring the User Interface for now


I created small focused routines for utility functions we need, such as startup and shutdown. One sets up and test the two bridges between the Field Programmable Gate Array (FPGA) with our user logic and this program running on the Hard Processor System (HPS) side of the chip. Another opens a disk file on the SD Card and maps it into virtual memory. There are also closedown versions of these. 


The main program calls the utility routines when necessary and will have comments at the point where routines I will write in the future will be executed. I added a few special tests for the initial board testing, which I will remove, but mainly this is set up with the appropriate code and checks that will be used in production. 


These routines send a command to the FPGA to begin a load or unload operation. These will cause the contents of the virtual 2315 cartridge image, held on a file on SD Card, to be passed through the FPGA to be placed into a reserved 1MB area of RAM. The unload pulls the contents of that area of RAM back and delivers it to our program where we can identify and store any updates. 

I also created a special version of the unload routine which printed any blocks that had changed - the idea behind this is that if I do a load followed by an unload, the data returned should exactly match what was retrieved from the image file during the load. 


I have to set up three interrupt routines. I will receive an interrupt from the LCD module any time the user touches the screen. In addition, as the disk drive controller does a pick, trying to lower the heads onto the disk surface, it will send an interrupt so we know we are ready to switch on the disk emulation in the FPGA - sending the command to switch drive_ram on. The third interrupt arrives when the pick signal is removed, usually because the operator has switched off the disk drive. We would then send a command to turn drive_ram off. 

The user interface will be a display of the file names from the SD Card which are valid virtual 2315 cartridge images. Buttons will allow the operator to scroll through those file names and select one to virtually mount on the disk drive. The user interface must respond to the button presses, update the screen contents, and when a file is mounted it opens the file using our utility routine. Deselecting a cartridge closes the image file.

In order for the disk drive to think it is ready for input-output operations, it must receive the HeadsLoaded signal that we generate from this program. We do that if we have an image file open and we get the pick signal interrupt. HeadsLoaded is dropped when we get the other interrupt that tells us pick has been switched off. 

The LCD Module comes with a library of C routines that I can call to handle most of the heavy lifting driving the LCD panel and determining where the user touched it. 

Sunday, April 2, 2023



There are multiple ARM architectural versions that have different GCC compiler choices. The ARM Cortex A9 MPcore processors required a particular choice among the compiler variants installed on my system. That was the first information I needed to proceed.

Second, one can compile code to run on the ARM systems in bare metal mode, as an alternative to under Yocto Linux. There are two different flavors of compiler and header file libraries. Eventually I settled on the arm-linux-gnueabi-gcc executable with a proper path set up in my .bashrc files. That worked fine.


My two laptops are in use as I work on this, in addition to the VMware Linux image. I use USB memory sticks to transport my files between the three environments. Earlier today, my main transport stick threw up an error saying it was damaged. Scan and repair didn't help. Trashed.

A bit later, a second drive I was using for transport choked with similar errors. It would seemingly quick format properly but then fail. I decided to try a full format, which froze. At this point, two memory sticks are ready for the real world trashbin. I have one working drive for file transport and a few new devices on the way from Amazon. 


My code is compiling properly, leaving me free to finish building out the best test code I can before I fire up the physical board and begin testing everything out. 



I wrote a quick bit of code to make use of the HPS to FPGA bridges to communicate with my logic. Basically the bridges are mapped into memory and thus can be accessed with simple C assignments and references. These are real memory addresses in the 4GB addressing range of the ARM processors. 

The special Linux file /dev/mem has accessibility to all the installed real memory. We open that file and then use the memory map (mmap) command to grab some virtual memory locations that are mapped to parts of the file. In this case, if I use the starting address of the H2F Lightweight bridge (xFF200000 in real memory) and map four bytes with mmap, that is a variable pointer which stores and fetches from xFF200000 to xFF200003. 

In the same way, I mapped eight bytes of real memory at xC0000000 to xC0000007 which is the location of the H2F bridge. Storing and fetching from that pointer to the virtual storage block returned by mmap allows me to send or receive over that bridge. 

My first test, other than having successful open and mmap system calls, is to read from the H2F LW variable, which is the status word I return from the FPGA side. It should be 0000 to represent the proper idle condition of my logic, else I return an error. 

Writing to the variable from the H2F LW mmap call will transfer a command word to my logic. I flip the driveram state on and off with various commands, checking the status after each and observing the LED on the board I use to report the state of driveram

If all this seems to be functioning properly, I will code up the logic to transfer a virtual 2315 cartridge image over to the SDRAM by passing it through the FPGA logic, then retrieve the data I transferred to verify it was faithfully transported. That will be done in a later version of the code 

The loading of the image to SDRAM is triggered by storing the Load command to the H2F LW bridge variable, which causes my logic in the FPGA to wait for me to write the eight byte block to H2F bridge for all the data from the start to the end of the cartridge file - 130, 326 writes. My FPGA logic will accept each write of the block and write it to SDRAM, advancing the address one block at a time. I should see a successful completion status when I read from the H2F LW bridge.

Unloading is a mirror, where I store the Unload command to H2F LW and then loop 130, 326 times reading blocks from H2F bridge and comparing them to that portion of the virtual cartridge file I used for the original loading. It should match to prove out the functioning. 


Although the documentation from Terasic for the board mentions installed the Intel SoC EDS development toolchain, the Intel site asserts that is superceded by the ARM development suite. I loaded the ARM toolchain, based on Linaro GCC, to cross compile my C code under Linux on my laptop to produce binaries that execute on the ARM processors which are in the HPS side of my Cyclone V chip on the Terasic board. 

ARM shows Windows, Mac and Linux versions but it is immediately obvious that the Windows version requires a shim of a Linux emulator. If the code is Unix native, then the best platform is my Linux image on VMware. 


My first trial at compiling the program threw errors as it couldn't fetch the #include files that are needed for file IO, memory mapping and other standard C functions. I will need to dive into this a bit to sort out the proper setup to build my binaries for the Cyclone V chip's ARM processors. They will run under the Yocto Linux image that is provided by Intel for their System on Chip (SoC) products. 

Saturday, April 1, 2023

Poring over the compile messages and cleaning up my FPGA logic


During the process of synthesis, fitting, routing and generation of the final binary to load the Field Programmable Gate Array (FPGA) half of the Cyclone V chip, the toolchain emits many messages both benign and indicative of potential errors in the submitted code.

Some of the messages are warnings that result from choices made while running Platform Designer (formerly QSYS), such as deselecting the option to have a flipflop delay on a particular bridge between the Hard Processor System (HPS) and the FPGA sides. Since the flipflop is not connected, there will be errors reported about dangling lines to the flipflop, after which the toolchain does the right thing and removes it from the design.

There are true issues in my code that were reported also. Each possible error caused me to think about what the warning message stated and look over my code. I found some signals that I generated for module A and another signal for module B, but the intent is to feed the signal between the two modules so there should be only one signal used. 


Truncation errors highlighted weak VHDL in the logic that generated the RAM address to be used for each word read or written to the disk. This was a bit complex, as it involved groupings like sectors, heads and cylinders, with each of the sectors taking up 321 contiguous words in memory. Finally, the pathway I used to access the sdram on the HPS side from the FPGA reads or writes blocks of four words at a time (eight bytes). 

The address sent to access sdram is 29 bits, as each integral value is a different eight byte block of the possible four gigabytes of RAM. Since I will be addressing individual words as the disk modeling logic reads or writes to disk, we have to convert between a word address (16 bits for the IBM 1130), a byte address, and a block address for SDRAM. 

Selecting which of the four words in a block is the target for the sdram access is done by setting the eight bit byteenable signal - each bit activates or blocks one byte of the eight in a block. Thus after I generate a 32 bit byte address from the cylinder, head, sector etc of the current disk activity, we drop bits from the end successively. 

First a bit is dropped to create 31 bit word addresses. Then two more bits are dropped to create the 29 bit block address. Those dropped bits select which two of the eight bits of byteenable are flipped on. This allows us to write only one of the four words in a block, leaving the other three as they were. 

Out of the four gigabytes of addressable RAM, only 1GB is installed on the DE10-Nano board. Further, most of that is used by the Linux image that runs on the HPS side. We reserve the last megabyte of RAM for our purposes holding the disk image. Thus, the 29 bit block address starts at a base value that is the beginning of the last megabyte of memory. 

To that we add the relative block address for our current disk access. The disk is organized in sectors of 321 words, four sectors per rotation. With two surfaces and heads, there are eight sectors available as the disk spins. By moving the arm in and out to one of 203 radii, the 203 cylinders provide 1,624 total sectors on a disk cartridge. 

My math to calculate the relative word address on the disk cartridge is:
            (Cylinder * 8) + Head * 4 + Sector) * 321 + Word 

This requires 99.4% of the 1MB area we set aside to hold the disk contents. The word address is converted to a byte 32 bit address, adding on the base address of the last megabyte of RAM gives us an absolute byte address. Since we are addressing blocks of eight bytes, only the leftmost 29 bits of the address are used to send to the sdram access method. As described above, the byteenable works with the last 3 bits of the 32 bit byte address. 


I had been used to the Xilinx toolchain which, at least with VHDL code, would cease synthesis if a signal was not declared. It also threw up errors highlighting signals that are defined but not used anywhere.

The Quartus toolchain acts similarly except in one important way. If a signal in a Verilog module is used but not declared with a wire or reg statement, the toolchain makes an implicit definition and proceeds to compile everything. This happened because, with signal names being case sensitive, I might have had DiskRunning used in many places but written it as diskrunning somewhere else. Thus two signals were created when I intended a single common signal. I found a few of these and fixed them.

Messages telling me that signals had no driver, or that they had no destination, were keys to superfluous signals that I could trim out of the top level file which was in Verilog instead of the VHDL I used for everything else.