Cooperative Multi Tasking on a Z80

I decided that the Zalt system is to be a game console operating system. Now I can focus on what bios/os code to write to accomplish this.

After getting the initial virtual device working I thought it would be a good idea to look into how to structure the rest of the code. One of the main problems I faced is how to let separate components work together on one CPU. I thought that a full preemptive thread scheduler would be pushing it at this point and also introduce overhead I could do without right now.

So I tried to use a cooperative multi tasking trick I had used before and see if it would work with the z88dk (sdcc) compiler. The idea is that you create a function for each task that has to run. The main loop (I guess I should now call it a game-loop) just calls each task-function in the appropriate order.

Each task-function does a little work and yields back to the main loop when its done, not taking too much time in each ‘slice’. On the next call into the task-function it remembers where it left off last time and continues there – a simple state machine.

The actual code trick to make this all look nice I came across here first. I have basically copied that implementation consisting of a set of macros. I normally try to avoid macros as much as possible, but here I could see no alternatives.

An example of a dummy task could look something like this:

Task_Begin(Task1_Execute)
{
    while(true) {
        Task_WaitUntil(CountDown());
        System_DebugConsole_Out('1');
    }
}
Task_End

The Task_Xxxx are the cooperative Task macros. CountDown simply counts a variable down on each call and returns true when it reaches zero. System_DebugConsole_Out is one of my functions to output a character to the debug-console.

What may surprise you is that the while-loop will not cause the method to hang the application. Task_WaitUntil will exit the Task1_Execute function unit CountDown returns true. Next time the Task1_Execute function is called it  will enter at Task_WaitUntil and call CountDown again. Only when CountDown returns true will the character be output to the debug-console.

So the main loop can be something as simple as:

while(true) {
    Task1_Execute();
    Task2_Execute();
    Task3_Execute();
 }

Each TaskX_Execute function will get a call and can do a small amount of work before returning.

Internally the Task-macros  use a integer variable to keep track of where to start executing in the task-function when it is called again. This is some nasty C code that you would normally not even think of writing involving jumping in and out of switch statements.

You can see that the current code __LINE__ is being used as a state value for the _task variable. bool_t is my boolean type.

#define Task_Begin(name) \
bool_t name() \
{ \
    bool_t _yield_ = false; \
    switch (_task) { \
    case 0:

#define Task_WaitUntil(expression) \
    _task = __LINE__; case __LINE__: \
    if (!(expression)) { \
        return false; \
    }

#define Task_End \
    } \
    _task = 0; return true; \
}

The _task variable is used in the switch to jump to the correct place when the task-function is called again.

If you would expand the macros in our example you’d get this:

bool_t Task1_Execute()
{
    bool_t _yield_ = false;
    switch (_task) {
        case 0:
        {
            while(true) {
                _task = __LINE__; case __LINE__:
                if (!(CountDown())) {
                    return false;
                };
                System_DebugConsole_Out('1');
            }
        }
    } 
    _task = 0; return true;
}

Note the odd placement of the case statements that cross scopes.

I must say the I had some strange errors in the z88dk (sdcc) compiler when testing this. I was able to make the code compile with some fiddling around though. If this turns out to be too brittle for this compiler I will try some other means, until then it’s good enough.

Advertisements
Published in: on February 18, 2017 at 11:49 am  Leave a Comment  

Zalt virtual devices over USB

I still don’t have any IO hardware in the Zalt system. I am working on a general high-speed bus design with Ron, but that is far from usable at this stage.

Virtual Devices

So the idea came to tunnel all the smart IO devices I would like to build virtually over USB to and from the PC. The PSoC (kit) System Controller has a (device) USB port on it and dropping in the USB design component in the PSoC design service and configuring that to two-way USB bulk transfer basically is all you need to get that working.

The Virtual Devices app on the PC is a C++ application in Visual Studio using Qt as an application framework and libusb as a USB library.

I had some trouble getting the event system working on a Qt Console application, so I turned it into a Gui application. I guess the eventing system is tied to the (Windows) event loop. The application installs an application-level event filter that catches all the key strokes – when the keyboard button on the Gui is active. These keyboard events are put in a USB protocol message of my own design and send to the PSoC. That is about all the app does at this moment. Future plans include having a virtual file system. Not sure about video yet – perhaps start with character based.

