I'm planning on doing a Z80 project, how can I do THIS - Page 1
Forum section: electronics / projects

author: alank2
author_rank: Super Contributor
timestamp: February 23, 2018, 01:56:50 pm
content: I know everyone has done a bunch of them, but I'm going to see what I can put together. I've seen a few people use an AVR for the I/O and that is the approach I am going to take as well. Most of them use a 7474 flip flop to trigger the WAIT line with IORQ to give the AVR time to fire an interrupt and handle the IN or OUT. I was planning on just trying to handle the IN and OUT and then releasing the flip flop WAIT. OUT is easier as the AVR can just grab the port and data and release the flipflop. IN is harder in that you have to provide data (drive the data bus) just long enough for the Z80 to grab it after the WAIT is released and then get off the bus fast enough. Others have taken a they control the clock with the AVR, and I saw a design where someone had a device that delayed the release of the clock. I am thinking depending on timing that one might be able to set the port to output, release the flip flop, and then set the port to input which I think is a 1 cycle instruction and that might work but I haven't tested it. So that is where I am now.Another wrench is that I'd like nice even speeds like 2/4/8/16 MHz for the Z80 and at the same time choose a clock for the AVR that is UART friendly like 14.7456 MHz. I have no idea how running the two async would work or not work well with the IN instruction timing above yet.Then it occurred to me that it would be great if the AVR could programmatically control the Z80 speed, 1/2/4/8/16 MHz, etc. You could use an OUT instruction to set the speed. The person's idea that used the AVR to clock the Z80 would work well for this except that the AVR can only output a signal as fast as clk/2 using a timer which really is not ideal, and then there is the AVR isn't running at even speeds issue as well so there are trade offs. I suppose one could start with a 16 MHz oscillator and use a divider to come up with 1/2/4/8/16 and then logic (or is there a more optimal device? to switch between pins) to control the clock. It might be necessary to have the AVR be able to clock it as well as those other 5 taps depending on the timing of the IN instruction.What ideas do you guys have?

author: Benta
author_rank: Super Contributor
timestamp: February 23, 2018, 03:02:14 pm
content: Well, I wouldn't trust changing the Z80 clock "on the fly" to work. Selecting a clock speed and then bringing the Z80 out of reset would be OK.

author: alank2
author_rank: Super Contributor
timestamp: February 23, 2018, 03:28:17 pm
content: I think they make different versions of the Z80 - I think the CMOS ones can be statically driven.

author: grumpydoc
author_rank: Super Contributor
timestamp: February 23, 2018, 03:37:52 pm
content: I don't think that there. would be any problem changing a Z80 clock on the fly - as long as no runt pulses are generated

author: alank2
author_rank: Super Contributor
timestamp: February 24, 2018, 02:14:09 am
content: Ok, so tonight I was thinking about the slow pain of clocking IN and OUT instructions manually and it occurred to me that that is a really bad way to do it. Instead I am thinking of making the AVR be a bus master and have the Z80 and AVR communicate through the SRAM directly. Each OUT instruction might have taken 15-20 cycles on the AVR and the IN instruction longer to clock the data in, perhaps 20-40 cycles. For EACH one and writing a 128 byte CP/M disk sector would take quite a few OUT's and IN's to facilitate. Instead if I set aside a 32 byte area in SRAM as a parameter area between the Z80 and AVR, the Z80 could write the command it wants to SRAM, which might be a complicated command like "write this sector" and then trigger the AVR to take action. The only way I can think of to do that is to do any out instruction - so the port and data wouldn't matter. The IORQ and WR signals would then trigger a flip flop that would not hold the WAIT signal, but trigger the BUSREQ signal. The AVR would also look for the BUSREQ signal and by time the AVR detects it, the Z80 would already likely be in BUSACK. Then the AVR reads SRAM directly, processes the command, and leaves a result code in SRAM for the Z80 to check. If the command involves reading or writing a sector for example, the AVR can do it itself much faster than a string of IN/OUT instructions would have been and finally clear the flip flop releasing the BUSREQ. I will be using static RAM so I don't have to worry about dynamic memory not being updated.Probably the only downside I see here is that the Z80 doesn't communicate in a single simple instruction like OUT 0x80,65 or something. Not a problem if I build a CP/M 2.2 and 3.1 BIOS to that uses the method above, but it might be harder to port code like ROM BASIC that people might modify to change the serial in and out ports on. In my case I'd have to change it to write a memory location and then do any out instruction which might not be just a byte change, but a disassemble and reassemble, but I don't care so much about ROM BASIC anyway.

