FAP reborn: the new I/O card

Previous article: CPU board, memory board, video card.

Github repo

We have finally come to the big one, the new I/O card.  This is the one I designed completely from scratch without influence of the half-assed old I/O card, so I’m going to go in details in this article.

So far, we have the backplane, CPU, memory, and video card. I can program FAP to display some messages on the screen but there is no way to do anything else because no input methods are available, and as a result FAP can’t communicate with the outside world. It needs some way of input/output and that’s why I’m designing the I/O card.

A quick recap of the the previous article about FAP I/O: Z80 uses in/out instruction for port  read/write. 256 ports are available and port address is the lower 8 bit of the address bus when in/out is executed. A port is read when both IORQ and RD signal goes low, and written when both IORQ and WR goes low. I’m also using interrupt instead of polling, Z80 has 3 interrupt modes, mode 0 is 8080 compatible mode that no one uses, mode 1 just jumps to 0x38, and mode 2 makes your head explode the first time you learn about it but is the most powerful, and is what my I/O board going to use.

The last time I worked on the I/O board I used an arduino just for reading PS/2 keyboard, an STM32F103 as the main I/O interrupt controller, and a bunch of 74 chips for the interface between STM32 and Z80 bus. The slap-together had 2 I/O ports and 2 interrupt vectors, but even with just that it accumulated 9 74 series chips, just look at this mess:

IMG_1473.jpg

Notice the piggybacking everywhere and the general messiness, if I were to continue to design the new I/O board this way it will end up a horrendous board to route, no flexibility at all, high power consumption, possible noise problems, and one single bug means making a entire new board.

So instead I’m going to do it properly and go the modern route: Using a CPLD. CPLD stands for Complex Programmable Logic Device, like FPGA it has logic that can be configured via HDL, but unlike FPGA it has a built-in non-volatile configuration memory so it works right away when powered up. CPLD is also cheaper and less complex than FPGA, often only have hundreds of gate-equivalents instead of millions in the FPGA, as a result CPLD is often used as glue logic instead of an active device. Personally I feel that  FPGA is mainly for high speed high bandwidth active applications, and CPLD is basically a replacement for 74 series chips.

And replace 74 series chips it will. The CPLD I picked is Altera EPM570. It’s a slightly older part, but has plenty of pins and is cheap, there is a even cheaper version EPM240, exactly same but with less logic cells. Because EPM570 has 144 pins, the plan is just connect everything on the bus to the CPLD and figure it out in HDL. As for the I/O controller, I’m using a STM32F051C8T6 this time.

I went all out on the STM32 side, adding as much peripherals as possible, in the end I have SD card, I2C EEPROM, PS/2 Keyboard, RTC, ESP8266, and a general purpose UART header all hooked up to the STM32. It might be a bit overkill but I guess it’s better to have them just in case than not having them at all.

The STM32 will talk to the CPLD via a mini-bus with 4 bit of address, 8 bit of data, and a handful of control signals. While the CPLD contains all the glue logic to interact with the Z80 bus. Below is the diagram of the I/O board structure.

Screen Shot 2016-12-26 at 01.19.52.png

To program the CPLD I bought a cheap chinese knockoff programmer which seems work well enough, also needed is Altera Quartus Prime Lite, which is free. I’m going to use schematic capture for this instead of connecting everything in Verilog because I feel that being able to see and edit a schematic is more intuitive in this case. But first I need to write a couple of components that I’m going to use inside CPLD, chief among which is the 74HC573 8-bit transparent latch, a simple matter of  30 lines of code:

Another one we’re going to use is a 4-to-16 line decoder:

And with that, we can start laying out our glue logic inside the CPLD. Instead laying down physical 74 chips, we can just do it in software and watch the magic happen. This I/O board needs to handle interrupts, port write, and port read. So let’s start with the first one:

int.PNG
FAP I/O board Z80 interrupt logic