The PSoC has a new UsbProcessor component that (for now only) receives the protocol messages sent from the PC app and dispatches them to the correct device handler. I changed the Keyboard device to now handle the protocol messages and signal availability to the Z80 using the interrupt and vector that was already in place. The Z80 will then use IO to come and get the key code.

virtual-devices

Smart IO Devices

The whole idea of making the virtual devices PC app is to develop the stream-based smart-devices Z80 API. The bus I mentioned earlier uses a high-level protocol to communicate with each smart-IO-device. The idea being that the Z80 programs does not want to know or care about file sectors or tracks – it only care about files, directory structure and content.

So now I can write the API that will be used to access remote data of the smart-devices over the bus. I can even start to code the bus protocol I had in mind to see if it covers all the bases. But first things first – small steps.

Published in: on January 25, 2017 at 10:40 am  Leave a Comment  

Zalt Debugging Support

I have been busy on the Zim80 Z80 simulator software a lot lately. But recently I have been switching back to writing the Zalt bios (kernel/os – whatever you want to call it) and setting up basic facilities for further development.

One of these basic facilities is some kind of way to implement a debugger in the PSoC System Controller. As I have mentioned before I have chosen to use the Z80 Halt instruction as a signal from the Z80 to the System Controller it wishes to break into the debugger. The System Controller responds and an exchange of data follows.

  • Z80: Executes the Halt instruction and the HALT signal goes low (active).
  • PSoC: Has an interrupt on the HALT signal activation and executes its ISR:
    • Activates the NMI signal to the Z80
    • Wait for the HALT signal to become inactive – this means the Z80 has detected the NMI and is executing its NMI handler at address 66h.
    • Deactivate the NMI signal.
    • The Debugger starts the state-machine to indicate we have a debugger session.
  • Z80: The NMI handler calls a routine to save all registers into memory variables and calls the PSoC to ask if we’re in a debug session – executes an In (io) instruction on the debug-port (currently 00h – but that may change).
  • PSoC: detects the IO-In instruction and calls the Debugger (because the address is on the Debug-Port) and advances the state machine to the next state. Note that the PSoC will insert wait-states for all IO-operations to/from the Z80 – it just isn’t fast enough because software is involved.
  • Z80: It checks the result of the In-instruction and continues. For now I have hard -coded to dump all register values  (we previously saved) to the PSoC. At a later time a whole debug-monitor can be implemented here.
  • PSoC: all register values are intercepted and stored in memory. When done the statemachine engages its last state that signals the main-loop in the PSoC to print all the register values – remember we’re executing inside the Halt-ISR here (actually it’s the IO-ISR).
  • Z80: With all register values sent, the NMI handler returns (retn) and continues normal execution of the program.

Because I am currently writing most code in C I have made some debug marco’s that encapsulate this ‘breakpoint’ halt statement and make it easy to use.

As I go, I will add more functionality to the debug-monitor implementation to support more commands and interaction with the developer at the debug console.

You can follow along with the progress at the Zalt github repository.

Published in: on January 6, 2017 at 1:23 pm  Leave a Comment  

Zalt is open source

I have recently published all the source files of the Zalt Z80 Computer project.

You can find it here.

It contains the modules that make up the Zalt Z80 Computer:

  • CPU Board (v1.0)
  • Decoder Board (v1.0)
  • BusSpy Board (no pcb)

Here is a short description of each of the folders:

  • BusSpy Board – module (handwired)
  • CPU Board v1.0 – locked – module (in production)
  • Decoder Board v1.0 – locked – module (in production)
  • Design – braindump and design documents
  • Kicad – Zalt specific (shared) libraries
    • Board Template – PCB template for stackable boards.
    • Logical Design – Logical scratch pad for working on ideas.
  • Source – Zalt OS source code
    • SystemControler – PSoC5 project and source code
    • Z80 Terminal – Beginnings of a terminal
    • Z80 Tests – Location for all kinds of test code
    • z88dk target – Source for the z88dk Zalt target
    • Zalt Bios – The Zalt OS source code

Hope you like it.

 

Published in: on October 23, 2016 at 3:57 pm  Leave a Comment  

Zim80, the Z80 Simulator

It’s been quiet for a while now and that is because I am working on building a simulator for the Z80 – or an emulator; it’s very confusing what difference is exactly. “Why would you build on from scratch when there must be some out there already?”, you may ask. Yes, they are out there but most of them are old and some of them don’t even work and they just don’t do what I would want out of one…