author: C
author_rank: Super Contributor
timestamp: February 24, 2018, 03:52:19 am
content: All Z80's I know of can change clock speed and shape of the clock if you stay with in limits of specification.The clock only has to be a square wave at max speed rated for chip.There must not be any runts or false changes.To get max speed from chip it is often better to run the master clock faster and use a FF to drive z80 clock.I saw one system that used a TTL delay line in place of osc for clock source. Advantage was a mux selected the delay line tap for each half clock cycle.You can do I/O using in & out instructions or you can have I/O memory mapped.Dual port memory was often used for I/O. Best if only I/O memory is dual port.You can find static memory in 512k x 8 in dip package also eeprom & flash.I would not waste time with CP/M2 and start with CP/M3 or TURBODOS(runs cp/m2 & 3 programs)For CP/M3 or TURBODOS you want a memory mapperWhen thinking of Flash memory think power-up boot code & rom/ram disk for system.There is a thread that uses a very fast cache ram chip for memory mapping & and one for two wide 74x670.The higher speed the Z80 clock the greater the need for faster memory & the mapper will cost time.If you want a very fast Z80, adj the clock for 0 waits states for normal memory.editYou will find that an attached microcontroller is most likely to slow getting off a direct connection to Z80 bus. Wait states gives time for microcontroller to respond but NOT get off the bus. To get this disconnect time use logic buffer, false DMA or clock modification.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 24, 2018, 10:14:21 am
content: RAM window is interesting if you configure it with bus interfaces to mux between the two devices. You still need a lock (a busy flag on a spare port pin perhaps, or at least hardware WAIT), but other than that, free access to the owner of the buffer is a very nice idea.Downside: you might want to double (or triple) buffer some data. It would be convenient to have individual hardware locks for each shared window. It would also be convenient to have small windows, like 256 bytes each, but you can't get* SRAMs that small (alas, so much waste, but what are you going to do?).*Assumption. Haven't checked. Guessing even if they are available, they're terrifically expensive compared to the average commodity part.Another option might be, find an AVR with parallel bus mode. These are usually old (obsolete?) ones, but it would make it -- well, maybe -- hopefully -- as easy as joining multiple CPUs of any flavor together. Obvious downside: you lose most of the ports.And there's always the classics. Z80-CTC, SIO, PIO. Or 16550, 8255 and such. Main downside: new hardware is loaded with so many more features (and usually speed to boot) than the old crap. Even a dumb ATmega32 has a better ADC than an ADC080x, and for far less external hardware!Tim

author: Benta
author_rank: Super Contributor
timestamp: February 24, 2018, 10:32:37 am
content: How about a dual-port RAM? I'd think it would be excellent for this job. Am I missing something?

author: Ian.M
author_rank: Super Contributor
timestamp: February 24, 2018, 10:43:18 am
content: Many of the Microchip PIC24 range have a parallel bus mode that can act as an addressable slave port. OTOH MPLAB X and the MLA USB stack and mass storage drivers are a real PITA.There's some discussion of what it would take to do Z80 bus-stuffing with an AVR or similar here:https://www.eevblog.com/forum/projects/z80-memory-banking-for-128k-mmu-design/msg1368658/#msg1368658(reply #99 onwards)If you decide to use the AVR as the Z80 clock source so you can go cycle by cycle when the AVR is in control to get the AVR off the bus fast enough at the end of a Z80 memory or I/O read cycle, for normal running, the fastest PWM it can generate is Fosc/4 so that limits you to a max Z80 clock of 4MHz if using an Arduino or 5MHz if using a bare AVR clocked at 20MHz.

