An attempt to build a Z80 computer capable of running CP/M
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
Well, I did it. I ordered my first custom circuit boards. I laid out a prototyping board with an ISA bus card edge, sent it to dirtypcbs, and after a month of impatiently checking the mailbox, they arrived.
I ended up with eleven boards. After I've built a few and done some testing, my plan is to order a second set of boards to use as a backplane. I'm thinking around five card slots per backplane board, with right-angle headers on the ends to link them together. Until then, I've soldered a couple slots onto cheap China special protoboards, and one slot built as a breadboard adapter.
As for the computer design itself, I decided to keep the buffers on the address and data bus since I'm going with the card-based approach and have a full set of Z80 peripherals to experiment with. And after quite a bit of going back-and-forth on the matter, I've decided to go with convention for the Z80 and use the low byte of the address bus as the IO address, leaving the high byte as an optional parameter byte. This will give the full 255 possible IO devices (instead of just sixteen as in my previous design), and give up to 8 bits for device parameters (such as A/B and C/D select on the SCC, PIO, etc). I'm using a design I first saw [Jan Verhoeven] use for selecting I/O devices: 8 DIP switches set the address of the IO card, and the card address is compared to the address bus with a 74'688 equality comparator.
Read more »After the HAD article [Brandon Dunson] wrote about Tanner Electronics, and the subsequent realization that I'm only 30 miles away, I had to go check it out. Two hours and $35 later, this project has new life.
I picked up a 1.8432 MHz crystal and an oscillator of the same speed. It should be a good clock rate for the UART, and I think it would make a good rate for the main system clock as well. I also grabbed a couple 62-pin card edge sockets (ISA, anyone?) so I could experiment with mounting various sections of the computer on boards (à la [Quinn Dunki]), and I got a CompactFlash socket for booting CP/M (à la [Grant Searle] (whose web host blocked on all AT&T services)). For the sake of my future MC68000 project I got a couple 30-pin SIMM sockets (though if I can figure out the refresh, I might pull one into this project).
Most exciting of all though, Tanner's actually had the Z80 DMA. The DMA is the the hardest to find of the Z80 set. Mouser still carries the SIO, SCC, PIO, CTC, etc, but not the DMA. And since they had them, I did picked up a PIO and CTC. This means now I have a complete peripheral set for the Z80, and I'll be going back to almost to square one.
I'm thinking this time I'll do without the buffers. They worked, but I think they may have been the source of some of my problems when I tried running slightly more complex code. I do wish I had an oscilloscope to properly investigate it though. I'll probably keep my ROM/RAM setup the same, with a 32kB ROM swapping with the lower 32kB of RAM. I'll probably also stick with the '154 for IO address decoding, and the flags register for the ROM/RAM swap.
Now, planning is all well and good, but the project already got put on hold for one move, and another is coming up soon. So, I don't know when I'll actually get to sit and work on this again, but at least it's back on the front of my mind. As anxious as I am to sit down and draw it out, I should probably finish my weather display first, before it ends up permanently stuck in the limbo of the projects bin.
I never thought I'd be so happy to see a few characters slowly type out on screen. Serial communication has been the hardest part of this project so far. I'm using the Zilog Z8530 Serial Communication Controller (SCC). It's a versatile 2-channel programmable USART capable of speeds up to T1, and most notably used in the early Macintosh line for serial and LocalTalk.
With its versatility though, comes complexity. The SCC has sixteen registers for each channel (some shared though) that have to be programmed in the right order to properly configure the chip. Get the order wrong, and an internal race condition is likely. The manual warns of this possibility, but other than a few example assembly programs in the appendices, doesn't give much detail on what the proper order is. What finally worked for me was a combination of procedures found via Google, and old-fashioned trial-and-error.
Read more »It never fails. If you get to the point where you start to suspect the Assembler/Compiler/Automated-tool-built-by-someone-much-smarter-than-you is what isn't working, then humility is sure to follow.
I salvaged a Zilog 8530 SCC (UART) from an old motherboard, wired it in, and threw together a quick assembly program to initialise and test it. It didn't work. For debugging, and so I could know if my code was at least getting past the initialisation, I added an LED to a register I have tied to address $F0 on the IO bus (something I know worked before). It didn't work.
I have a '154 4-to-16 decoder I'm using for peripheral select. The Z80 OUT instruction will output an address on the low byte of the address bus. I'm using the high nybble (A4-A7) of this address to provide chip select lines for up to 16 peripherals, with the low nybble (A0-A3) available for the device (e.g. A/B select on the SCC).
Probing around the '154 to figure out why not even the LED would light, nothing was working as expected. Output 15 was never enabled, 0 only blipped, 3, blipped, and 1 was all over the place. It almost seemed like an endian mixup, but surely the assembler wouldn't mix up something like that.
No, of course it wasn't the assembler. I had wired the '154 to A0-A3, instead of A4-A7. It didn't show up before, because I had always used $FF or $00 as the output address. Now that I'm to the point of using $F0 for the register, and $00-$03 for the SCC, it's a significant problem.
In my defense, thanks to allergy medication, I'm surprised I know which way is up. Cursed Spring.
I spent a few hours last night wiring up my breadboard. I'm using three 74x244 buffers for the address bus and control signals, a '652 transceiver for the data bus, a '32 quad OR for some glue logic, and a '273 register for output. My Flash is serving as ROM on the low addresses, and an SRAM on the high addresses. The second RAM chip is on the board, but not wired in yet. Eventually I plan on being able to bank swap ROM for RAM in the low addresses. Clock is provided by an oscillator built from a 40106b hex Schmitt trigger inverter.
Read more »I've finally completed the code for programming my flash ROMs, and successfully tested all functions for the first time. The code is an absolute mess, but I'm posting it here in case anyone else might find it useful. I've broken out the functions specific to working with the flash into a library. This is my first experiment with classes in C++, so forgive me if its implementation is non-standard.
The Arduino sketch posted below will present a prompt and menu for working with the chip. The Read function will read the specified address range and output Intel Hex format. The Write function parses Hex format and programs the chip with it. Extended Linear Address entries are used to select the sectors on the chip (0-7, for 8 64k sectors). Verify checks the lock bits for the specified sector, and scans through the sector looking for any bytes that are programmed (not reading $FF).
I did run into a few problems while testing the programmer. The first was I noticed that between reads of the same area on the flash chip I was testing with, the value returned was inconsistent. Sometimes it would be just a single bit different on one read out of three ($FF $7F $FF), but sometimes it would be three very different reads ($7F $1F $60). My first thought was perhaps I needed decoupling capacitors, so I broke out the soldering iron. No change. Maybe I'm not accounting for setup time, so I added a delay, and read the byte three times in a row before bringing OE back up. No change. Finally, I threw together a quick sketch that would scan through the entire address range of the ROM and read each byte sixteen times, and report any that were inconsistent.
Clearly, this chip has a bad sector. I pulled these chips out of a wall-mount touch panel that is at least 15 years old, so a bad sector is not surprising. Of the four, two have bad sectors.
The other big problem I ran into while testing was none of the flash chips wanted to respond to any of the write commands. I pored over the datasheet for hours, checking, rechecking the commands, the timing diagrams, everything I could think of. Nothing seemed out of place, and I know I had it working before I moved from the breadboard. ... Which of course means that must be where it went bad. Sure enough, another quick sketch to step through the address pins one-by-one, and I had swapped A14 and A15 when building the board. Trying to desolder from the cheap import board resulted in completely removing the copper pad as well, but I got them connected the right way in the end. It was pretty exciting to see the byte write command complete successfully, and be able to read back in the data I had written.
Programmer library and Arduino sketch below:
Read more »I've been working through the code for reading/writing/erasing my flash chips. I've got reading down and outputting hex format nicely. Chip erase is working, but sector erase still needs some work. For writing, I've been working on the code separately, and have it correctly parsing hex format; I just need to roll it in to the rest of my code. I'm getting to the point where the code is unmanageable in the Arduino environment though. I need to get a programmer and start using a real IDE.
I spent the last two weeks obsessively checking the USPS tracking site hoping for any update on the parts I ordered from China to come in, and finally today they were delivered. I got some 40-pin ZIF sockets, pin headers, a Mega shield protoboard, and after a few hours soldering, I have an Arduino Mega Flash Programmer Shield. Not my prettiest soldering job, but it works. I am a little annoyed with myself for a careless wiring mistake—my control lines I ran around the board to Analog 2-4, when I meant to run them to Digital 2-4, which would have been a short, straight shot. Oh well, it works either way.
Hopefully once this semester has wrapped up I'll be able to finish the programmer and get some code burned, so I can start testing the Z80. I think I've got my initial schematic figured out, but need to order more buffer/drivers and maybe a few other odds and ends logic. I want to try to build the glue logic out of 7400-series, but if budget doesn't allow, I'll use the Altera CPLD I already have.
I also picked up a used copy of "Microcomputers and Microprocessors" at Half Price Books. It goes through interfacing and programming the Z80, 8080, and 8085. It has already proved very helpful for a few points I was fuzzy on.
With its 16-bit address bus, the Z80 can access up to 64KB of memory. It has built-in support for DRAM refresh, using the low byte of the address bus to provide a refresh address during the second half of the M1 cycle. I don't have any RAM on hand that would work with something so old as a Z80, so I'll have to order some. DRAM refresh sounds like a hassle (especially using such a slow clock starting out), and isn't currently available in through-hole packages or 5-Volt, so I'm going with the obvious choice of SRAM. To try and minimize chip count, I'm going to use a pair of 32KB SRAMs with A15 selecting between the two.
As for ROM, I have an old Crestron touch panel built primarily with socketed ICs, including four 512KB AMD AM29F040 Flash memory chips. My plan is to use the lowest 32K of one of them and bank switch with the low RAM. This will put my ROM at address $0000 on boot, so I don't have to try to feed a 3-byte jump instruction on reset. I've seen a number of different ways to pull off the switch, but what makes the most sense to me is to put a register on the IO Bus that handles the swap.
What I'm thinking is a pair of 4-to-16 decoders on the address bus, enabled by IORQ (which I'll need for peripherals anyway). A high address like $FF will select an 8-bit register. Bit 7 on the register will select between ROM (clear) and RAM (set). On reset, register is cleared, and Z80 starts executing from $0000, which is ROM. ROM copies what it needs into the high RAM (CP/M sits at the top anyway), then jumps up to a routine that will set the bit for bank swap. With this approach, I could use the additional bits of the register to swap out additional pages of the ROM, by connecting them to the address lines above A14.
Before I can do any of this though, I need to figure out how to program the Flash, and I want to back up what is currently on the chips, just in case. My first thought was an Arduino Uno with a couple of shift registers outputting the addresses, and PORTD as data bus with the Flash. I'm sure I could have made it work, but after my first attempt failed, I remembered I had picked up an Arduino Mega from one of the closing Radio Shack stores. I used ports A and C for the first 16 address lines, and since those are numbered as digital pins 22-37, I just used 38-40 as A16-A18 (though I would really like to know whose idea it was to number the pins on the Mega in such a haphazard way, with some ports counting up, some counting down, and some just mixed at random). PORTK was data, and PORTE serial and control signals. I can read the entire memory and output it as ASCII-encoded Hex over serial at 115200Kbps in no time at all.
Now I just need to make sense of the datasheet and figure out how to erase and write to the Flash.
For years, I have wanted to try building an 8-bit computer from bare chips—ever since as a young teenager I saw a build log where someone was building a computer around a 68HC11. I stared at those schematics for hours unable to decipher much beyond which thick line was the data bus. The idea was planted though.
I've learned much since then, but there is still much, much more that I don't know. I think I'm finally at the point where I know enough to at least get started.
Over the years as the idea has jumped in and out of my head, I've debated different processors—6502, 6811, 8080, Z80 ... even 16-bit chips like 8086—but the one that has always stood out is the Z80. When I was a kid, my family had an old Sanyo MBC-1000 which ran CP/M on a Z80. That old machine with its green phosphor display is etched into my memory.
In March of this year (2015), my uncle gave me his old electronics kit and a bucket of miscellaneous components and wires. Sorting through this I found a Z80, a Z80A, and a D780C-1 Z80 clone. Suddenly I had no excuse to not give it a try.
I'm working with the D780C-1, because it was in the best shape. To start out, I've built an oscillator out of a 40106b, running at about 10Hz. I've got it free-running with data pins all pulled low (NOP). It may not be much, but there is a certain feeling of accomplishment seeing the address lines count up.
It's hard to find a 7-segment decoder with hex support, and all the ones I have on-hand are BCD only. So, I'm currently driving the displays with an Arduino and a couple of '164 shift registers. Messy, but it works for now. I've ordered a Terasic USB Blaster, and I have an Altera MAX 7000 CPLD from a digital logic class. Plan is to drive a 4-digit multiplexed display with it so I can see the entire address bus.
Create an account to leave a comment. Already have an account? Log In.
Hi Joshua,
At last my monitor type OS (with inline assembler and disassembler )is ready
Please setup and try this v1.0b
you can find all necessary information in my Efex pages;
http://peker.000webhostapp.com/Efex-V4/
please send me your comments than I can improve software
Thank you
I am interested to see what you have, but it looks to be unavailable right now.
I'm amazed to hear that the Macintosh had a 3/4 layer board so early on.
The windows terminal (Hyper Terminal) can send binary files. DON'T choose the 'send file' option as it wants a protocol. If you choose the 'send text file' option then it will send the file in raw binary (it doesn't have to be a text file).
I have never looked into the workings of CPM but I would expect that it works with a cylinders/heads/sectors media format so it might port across to a SD card with FAT32 without (fingers crossed) too much effort.
It's kind of sad that your moving on to the 68000. I liked the Z80 and it's been great watching your journey.
I did end up buying a mega to program the flash. I am still converting the code over from the CPLD programmer.
I looked at your code (I haven't done C) and it looks like you are checking the status bit that I saw in the data sheet. I ignored this and just waited for the delay specified in the data sheet and that all went well.
I put the Mega programmer here - if you want to see the hardware - https://hackaday.io/project/6275-quick-and-dirty-parallel-flash-programmer
I will read through your programming software again and see if it will do what I need. I assume I am free to use it? if it's here on your pages.
This particular Mac Plus was built in 1987. Over by the keyboard connector there is an area that shows the four layers. The board is fairly translucent wherever there is no copper, so you can see all four numbers from either side. I don't know much about when multi-layer boards came about.
I don't like trying to work with binary over a serial connection, so I tend to stick with ASCII formats where I can. I built my Flash programmer to accept Hex format one line at a time. SDCC and ZASM both output Intel Hex format, so that works out well. Even having never used Python before, it was pretty easy to throw together a script that would navigate the menus on my programmer and send the .hex file line-by-line.
I know others have come up with various solutions for emulating a floppy drive, or otherwise interfacing modern storage media with old technology. I think that sort of thing is beyond my programming abilities.
So that's really what I'm fighting right now. The hardware side is fun, and (I can't believe) it works now. There are some things I'm looking into still, like PS/2 keyboard interface (I think I can do it with the PIO, a shift register, and a counter), and moving everything to an S-100 style backplane, but my hobby budget is empty right now. That means I'm stuck with only software to work on, and I am not a good programmer. I am taking a couple programming classes in the Fall though, one of which focuses on Assembly and low-level organization. Hopefully I'll learn what I need for this project.
I have been looking into the 68000, and I've been planning on it being my next project since I started this one. The hardware is much more of a challenge, and I'm already stuck before I've even really started. It's amazing the difference in complexity between the Z80 and the 68000, with them only being released three years apart.
For the flash programmer, I did try to check the status bit. For an individual write, it's not all that important, unless something goes wrong. The way I understood the datasheet, it could get stuck in a loop if a write failed. Polling the status bit would let you know quickly that something isn't going right. This is a concern with my old chips and their bad sectors. I consider checking the status bit far more important with erase—especially chip erase.
Unless specifically marked otherwise, any code I publish on here I consider released to public domain. That said, I'll reiterate that software isn't my strong suit, so make sure you know what you're getting yourself into ;)
I remember working as a tech fixing IBM PC Junior / XT / AT and clones in the early 90's. The first 4 layer board I saw was a CGA card so Mac must have been way ahead of it's time. One tech there had an Apple computer but I didn't pay much attention.
If CPM is cylinders/heads/sectors access then a port shouldn't be too hard. The old file systems were similar to FAT8/16/32 which is still in use today. Though larger media > 32 Gig is usually FAT32ex - only a slight variation. I will give it a go with one of my projects when I get that far.
As for Buses - I found these on ebay
http://www.ebay.com.au/itm/390993328548?_trksid=p2060353.m2749.l2649&ssPageName=STRK:MEBIDX:IT
They're a 80 pin dual row PCB mount header socket. In combination with standard 80 pin dual row headers, they should make for a cheap backplane/bus system.
I intend to use a PS2 keyboard and mouse on at least one of my projects but I haven't started that yet. I normally start with the Video output (VGA) first as that's the hardest part to complete. After that it becomes easier to do the rest.
If you are interested, I can help with some things. I have leant (mostly) VHDL and I can throw code together to suit board available from ebay. Altera programmers are under $10. CPLD is cheap.
I can also code for Z80 but I haven't gotten back into that yet (been 35 years) but I am sure I will pick it up again. I can do most hardware and Intenet languages - just not C ,anything starting with 68 or 65 or ending in 86 and not anything Microsoft except DOS/FAT.
I've not gotten far into the disk structure yet. In fact, the extent of my knowledge is 128-byte sectors ... and I'm not too sure about that much.
I've been debating between using pin headers and using card slots. It strikes me that large double-row pin headers would be much harder to insert/remove and keep clean (not to mention having to solder so many pins on both card and backplane). I'm watching some of the 62p card slots (PC-XT / ISA-8) on ebay ... $3.30 (US) + S&H for 5 of them shipped straight from China. I'll probably use dirtypcbs to run off a set of custom protoboard with card-edge (since the only pre-made ones I've seen are $30 each).
PS/2 looks like it'll be pretty easy to implement. I haven't tried, but I think I could do it with a 74595 shift register and a 7493 counter with a couple inverters and AND gates, along with the Z80 PIO. It seems to me though, that the SCC should be able to handle the protocol in one of its synchronous modes, but so far I've not been able to figure out how to configure it.
I'm fairly new to VHDL—I took a digital logic class last year that got into it. I just recently got one of the Terasic USB blasters, but currently only have a single MAX7000 CPLD. I've been trying to think of what would be the best use for it in this project.
Can I ask why you need the address/data/control buffers (74xx244 and 7x22652). I thought the Z80 could direct drive a couple of chips.
I can't find a datasheet that lists the specific current limits for the D780C. It's my understanding that the NMOS outputs can only drive 2-3 TTL loads. As simple as my circuit is right now, it would probably work just fine without the buffers. Looking ahead to what I have planned though, I'll need them.
Plus, with the buffers there, if I do something stupid then I lose a buffer, but hopefully save the processor.
I didn't even look at the data sheets for what I was doing but I am using a more modern Z84C0020 (CMOS) CPU. I will be using a higher speed 10Mhz NMOS chip in another project soon but after my last post I went and found it and I suspect it's a fake from China. Generally 'fan out' was a problem with older chips. Newer chips can drive lots. A 74LSxx needs far less drive than a 74xx of the TTL era so you may not need buffering for low chip counts especially if you are using modern RAM / FLASH but you would need to check the data sheets.
Yeah they're a good idea for a proto. Standard TTL (including the D780C) has a fanout of 10 TTL loads. The FTC buffers are giving you a fanout of 160 TTL loads. Bit of overkill lol but that FCT is very good with capacitive loads and there would be lots of stray capacitance on a bread board (depending on signal frequency).
Kewl, I like the programmer and code.
I have run into a problem with my project. I need a second ROM or FLASH to use as a character ROM to use on a breadboard. Problem is that all my FLASH is PLCC32 and I only have one DIP32 adaptor. Looks like I will be going to buy a 27C256 EPROM (all I can get locally) and making a programmer for that.
Video is still too far beyond what I can handle right now. I'm thinking I'll just use one of the larger AVRs as a replacement for the Zilog SIO and run with a serial terminal.
I don't have enough faith in my own abilities to try to use a once-write ROM. I'm glad I had such friendly chips on hand - 5 Volt, DIP, and low-voltage programmable.
Z80 CPU's are still in production and as far as I know the SIO are as well. A SIO and a MAX232 or like would do the serial. There are plenty of options for video as well. There are SPI video boards like the GameDuino, the microVGA and I did see another that was a VGA Terminal run via Serial. I will post some links.
In production Z80 chips (CPU SIO CTC etc) -
GameDuino SPI Graphics module -
http://excamera.com/sphinx/gameduino/
MicroVGA SPI or UART -
Having trouble finding the atmega serial video terminal. I will post it later.
I did look into the SIO/PIO/CTC. The SIO/PIO still run around $9 (US), and SIO requires the CTC ($4). I think the only one I couldn't find was the interrupt controller. Since I'm not going for historical accuracy, I figured I could emulate the what I needed from the standard peripherals with just a $6 ATMega164.
This is looking good! I like the Mega shield. I was considering the same thing but I couldn't have been bothered waiting for a Meg to arrive so I went with what I had - CPLD/Uno.
I am doing something similar. I used an Arduino Uno to program the flash. As the Uno didn't have enough pins, I made a big shift register in a CPLD chip. I am using the 39F Flash. I just had a quick look at the datasheet for the 29F and it's much the same.
My messy and incomplete code is here - https://hackaday.io/project/3610/logs
You have to change the code to swap from reading, writing and erasing. It's a lot different to what you need but a quick read might be useful. It also need verify - not done yet.
Thanks! It's great to see someone else doing the same thing ... makes me think I'm on the right track after all. The write process is easier than I initially thought, and I think I might have figured out the verify as well. I'll follow your lead and post the code here when I get something that works.
Become a member to follow this project and never miss any updates
sorry server down, you can check;
mkpeker.wixsite.com/efe