When I began writing the first code for the BIOS (kernel) for my Zalt Z80 Computer, I quickly realized that I needed some way of verifying the correctness of that code even before trying to upload it to the Zalt computer. So I was looking for something (a simulator or emulator) to do that with. Problem is with having a homebrewn computer design is that the normal Spectrum, MSX or TI-calc sims won’t work.

I wanted to be able to write unit tests that could validate each piece of code, each function and control the state of the entire system, not just the Z80, before it is called and assert the state of the entire system after it had executed.

So after a couple of days searching and trying out archaic software I was fed up and started to  think about writing my own Z80 simulator. My simulator would need to be able to also simulate the electrical signals of the Z80 and other parts of the system, like RAM etc. Simulating the Z80 itself would probably be just a really big (and complex) state machine, with all sorts of special cases.

Because I know Visual Studio and .NET / C# best, I decided to use these tools to create the simulator. Alright, I set to work. The basis of a digital signal is a datatype (enum) that represents four states:

  • Low
  • High
  • PosEdge
  • NegEdge

The simulator is not meant to measure performance or anything so no steps are taken to even consider absolute timing. Relative timing, however, needs to be very accurate based on these four states.

I created general digital signal classes with providers and consumers and even buses (a collection of a fixed number of digital signals). Then I started on the Z80 class and its implementation. I try to make a unit test for each aspect I program so coverage is pretty good.

I have approached the Z80 as a state machine. So there are a couple of states the CPU can be in:

  • Fetch
    This is the initial state that gets an instruction out of memory. When the opcode is known (decode) it switches to the Execute state.
  • Execute
    This state instantiates an instruction class associated with the opcode and gives it a chance to run until it signals complete.
  • Refresh
    This state class is used as a base class for other state classes that have a refresh cycle in their T3 and T4 cycles (of M1).
  • Interrupt
    This state indicates that the normal program flow has been interrupted and a new execution path will be followed. Not ready yet though.

So the Execute state executes instructions, which themselves are states as well and even can contain sub states (instruction parts I’ve called them) usually to read or write from/to memory. Think about an instruction like LD (IX+d), n. It has quite a few bytes: $DD to indicate IX, the opcode byte, a byte for the displacement (d) and a byte for the parameter value n. Then when its executing, that value n has to be written (instruction part) to the correct memory address – computed by adding the signed value of d to register IX.

At the time of writing I have just over 500 instructions implemented. That doesn’t mean I have implemented 500 classes, thankfully. It turns out that the Z80 instruction (binary) opcodes have a method to them. Using this some instruction classes implement almost a complete range of mnemonic in all its variations. Think of all the LD A, B and LD A, C etc. variations there are. The entire range is implemented by one instruction class. But  not always. Sometimes it just makes more sense to implement only on Z80 instruction in one class (like NOP). I still have to do a final completeness check if I have all Z80 documented and undocumented instructions in my opcode definition list (the root definition of all instructions) but currently I still have around 250 unimplemented opcodes. Most of the easy ones are done so there is still a lot of work to do.

Oh, by the way: Zim80 is pronounced as ‘symmetry’. I have made the project open source so you can all read along if you want.

Hope you liked it.

 

Published in: on October 23, 2016 at 3:50 pm  Leave a Comment  
Tags:

Casio MG-510 rebuild with Roland GK Kit GT-3

Taking a break from the Zalt project…

I had bought this broken Casio MG510 Midi Guitar from the 80’s for not too much money. The hex-pickup was shot – the previous owner had tries … something and it is beyond repair. The rest of the electronics seems fine. The main board still works. I tested that by swapping it out with my own (other) MG-510 that is still original and in working order.

wp_20160921_09_36_50_pro

The broken original Casio MG-510 hex-pickup.

Previously I had the idea to convert my own MG-510 to a Roland Guitar Synth pickup and connection, but I decided that would devalue my guitar, so I waited for the right moment to buy a second hand fixer-upper.

So when I had my ‘experimentation-guitar’ I bought the Roland GK Kit GT-3, the built-in version of the Roland GT-3 hex pickup, electronics and 13-pin connector.