author: alank2
author_rank: Super Contributor
timestamp: February 24, 2018, 05:13:23 pm
content: All excellent thoughts guys - thank you and please keep them coming!I don't have any experience with dual port SRAM. The way I am thinking so far (and it may be obvious) is that a single OUT instruction is used to trigger a transaction with the AVR via a BUSREQ cycle. In this way, the AVR only uses cycles the Z80 could be running when it is called upon. I thought that I could make commands that are asynchronous where the Z80 requests something and then goes on to run while the command executes and checks the result later, but it doesn't seem that most commands from CP/M will be structured that way anyway. I am really wanting to design it for CP/M 2.2 and 3.1. Most commands do an I/O and wait for the status of it to complete which I realize is a waste of cycles by modern ways, but the way it was done.Dual port SRAM that the AVR could poll it constantly looking for a command, but is that any better that using an OUT to trigger a transaction with single port SRAM?I plan on having a 128K SRAM with a single bank scheme. Two lower 48K banks that can be swapped and a single 16K upper common memory.

author: C
author_rank: Super Contributor
timestamp: February 24, 2018, 08:41:06 pm
content: First you should really study CP/M3.128k of ram is a crippled CP/M3 system if you want a good system today. It is the very old low cost min to get CP/M3 to just run.Get on digikey or some one like this and look at the cost of a 5v 512k x 8 70ns static ram in a 32 pin dip package.If you have the large size you have a choice of using it or not.Then look at the same but flash or eeprom with software write capability. This can be code you need at power-up and what is left a ROM/slow write system disk that CP/M wants..With 16k blocks the memory mapper can them build the many 48k banks that CP/M3 can manage.It is good to have a memory mapper that can manage more memory then what you plan to use.Four I/O outputs of 8 bits lets you manage the 16k blocks.A 74x273 that can be reset on power-up will give you 8 outputs of which one can be used to enable/disable the memory mapper to get started using one I/O out.Up to 8 512k chips become accessible and area of one chip or more could be dual port ram or access to more processors.As CP/M3 runs almost all CP/M2 programs, today it's a waste of time to even build a CP/M2 bios. Any working CP/M system will allow you to use CP/M3 system build tools to create a CP/M3 system. This includes the many CP/M emulators that run on a PC.The CP/M3 system build tools remove a lot of work to get CP/M3 running or making changes.QuoteYou are thinking microcontroller logic where you have 8 bit port on 8 pins. With microcomputer it is easy to add a FF for written to area or port. Chip select just sets FF.Dual port memory chip is expensive and normally smaller in size. Building a dual port memory is not hard just a lot of chips.You should think of using a 2560 clone board for avr part.Just to set a foundation.CP/M user program,uses 8 bit bytes for I/O and 128 byte blocks for storage I/O.CP/M2 expects system builder to blocking/deblocking code is storage block is not 128 bytes.CP/M3 cleans up a lot of CP/M2's mess and does blocking/deblocking storage and some of software side of memory mapper.TurboDos adds mulit-user using many z80's and networking. Most MP/M & CP.M3 programs will run in addition the many turbodos user programs. Many TurboDos systems were still running long after first PC's.CP/M3 & TurboDos use relocatable modules to build a system. This makes working common & bank code easer.

author: alank2
author_rank: Super Contributor
timestamp: February 24, 2018, 09:24:37 pm
content: Are you sure about CP/M 3.1 using more than 128K? How would you use it? It can only load and run one program at a time, right? Are you thinking about MP/M which I think is more of a multiuser type of thing? I thought the banking of CP/M 3.1 was to increase the TPA by putting some of the OS in a different bank. I've looked through the user manual and it showed banks 0 and 1, and they also had a bank 2 example where you could stick some things like CCP so it wouldn't have to be reloaded from disk, but I didn't see a huge need for memory beyond that design.