While it might look complicated at first, this is actually not that bad. The centrepiece is just a 8-bit latch. When the STM32 controller wants to start a Z80 interrupt, it first puts the interrupt vector on the STM32-CPLD data bus, then activates INTVECT_LOAD signal, this loads the vector into the latch. Then STM32 pulls down the INT line on the Z80 to start the interrupt, the Z80 will acknowledge the interrupt at the beginning of the next instruction, where both IORQ and M1 goes low. They are OR’ed together to give INTACK, which then activates the output enable of the latch, putting stored interrupt vector onto the CPU bus, which Z80 then combines with I register and jumps to that interrupt vector address. The INTACK also generates an interrupt on the STM32, upon which deactivates the INT line. Here is the STM32’s code snippet:

With that out of the way, next up is port write. It uses 2 transparent latches and it’s actually extremely similar as the interrupt above, only the data is loaded from Z80 side. When Z80 wants to write to a port, both IORW and WR goes low, which is OR’ed to give IOWR signal. When IOWR is low, there is valid port address and data on the CPU bus, so I made IOWR simply load the address and data into the corresponding latches. IOWR also fires an interrupt on the STM32, who will then activate the latch1 signal and read the data and address off the latches and process them. Below is the diagram and code snippet.

portwrite
FAP I/O board port write logic

Next up is port read, this is the most complex of the three because of the timing constraints. Let’s look back at port write first: when CPU does a port write, the port address and data are loaded into two transparent latches, while STM32 is notified at the same time. So even if STM32 bogged down for some reason the port address and data will still be available in the latch, nothing is lost.

There is no such luxury in the case of port read, when Z80 wants to read a port, both IORQ and RD goes down, OR’ed together to give IORD. Port data must be valid the moment IORD goes active, otherwise the CPU gets garbage data. That means I can’t make STM32 respond to IORD as an interrupt since it would already be too late. So as you probably have guessed, transparent latches to the rescue again.

pred
FAP I/O board port read logic

This is much more complicated than the first two so bear with me: There are 16 transparent latches, corresponding to 16 available Z80 ports. When Z80 wants to read one of these ports,  a valid port address will be present on the CPU bus, then the IORD signal goes active. When that happens a 4-to-16 decoder is activated and selects the corresponding latch out of the 16 based on the address on the CPU bus, this select signal along with IORD itself enables the output of that latch, putting its content onto the data bus instantly.

Of course we need be able to write data into those latches first for CPU to read. When STM32 wants to load data into a latch, it puts the address and data onto the STM32-CPLD bus, then activates the LATCH16 signal. This enables another 4-to-16 decoder inside CPLD that select the corresponding latch. The select signal together with LATCH16 signal loads the data into said latch, which will then be available for CPU to read. The STM32 code is actually pretty simple:

With all those out of the way, here is the finished board:

sdfsdf.png

IMG_6405.jpg

Again, I made some mistakes in the rush to get the board made, the footprint of PS/2 connector is flipped, the JTAG connector pinout is all wrong, and somehow I missed the TDO line. Those are all fixed in the repo. And with just one jumper wire, the board functions perfectly.

 

Previous article: CPU board, memory board, video card.

Github repo

 

Advertisements

FAP reborn: CPU board, memory board, video card.

Previous post: FAP reborn – Backplane

Next post: the new I/O card

Github repo

With backplane finished, next step is to design a number of modules that plug into it. It would be the same as the old FAP, consisting of CPU board, memory board, video card, and I/O board. In this post I’ll get the first three out of the way, since they are have not changed much.

And because they are still largely the same, albeit laid out nicely on a PCB,  I’m not going into details about how they work in this article, check out the older entries for those details.

Read more about FAP’s CPU here

One thing that did change was the bus voltage. Originally the bus runs at 5V since both Z80 and memory operates on that voltage. However, the FPGA video card only tolerates 3.3V, so was the CPLD that I’m planning to use for the I/O board. So in the spirit of doing things properly, the new FAP’s bus will be running on 3.3V. How are we going to achieve that? Take a look at Z80’s data sheet:

Screen Shot 2016-12-24 at 13.09.41.png

Looks like inputs are at TTL level, meaning they only needs 2.2V to be registered as high, so 3.3V inputs should work. However, for some reason clock inputs still needs at least 4.4V, so that will need level translation.  To shift signal level up, power the 74 chip at 5V and give it the input at 3.3V, buffered 5V signal will come out the other end. Similarly, to shift down power the chip at 3.3V and give it 5V inputs, 3.3V signal will appear on the output.

As before I used 5 74HC245 bidirectional bus transceiver as both level translator and buffer. Every single signal is broken out on the bus, buffered, and all at 3.3V. The jumper wire you see on the picture below is to correct a small error in the first revision of the PCB, the latest board file in the project GitHub already had it fixed.IMG_6393.jpg

CPU Control inputs such as CLK, INT, NMI, WAIT, BUSREQ, RESET needs to be pulled up as they need to be at defined state at all times. I also added LEDs for power and BUSACK. Decoupling capacitors are used liberally, since I was in so much trouble with noise last time.

Read more about FAP’s memory here

and here

Next up is memory board. I’m actually planning to design a memory board with a modern flash memory for both ROM and RAM, and a CPLD as memory controller, but for now I’m sticking to the old plan: 32KB ROM from 0x0000 to 0x7fff, and 16KB RAM from 0xC000 to 0xffff. The missing 16KB at 0x8000 is used for VRAM.img_6396

In the old FAP I piggybacked two memory chips so it needed less wiring, this time I again did it properly and put them side by side. Those two chips runs at 5V but takes 3.3V inputs as well, so only one output buffer-shifter is needed. I also changed the the write enable signal of the EEPROM by ORing it with BUSACK, so that EEPROM write is only possible when CPU is off the bus, that means misbehaving programs will not be able to write into ROM during normal execution. Another couple of LEDs round up the board.

Funny thing happened when I tested the newly assembled memory board, as writing into addresses beyond 0x2000 will change the data starting in 0x0000, I thought there was some short in the address line, but in the end it turned out my eBay-bought AT28C256 32KB EEPROM chip is a fake, and it’s actually a AT28C64 8KB part. They actually spent the effort sanding off the original marking and laser engraved a new one. I ordered some more from mouser, and I guess I’ll have to make do with 8KB for now, which is still plenty.

Next up: video card

Read more about FAP’s VGA video card here

And here

… and finally here

IMG_6426.jpg

IMG_6401.jpg

This one is pretty straightforwards as well, I’m still using the Mojo V3 FPGA board piggybacking on the circuit board, and two SRAM chips for double buffered video memory. 6-bit R-2R DAC produces 64 colors, and a nice VGA connector instead of just wires.

Being the board with the highest speed signals, 25MHz pixel clock, the improvement in video quality is night and day compared to the old hand-wired board. The whole display is much sharper than before, and ghosting and color desync is gone.

IMG_6247.jpg

There are still some issues though, in the rush to get the board made I didn’t realise the VGA connector actually blocked the USB port on the Mojo, so I had to either take the Mojo off to program it or remove the VGA connector, I did the latter. This has been fixed in the project repo. The other thing was I ran out of pins on the Mojo, so I had to omit some signals that I would otherwise like to include for more functionality. I saved 2 pins on the VRAM address line, halving VRAM from 32KB to 16KB, I also had to give up the maskable interrupt interface and use NMI instead. When I have time I’m going to design FAP’s video card with on-board FPGA instead of using Mojo, but for now it it’s still pretty capable.

With the boring stuff finally out of the way. I/O board is next, and it’s going to be a long one.

Github repo

Previous post: FAP reborn – Backplane

Next post: the new I/O card

FAP reborn – Backplane

Previous Post: FAP with a Keyboard