I decided I wanted to keep everything original, so I could always restore this guitar into its original intended state. That meant that I had to make a new pickguard plate. I bought a piece of three-ply plastic and copied the shape, the pickup cutouts – but not for the hex-pickup and the potentiometer holes. I wanted three individual switches for each pickup instead of a 5-way switch (also easier to make in the pickguard). So I worked on sawing and filing out the pickguard. I created a small hole in the pickguard for the wires of the Roland hex-pickup to go through (they come out of the back of the pickup) because the hex-pickup itself could lay flat on the pickguard – no routing was needed there.

wp_20160920_21_33_55_pro

I write this as if I worked on it continuously, but the truth is that I started it then didn’t work on this for some time (as in months) and just recently finished it. Oh well…

When the pickguard was finished, I started soldering together the analog guitar ‘electronics’ (passives). I have three, double pole, three position switches: on-off-on for each of the pickups. The idea is that when a switch is in the middle position the pickup is off. This allows selection of what pickups to use or not to use. The bridge pickup is a humbucker and its switch coil splits the pickup. The other two single coil pickups have a switch that puts their coils in- and out of phase. This allows you to created sounds that weren’t achievable before.

The volume and tone knobs are original. Did you know there is a small capacitor over the volume knob? I left it for now.

After testing the analog part of the guitar I removed all the electronics – the control knobs on the front and the jacks/connectors on the back from their face-plates and started to lay out the GT-3 kit components. Turns out that it all fits just as is.

wp_20160920_21_29_55_pro

Here is the original back plate with the GT-3 kit 13-pin connector in there. I also put in the light here because I don’t like it, too ugly to put on the front, but nice to see if it’s on. The jack is a reclaimed one I had laying around.

wp_20160920_21_30_18_pro

The GT-3 kit has most wires included and some even already attached. I ended up flipping the 13-pin connector up-side down because of the lock. Now you don’t have to put your finger or thumb in between the plug and the rim of the guitar to unlock the 13-pin plug. About the only design-flaw in the original MG-510.

wp_20160920_21_30_45_pro

The control face plate has the ‘digital volume’, the GK/Guitar mix switch and I replaced those big ugly push buttons with a momentary mini switch.

wp_20160920_21_30_59_pro

Here you do have to solder on some wires but its all very clear from the installation manual that comes with the GT-3 kit.

wp_20160920_22_03_26_pro

The Roland hex-pickup wire (with connector) just makes it to the PCB-cavity so I positioned the small GT-3 kit board right at the edge of the cavity with the pickup socket closest to the neck-end. I used double sided (foam) tape to stick it in there.

You can also see I have hooked up the analog audio output jack.

wp_20160920_22_11_38_pro

After that you simply plug in all the wires in their respective sockets and screw the covers in place. Done.

I was pleased that the GT-3 kit worked right of the bat. Great stuff.

Published in: on September 21, 2016 at 8:23 am  Leave a Comment  
Tags: , , ,

Zalt: Memory Management Unit

So everything is working so far, except that the Memory Management Unit (MMU) has not been tested yet. Before we dive right in, I will show the part of the schematic involved. Never mind the blue text, those are my scribbles on IO-address ranges etc.

Z80 MMU2

IC106 is the memory map RAM that maps the Z80’s A12-A15 to the Memory Addresses MA12-MA19. U101 select the operational memory map table – one of 256 – to use. The contents of the memory map table will be used to map A12-A15 to MA12-MA19 when it is selected. The contents of the memory map tables can be written and read back by setting U102 with the correct table address and driving U103 (the bi-directional buffer) to read or write the data. Note that all the necessary control signals are provided by the Logic board with the CPLD on it. As soon as the IO-address is detected to read or write the memory map table, U101’s output is disabled, and U102’s output is enabled – in normal operation U102’s output is always disabled and U101’s output is always enabled. This allows you to read and write a different memory map table than is currently used to (perhaps) run the program.

System Controller

Because the System Controller can access the entire address and data bus and control the important control lines also, I decided to have it exercise the MMU. So I wrote an additional command that allowed control of the MMU from the PC terminal application.

The Memory Manager command ‘mm’ has a couple of modes:

  • nul [table]
    Writes a null-table to the indicated memory map table. If no table is specified, all 256 tables are initialized to null tables. A null table has a 1:1 mapping between the incoming A12-A15 and the MA12-MA15 lines. MS16-MA19 are always zero. A null table only allows access to the first bank of 64kB of RAM memory.
  • sel <table>
    This writes the U101 with the specified value and selects the memory map table for operational use.
  • get <table> [index]
    This prints the value for the specified map-index of the specified memory map table. If no index is specified, all 16 map-values are printed on the PC terminal program. This uses U102 to select the table to read.
  • put <table> <index> <value>
    This writes the value in the map-index for the specified memory map table. This uses U102 to select the table to write.