author: C
author_rank: Super Contributor
timestamp: February 24, 2018, 11:15:43 pm
content: You have to remember that a CP.M program can have many files open at one time.For each open file some data must be kept. If you do not have space then you have to share space by doing a lot or read-modify-writes to storage. With a lot of space you can hold one block storage size per file open. Then when storage block is large like 4k and CP/M user program is working with 128 byte blocks does one read & up to 32 modifies before writing block back.Remember that a CP/M user program has a limited memory space & temp files are often used to increase space.Think you will find that CP/M3 can manage 16 banks of memory. This does not stop you from having you BIOS manage more memory that CP/M3 does not know about. One more memory area is system disk when you are running a chain of programs.So 16 banks of 48k + 16k common can be managed by CP/M3. The Common can be part TPA and part common Bios.In to old daysEven byte i/o was buffered, program uses buffer at it's rate while interrupt or dma keeps actual I/O device at max speed.Can be a huge time saver.But and there is always a but, it needs to be done properly or you lose chunks of data.Worked and built some fancy systems way back, you have to get it correct and little details matter and also effect total system speed..You need to keep looking at total system while doing small details.For example most systems are limited by memory speed, A system could be faster by lowering CPU clock some to have needed margin with less wait states. Note that a wait state is a block of time wait, a miss of just nano seconds could add a wait block of 50 or 100 ns.The trade is how much time is spent with CPU using internal clock cycles vs time spent with CPU clock cycles for memory access.Back then was nice to say you had a 6M Z80 as if that says something when a slower clock Z80 gets more work done.Only reason to nice clock rate is for software timing loops. How hard is it to multiply 120 Tstates by 50ns vs 53.33ns and this should only be needed in the bios.Start with this1.Cold Reset: a power up reset button that is also triggered by power on.2. Warm Reset: used to restart CP/M to abort a program.3. Break: Soft abort to CP/M program.Could add a bank of switches.A switch that lets a very simple first stage boot loader to select one of two sets of stage two boot code.While testing would be nice to have very simple I/O input and output.An input port to read switches.An output port with leds. This also makes a nice connection to trigger a scope.

author: C
author_rank: Super Contributor
timestamp: February 26, 2018, 09:20:51 pm
content: alank2when building a microprocessor it's all about getting the timing correct with a little margin & glitch free logic.One thing you want to miss is trying to trouble shoot a bad design, A CPU that does random things.A few ns can make a huge difference.Use a spreadsheet with data sheet numbers and look for problems.Trying to run a part out of spec might work or randomly fail.Note that if you use Z80 chips like SIO or PIO they need to be clock speed of Z80. These chips save pins by having internal logic that recreates the missing pins by monitoring Z80 pinsZilog did make some chips with vector interrupt capability that will work with many CPU'sYou could think of a Z80 as slow that gets faster with better/more hardware.Your AVR only can get slower with more software.Keep in mind that there is often many repeated bytes with same value when dealing with I/O.For connection between CPU'sOld time parallel was SCSI & HPIBFor SCSI think of C/D being the 9th bit.Old time serial was HDLC SDLCRead wiki for thisCurrent serial link standard is CANDoing something else requires software and time.

author: alank2
author_rank: Super Contributor
timestamp: February 26, 2018, 10:39:02 pm
content: Thanks for all the info C; I appreciate it. I definitely don't want to be troubleshooting timing issues.

author: C
author_rank: Super Contributor
timestamp: February 26, 2018, 11:43:28 pm
content: Might help to know what you want to learn from a Z80.I Used and built many.from memory one Z80 box had 18 Z80's in it supporting 16 users networked to many boxes and each user could run CP/M programs.down to systems using Z80 where a microcontroller is used today.The other chip you might want to check out is the 68000 & 68010Some called this a minicomputer in a chip.Like Z80 lacks hardware floating point & MMUWas easy to put many 68k's on a bus due to built in hardware & soft.Memory was very expensive back then, the desktop 68k I used had a couple thousand dollars of ram.With a little care you could get many Z80's &or 68k's working together.No good reason to build one for computing power.Might be a surprise how fast a Z80 can work if hardware & software is good.On youtube you can find "Z80-MCB which is a Z80 connected to a Atmega32A and the AVR is the limiter here.To play with Z80 software get a copy of Z80pack for your pc.Keep in mind that a async serial is really a poor connection to a PC. You have to jump through hoops to do things that could be very easy.So what do you want to learn?