Next post: CPU board, memory board, video card

Github repo

Can’t believe it has been more than 9 months since my last update. Work picked up, and although I was still working on FAP on and off, I just didn’t bother update the blog until I made some progress.

Last time I was here I just finished the I/O board. The mode 2 interrupt and port read was working, keyboard was working, so did the serial input. So I started coding some simple print routines in assembly, stuff like putc and puts. It quickly turned out that my programs would only work intermittently, sometimes goes into NMI for no reason, sometimes resetting by itself, sometimes jumps to the wrong address. And faster the clock speed, more often those happen. It was getting extremely frustrating since when it goes haywire I wouldn’t know if it’s a bug in my program or just FAP being unhappy.

As you probably have guessed, It was the noise problem from having no ground planes,  hundreds of wires bunched together cross talking like crazy, and maybe even one or two cold solder joints. I thought I could get away with it but I should have known better, just look at this spaghetti shitshow running at 8MHz, it’s amazing it worked at all.

IMG_1308.jpg

Clearly, in order for FAP to work, I had to ditch hand-assembly and go full PCB. This way, it will look much more professional, and I don’t have to cut, strip and solder miles of red wires. That’s exactly what I did. And now, after 9 months of hiatus, FAP rises again, stronger than ever.

First things first, I need to design a brand new backplane. The original one is basically a stripboard with 4 dozens wires soldered from an STM32 dev board. Since I’m doing it again, I’m going to do the whole thing properly. The uC used on the old FAP was an STM32F103VCT6, 3 problem with it: it’s a 100pin part which is too much for this application, it’s a relatively old member of the STM32 family, missing a lot of nice features, and there is a 32KB code size limit in uVision5. So back to the parts pin it goes, instead I’ll using STM32F072R8T6. It’s a F0 so no code size limit in uVision, it has a lot of new features that F1 doesn’t (32-bit timer, build-in USB pull-up, swappable RX/TX, just to name a few), it’s a 64pin so it’s easier to solder, and in the end it’s cheaper too.

Now comes the problem with the size of the backplane. The board size limit of EAGLE free version is only 8cm x 10cm so that won’t do. Luckily EAGLE offers a educational version, free as well if you have a .edu email, that has a 10cm x 16cm limit. That’s what I ordered and as a result 10cm x 16cm will be the dimension of the FAP backplane.

Next part to reconsider is the bus connector, in the old FAP it was a double row female pin header with 2 rows of 40 pins, so in theory it should have 80 signals. But because it was on a strip board the two rows were connected, only 40 signals were actually available. And because I had to cram most of the CPU signals on there, few control signals had to be omitted and only one pin was used for GND, resulting in the non-existent noise immunity. This time I decided to still use double row female pin header, this time 38 pins wide because of the board size. But because it’s on PCB I have all 76 signals so every single Z80 signal is on the bus this time. Here is the pinout of FAP’s new bus connector.

screen-shot-2016-12-23-at-02-24-15

As you can see most of the first row is GND to reduce noise, the clock signal is surrounded  by 3V3 to for that reason too. The signals is arranged in the form of control outputs, control inputs, data, and address.

With those problems out of the way, here is the finished design of FAP’s new backplane:

bp.png

5 bus connecters spaced 2cm apart, the microcontroller on the right side of the board, a USB connector provides both power and communication, and a 3.3V regulator and 6 buttons round up the design. I’m also putting the LCD above the uC instead of letting it dangle off the side of board.

Here is the assembled board, much neater than the old one, and hopefully a lot less noisy too.

8qytgad

The LCD is secured via 4 mounting holes, and the microcontroller hides below it.

bp13zbk

The backplane firmware needed an update too. On the old backplane communication was via a serial port, this time we’re using USB, which is much faster. But overall not much has changed. You can find the up-to-date resources on the Github repo of this project.

Previous Post: FAP with a Keyboard

Next post: CPU board, memory board, video card

Github repo