Testing

After this was programmed into the System Controller it was time to start the test. I removed all chips from the CPU board and left only U101. This way I could test if the IO-address decoding for setting the operational memory map table was working. It was. I wrote the VHDL in the Decoder board’s CPLD earlier and this was the first indication that at least some of it was correct. I worked my way through the other MMU ICs and found a couple of small errors in the CPLD’s logic, that were easily fixed.

But there was something wrong when reading back the memory map table value. Both the WE and the OE of the memory map RAM were active at the same time. That is not good. I looked over the VHDL code a lot of times without seeing the problem.

Then I spotted that the WE and CE signals of the memory map RAM were labelled wrong on the connector in the CPU board schematic. That meant that the CPLD was sending the wrong signals to the wrong pins on the RAM. At moments like these, I love programmable logic. Simply swap the two pin definitions in the VHDL, reprogram the CPLD and all was well. Or was it…?

The 74F245 was getting quite hot when I stopped the System Controller on the code that engaged the correct IO-address and read the data. But why?

When I checked the data lines they were not a definite logical zero or logical one – they sort of floated around the 2V mark… That could only mean one thing: I had a data bus conflict. Something was driving the data bus at the same time as the memory map RAM was outputting its data and U103 was setting that onto the data bus.

The System Controller responds to a Z80 IO request (input and output). The System Controller detects a IO condition and responds. This is how a Z80 program can send characters out over to the PC and receive key strokes from the PC. That logic is disabled when the System Controller takes control of the Z80 bus(ses) – like when using the ‘mm’ command. The only thing that didn’t get disabled was setting the System Controller data bus to output when seeing an IO-input request. And the ‘mm’ command generates an IO-input situation to read the memory map table data back in. So the System Controller was driving the data bus while the 74-245 (U103) was trying to pass on the memory map table data.

Luckily it was an easy fix. The PSoC5 also has programmable logic and adding another AND-gate fixed the issue. Now it all worked.

Software

Next is writing the humble beginnings for an actual Z80 program. I had been dabbling with some Z80 assembler to run some basic tests and have written some routines in assembler for the bios. The plan is to add these to the z88dk target I made earlier and be able to write a complete program. I wan’t to move over to programming in C (z88dk target) as soon as possible because that is just way faster and more productive. If and when I discover problems in performance, I will hand optimize the assembly for the critical parts only.

I have also been creating a system C API for the memory manager.  Here’s a sneak preview – subject to change.

// allocates max 64k of memory
handle_t Memory_Alloc16(uint16_t flags, uint16_t capacity, uint8_t pageIndex);

// allocates max 1MB of memory
handle_t Memory_Alloc24(uint16_t flags, uint32_t capacity, uint8_t pageIndex);

// releases onwership of memory (by handle)
void Memory_Free(handle_t memory);

// releases ownership of memory (any ptr in allocated block)
void Memory_FreePtr(void* memory);

// retrieves access to memory (by handle)
AccessFlags Memory_GetAccess(handle_t memory);

// retrieves access to memory (any ptr in allocated block)
AccessFlags Memory_GetAccessPtr(void* memory);

// locks memory into active region and returns pointer
void* Memory_Lock(handle_t memory, uint8_t pageIndex);

// releases lock on memory - keep ownership
void Memory_Unlock(handle_t memory);

// releases lock on memory - keep ownership (any ptr in allocated block) 
void Memory_UnlockPtr(void* memory);

So there is a good chance the next (couple of) post(s) will be about software primarily – simply because all the hardware’s pretty much done for now.

Published in: on July 1, 2016 at 5:33 pm  Leave a Comment  

Zalt: System overview

I have been writing about the components that make up the Zalt Z80 computer. I realize that it may be overwhelming and hard to follow how the components interact. That is why I made a block diagram of what the Zalt computer components are at this time. Being that Zalt is built as a modular system (an attempt anyway) more components can be added at a later time.

Here is the block diagram:

Diagrams