author: alank2
author_rank: Super Contributor
timestamp: February 27, 2018, 12:32:59 am
content: Quote from: C on February 26, 2018, 11:43:28 pmI've done quite a bit of development with AVR's so I am familiar with them. Barely touched an STM32 or two. I am intrigued with the Z80 and CPU's in general and want to have a project with it to see what I can get done. I've played around with Grant's FPGA CP/M machine and was messing around with the VHDL a bit. I think CP/M is pretty interesting and am impressed with how you can write a program for it that runs on quite a bit of different hardware because the BIOS is an abstraction layer. I think when they went from control panel machines to "turn key" machines to then next consoles that they made a mistake at the console. I started with a VIC-20 and then had a NEC PC-6001, and I like them, but I don't consider them a progression of something better, but a step backwards!My goal is to build a Z80 SBC that uses an ATMEGA64A to consolidate a lot of things it would need otherwise. It has been done before, but I've got a direction I plan to attempt that I am not sure has been. The issue of the AVR not being able to handle an IN or OUT command looks like it has been tackled in various ways, from using logic to controlling the Z80 clock manually and clocking things in at a slow rate, to using the WAIT line to hold the works up. Instead of that I want to use an OUT command to trigger a BUSREQ and then have the AVR use SRAM to communicate with the Z80 using a window of memory at 0xFFE0-0xFFFF. The Z80 would set a command and parameters it needs for serial comm, disk request, etc., and then use an OUT command to trigger the AVR. It will set a flip flop to enable BUSREQ and after the Z80 finishes the OUT, it will do BUSACK allowing the AVR to read memory, execute the command such as load 128 bytes from SD to memory directly, and then release the BUSREQ by clearing the flipflop. I could skip the OUT all together by triggering off of a write to memory location 0xFFE0, but that would take more decoding and more logic and I'm not sure it is worth the trade off. It would take four 138's instead of a single 138 for example. The OUT can be 0xF0-0xFF and be outing any value, it doesn't matter, its whole purpose would be to trigger the AVR into taking control and checking for a command at 0xFFE0. So my first goal would be to put this hardware together.I'm probably going to just stick to the very simple 128K SRAM because a single 74AHC00 can be used to combine the BANK, A14, and A15 signals into an A16 signal that gives me two lower 48K banks (bank0 and bank1) and a common upper 16K bank. It looks like I could move up to a still fast 512K SRAM if I wanted to make a more complicated MMU, but even then I'm only gaining a 400K ram drive probably because I only plan to run CP/M 2.2 and CP/M plus 3.1 on it. CP/M plus 3.1 should be able to function pretty well with two 48K banks. I'd like to see how much TPA I can come up with as a challenge.I've not done much with Z80 assembly, but I've had experience with other assembly. I'd like to write a CP/M 2.2 BIOS along with CP/M 3.1 banked and non banked BIOS's just to see if I can do it. Once I get that working I want to write some utilities that let you mount and unmount disk images on the microSD as drives A:-D: so you can change disks, etc. In the end I'd like a SMD Z80 SBC that is compact (10x10cm/2layer) with a couple of serial ports that can use RS232 DB9 or USB TTL headers with an FTDI cable.