The squares are the components that make up the Zalt computer. We’ll talk about each component in a little more details. The thick lines between the components are the buses. The address bus (light blue), the data bus (green) and the control bus (red) that contains all the typical Z80 control lines like, MEMREQ, IOREQ, RD and WR etc. Thinner lines are sub-sets of the bus signals or dedicated signals.

CPU

This is the Z80 CPU that is located on the CPU board. All address and data bus lines are connected to their buses as well as all the control lines. The clock (not drawn) is generated by the SysCtrl component. Interrupt signals INT and NMI are not used at this time and pulled high (inactive).

RAM

The RAM component currently consists of 4 static RAM chips of 64k (8 bits) each, located on the CPU board. These chips are enabled by the Logic component whenever it detects a valid Memory Address range. The address lines A0-A11 are connected to the address bus lines A0-A11. The RAM’s A12-A15 are connected to the Memory Address lines MA12-MA15 (also in the address bus). Because the design allows for a bank-switched memory layout all memory has to be connected the (upper) Memory Addres lines (MA12-MA19). In total we have 20 Memory Address lines (A0-A11 and MA12-MA19) that allows a total memory of 1MB. The RAM’s data lines are connected to the data bus.

SysCtrl

The System Controller component is a PSoC5 module, currently  located on the Bus-Spy board. It is actually a dev-kit for the PSoC5 but at $10.= it is a very economical choice. Because the Zalt computer does not have an ROM, the System Controller is responsible for booting the computer. It has a serial connection with the PC and implements several commands that allow the user to upload the program and execute it.

The System Controller also monitors the control bus to see if there is an IO-request ($0000-$00FF). Currently it implements IO address $20 (hex) to connect the Z80 program to the serial link to the PC. That means that the Z80 program can print characters on the PC screen (running a terminal program) and receive keyboard input.

The System Controller is also the source of the system clock. It implements commands to change the speed of the system clock, which is convenient for debugging.

MMU

The Memory Management Unit component is also located on the CPU board. It is hardware (4 ICs) that is in charge of mapping the upper address lines A12-A15 to Memory Addresses MA12-MA19. It does this by storing the memory map in a 32k fast (15ns) static RAM. The address lines A12-A15 address the memory map RAM (A0-A3) and the data stored at these locations is output as MA12-MA19 (8 bits).

The MMU component receives control signals from the Logic component that decodes if the program (or System Controller) tries to write or read the memory map. This allows the program (or the System Controller) to initialize and later change the contents of the memory map table by issuing output instructions on the correct IO-address ($F8F0-$FFFF).

Logic

The Logic component is an Altera Max II CPLD (EPM240) IC. This programmable logic IC contains the logic for decoding the IO addresses for interacting with the MMU component as well the decoding for enabling the correct RAM chips during a memory-request. All address bus and control bus signals are fed into the chip. The data bus is not connected.

Currently less than 10% is used of its capacity for the logic contains only combinatoric logic expressions, which are pretty cheap. There are more than 30 free IO pins left on the CPLD chip for future use.

Wrap-up

Well, there you have it. I hope it sheds some light on the organization of the Zalt system components. The only thing not covered in the overview is the Bus-Spy board that houses the System Controller. The Bus-Spy is connected to all address and data lines and uses a couple of control signals to generate strobe and latch signals for displaying purposes.

Published in: on June 29, 2016 at 8:26 am  Leave a Comment  

Zalt: The Decoder Board (again)

After I had finished my hand-wired Bus-Spy board, I turned my attention to the Decoder board. I had already assembled the Decoder board PCB with the clamp diodes and resistors I needed to bring the 5V signals down to 3V3 and visa versa. There is documentation on the Altera site on how to do this.

WP_20160522_11_33_32_Pro[1]

This is the Decoder board as it came from Elecrow. This time I opted for the green solder mask just to see what the quality would be. Again, Elecrow has delivered excellent work, although this time, on few via’s, the hole was a little off center. No break outs or anything, so not a problem.

I had already ordered all the passive SMD diodes, resistors and capacitors that needed to go on the board. After a few hours soldering with my magnifier (old eyes) it looked like this.

Sight_2016_06_19_120658_737[1]

As you can see, I did not populate everything just yet, although I did solder all the diodes. This is because of the 80 IO pins the Altera Max II (EPM240) has, I only needed about two-thirds. The rest is will be done as needed. For the unconnected IO pins I designed both a pull-up resistor for output as well as a series resistor for input. Because I did not solder the resistors for the unconnected pins, those pins are physically isolated from the header pins they connect to.

After I had the Bus-Spy board and the CPU board running, I could do DMA from the System Controller (on the Bus-Spy board) and run a simple ‘Hello World’ program from RAM I added the Decoder board to the stack. Without the Decoder board, I had to use a jump wire to connect the enable for the RAM chip to the Z80 MEMREQ control line in order for it to work – otherwise the (one and only) memory chip would never be enabled.

In order to start small and test if the Max II could even be programmed I coded the following VHDL:

MBE0 <= MEMREQ;

Sheer brilliance if you ask me. Basically the jump wire in code: let the first (zero) Memory Bank Enable be the same as the Z80 MEMREQ.

I was pleasantly surprised when the Quartus software programmed my board on the first try and my simple “Hello World” test program ran once again. That meant that the Decoder board was basically working! Whoohoo!

The tower of power was growing:

Sight_2016_06_19_164321_468[1]

Published in: on June 26, 2016 at 7:14 am  Leave a Comment  

Zalt: Working on the Bus-Spy board

It has been a while since I wrote about my home brew Z80 computer project now called Zalt. It is not that I haven’t made any progress – although at times it has been slow- I just did not write it down. So here is what happened.

After designing the Decoder board PCB and having it manufactured I thought making the Bus-Spy board would be a good pass time project while I was waiting for the Decoder board to show up in my mailbox.

The Bus-Spy board I ended up making, houses the System Controller (the Cypress PSoC5), some logic to drive 8 TIL311’s my pen-friend Ron was kind enough to sent me -and a duplication of the bus connectors to make it easy to hook on extra logic or the logic analyzer for debugging.

I decided to make this board by hand and used 30AWG wirewrap wire to do the connections. It was a little more work than I thought, although I have made these type of boards before, so I did not get it finished before my Decoder board showed up. But I decided to focus on the Bus-Spy board because that would allow me to do away with all the bread boards and temporary wire-mess.

When it was time to test it, I discovered that the 100mA current a TIL311 may draw on average is a little much for 30AWG wire and I had a considerable voltage drop across my power lines from my poor-man’s bench supply: an old 300W PC supply. So much so that I only had 4.4V on some of the IC’s on the CPU board. I dug in the parts bin for a beefier wire, put on some banana plugs on one side and soldered a connector to the other. I then routed the power directly from that connection on the Bus-Spy board to the TIL311’s supply pins with some thicker wire. That fixed it.

There was one goof-up I only discovered when I was staring at the TIL311’s. I had reversed the order of the LSB/MSB on the displays. I can’t believe I didn’t notice that earlier! Doh!

So from left to right, the first digit is A0-3, the 2nd A4-7 etc. instead of the other way around. Ah, well. I printed out a small piece of paper indicating what each digit is. If/when I create a real PCB for the bus-spy, I will make sure this is fixed.

 

Sight_2016_06_19_160233_037[1]

This photo was taken before I fixed the power.

I used the two decimal points on the TILL311’s to indicate the status of some of the control lines (as you can see on the legend I printed out).

The top (left) IC is a GAL16V8 that is programmed to deliver the Strobe signal for the TIL311’s and the Load signal for the two 74-573’s that latch the control signals. There is a row of jumpers (just above the displays on the left) that tell the GAL16V8 what events to capture. This allows you for instance to concentrate on just memory-writes or instruction cycles (M1) etc. Each jumper turns on a specific event type. Removing the jumper turns it off.

You’ll notice that the size of this board is a standard eurocard size (10cm x 15cm). That means that the other boards can go on top and you’ll still be able to see the display digits.

Sight_2016_06_18_163427_268[1]

Here I am performing a basic DMA test where the System Controller on the Bus-Spy board talks to the Memory on the CPU board. I have removed all other ICs to keep it simple.

That is when I discovered that I had a problem. The values I wrote to the memory were not read back correctly. After some digging I found that I had not seated the IDC flat-cable connectors properly. The middle wires were making intermittent contact. So after pressing them down firmly in the vice, it all started working. You’ll be amazed at how much force you need to press down 40 pins into the wires of the flat-cable…

With this out of the way, I could focus on the Decoder board.

Published in: on June 25, 2016 at 6:13 am  Leave a Comment