author: C
author_rank: Super Contributor
timestamp: February 27, 2018, 02:25:50 am
content: Ok first if you do not already have memory, think ahead. You can use 512k chips and just strap the unused inputs to a level.You can think of an MMU as going between CPU & memory. Using a dual row header you can have one side CPU and other Memory. Start with a jumper and add a mmu sometime.Think you will find that when you start adding logic to do 48k banks it can be easer to just do a mmu.Third choice for MMU is to use some latches and a data selector to switch memory.Keep in mind that CP/M3 in banked mode has two parts, banked & common.Unless you write a banked bios for CP/M2 or CP/M3 you will loose more and more TPA space for CP/M programs as drives or storage block size increase. With CP/M3 or CP/M plus as it's sometimes called, CP/M3 does the work for you allowing space needed for storage not be in TPA.CP/M3 is easer to create a bios for if you work with CP/M3 build tools which any CP/M system can run. It was built to make CP/M3 an easy upgrade.So while running CP/M program TPA goes from 0 up to start of CP/M that starts some place in common high.About only reason to put ram buffer between processors in common is if you only have 64k. By AVR using DMA any address can be used if AVR has logic to control address range.Need to remember that Z80 is really the master making requests to AVR. Most times the Z80 will be spinning its wheels waiting for AVR on I/O.As you are thinking a Z80 out is easy way to send a command to AVR. This gives you a byte for command & the fact that Output happened captured by a FF stating new command. This FF could cause an interrupt to AVR. You then have option of AVR doing DMA Req or FF.Would be smart to use a Z80 input to read a status port that part of which is controlled by AVR.You could save the Z80 some time if the AVR could create a vectored interrupt to Z80 to reduce Z80 polling.Keep in mind that the big difference between a microcontroller is that with out added software the connected device does not know that the data has changed on a port.A microprocessor lets you easily write a byte & set a FF at the same time.One problem with a lot of systems is a lack of ports. Much easer if you have a debug port in addition to console port.If you want PC to act like storage then more ports.Think of making your stm32 assuming it has a USB interface into a USB multi port serial I/O. This would let you have many terminal windows.A step up from this is adding USB drive capability.The problem here is the 3.3v logic to connect to 5V logic.Need to remember that standard ardunio serial has no hardware handshake. You play ping pong to control transfer speed or use XON/XOFF and lose 8 bit transparent data capability. With out this the AVR will suffer data overrun unless you slow serial speed a lot to cover all bases.Think it might be cheaper to use a 2650 clone board over the ATMEGA64APull out the manual for CP/M3 and start looking at what is needed for bios, it is much easer to create a bios for then CP/M2.2 & you still have a choice of banked or non-banked.Very simple code compared to CP/M2.2 and more powerful.Many problem areas of CP/M2.2 are handled in a nice way.Doing this you will better understand the data that CP/M needs to work with.After you understand this then work on hardware.Over all idea is good.May have missed something, if so ask.I stared maintaining to many different types of computers. Helped design first Z80 when chip cost $350.Got spoiled with the PDP-11 as it was much better then others.

author: alank2
author_rank: Super Contributor
timestamp: February 27, 2018, 01:38:03 pm
content: Quote from: C on February 27, 2018, 02:25:50 amI'm using a 74HC00 right now and it is working well. I measured the propagation time through both gates and it is around 15ns. I think an AHC one will possibly half that if the datasheet is right. The first NAND is being fed with A14 and A15 and its output is supplying the second NAND along with the BANK signal and its output is feeding A16. The result is:BNK A14 A15 A160 0 0 10 0 1 10 1 0 10 1 1 11 0 0 01 0 1 01 1 0 01 1 1 1So for bank 0 A16 is always 1, bank1 only the lower 48K are set to 0, else back to 1 for the upper 16K common area. CP/M 3 compatible MMU in 2 gates.Quote from: C on February 27, 2018, 02:25:50 amExactly. It will be great when doing a disk I/O because it can transfer an entire 128 byte record a time, but I'd love to think of a way to speed up the character I/O to more than just one character per AVR transaction. Incoming I could just build a buffer and the AVR could bring more than one char in at a time if available and then get character bios function could draw from that until depleted and then ask for more. Outgoing is a bit tougher as I can feed a buffer, but I don't want to wait until it is full because a program might only output 3 chars and expect them to be delivered and then wait for a response. I suppose I could make the AVR do a transaction after a period of inactivity to check for outgoing chars in a buffer but I really don't want to do that.Quote from: C on February 27, 2018, 02:25:50 amI saw that, but haven't looked into it yet.Quote from: C on February 27, 2018, 02:25:50 amIt sounds like I should start with cp/m 3 non banked first.Thanks!!!

author: C
author_rank: Super Contributor
timestamp: February 27, 2018, 02:06:55 pm
content: Will try to make this quickYou can easily build a timer on AVR and have it interrupt the Z80Then Z80 can do some tasks.CP/M3 supports a clockZ80 Timer interrupt could also tell AVR to pick up characters.Note:Storage sector size effects total disk size. Bigger the disk the bigger the sector size.Yes start with CP/M3 and I think you will find that very little time is needed to get to banked mode.