John ... this is absolutely brilliant. I needed to go through this several times, before I understood how it is that you are not throwing away half the SRAM. But now I get it. Thank you.
Once built a system using two 64 kB boards with RAM and a 32 kB EPROM for the startup. The system could swap out the EPROM in the low memory allowing a system using 64 Kb of RAM. CP/M of some early version as well as UCSD Pascal was used. A memory protect was built, making it possible to protect any ram in chunks of 16 bytes I think it was. A real time, multitasking, using priority, preemptive scheduling, time sliced, operating system was built. Those were the days...
John, you wrote to me a while back and I caught up to you the other day about my comments being gone when you went to read them. I think I commented on this video. If I recall, my comment was: Typically, a Z80 address 0x0000 thru 0x0002 is a 'Jump to 16-bit Direct Address' instruction to where the Cold Reset routine starts incase its ROM (program space) is in high or low memory of 64k byte space. Thus in the ZX81 computer (to reduce components), the ROM starts at 0x0000 because it does not copy Flash to RAM for use as its ROM - it runs directly from ROM in its lower bank of memory (only 8K in the ZX81's case) and jumps to the first even address after a copy of the ISR table that is just after that adress 0 Jump instruction. So, to theoretically expand my ZX81 to use 32-bit address space of 64k banks of 64k bytes each: The first 64k (bank 0) looks like the classic ZX81 memory map (the ROM and custom ASIC in the ZX81 expects the screen memory, system variables, keyboard, ASIC registers, ISR vectors, and user RAM to be in a certain places within the Z80 64k space). By using two IO addresses to hold a 16-bit bank number, banks 1 through 65535 can then be selected where RAM can be filled with different copies of program space from Flash/ROM and/or used as data space - the actual memory space not in bank 0 being enabled only if the bank select is non zero. These other banks can even have a copy the 8k ZX81 ROM to each lower 8k of each in these banks, or use bank memory as hadware directly mapped to memory for things like high resolution displays. That should allow me to use it as a standard ZX81, but if I code in a BASIC patch to switch banks, a Flash can then be addressed to copy itself, other Flashes, and the ZX81's ROM to various other banks and then multi-task among them. When going to non-zero banks, I can command the ZX81's ASIC to stop grabbing from memory for the display (called Fast Mode), this can suspend the ZX81 ASIC from being a ZX81 or if I map/copy certain data into the upper banks from bank 0, it could be used as a multi-tasking ZX81 or a multi-tasking generic Z80 system. Does this make sense?
Indeed it does. The Z8S180 supports much of this internally. For example it provides a 3-window memory mapping logic so that a user-defined size of low, middle, and high memory segment can be banked independently. So you can keep a ROM at the bottom & top while banking the middle.
@@JohnsBasement I just looked at the Z8S180 data sheet. The CBR, BBR, and CBAR registers are mapped internally as I/O. The data sheet was not very comprehensive but I got the jist of Common Area 0, Banked Area, and Common Area 2. This CPU can only address 1 MB of memory. My idea was to have 4 GB of memory. I could do that with this CPU but I have to study to see how expanding this to 4k (with my add-on external CPLD based Extension MMU) of 1M banks (along with the tri-space mapping of the internal MMU) would work out. This CPU is faster, lower power, and less noisy than the Z80 - I like it. It also has sync/async serial interfaces, counter/timers, and DMA Controller as well. If they could have only put in a 4K Flash and 4K of SRAM, this could have been a micro controller on steroids (for the time it was introduced). Let me sketch out some full 4GB system memory maps to see if it works to my application. I will get back to you.
@John's Basement OK, there appears to be some typos in the documentation, this doesn't surprise me, as you know, the Z80 family designs were handed over from one company to another over the years, documentation was lost, so it had to be scanned for OCR and lots of scan errors were never corrected. Also the use of terminology is not always consistent. For example for these 3 registers, they use the term "base" and "start" address in different places, which to me are the same (but are they the same for the author?) They also say something like"...is the Common Area 1 Start Address which is the Bank Area prior address." A better way to state that would be, "...is the Common Area 1 Start Address, within 1MB space on a 64KB boundary, which, minus 1, is the top (end/final) Address of the Bank Area." They basically got lazy in some parts of the documentation and just slapped down something to "tick the box", or different sections were written by different people. I have seen this in several places in the Z80 datasheets and documentation. All it takes is one typo and/or a wrong subtle term and things only partially come across correctly, then you have to read other documentation sources to find out what they meant by an "odd man out" analysis. So I should be able put 64k of ROM at the bottom of 1MB space with all other space above it as RAM, then bank that as 64K banks of 64KB to get 4GB of 32-bit address space.... I just have to play with the MMU registers to make sure I am picking up properly what they are saying. Many engineers will do the bare minimum to document their designs because they are lazy when it comes to "un fun" tasks, and they fail to step back and describe things for a wide audience, they often write something that makes sense to them and never look at it from someone else's perspective. I teach my STEM students not to fall into that mindset. Take ownship, be thorough, and have pride in ALL your work, especially documentaion.
The bank select scheme you describe is similar to what is used in DRAM microbees except that microbees can have ROM and video memory overlaid over the DRAM in the upper 32K memory space. Bank selection on an IBM PC is known as Expanded memory which comprised 16K banks with any 4 banks being mapped into the memory address map.
My little brother and I had a scheme to switch the North Star floppy controller (read only) in and out (write to RAM) while still using the high RAM it was sitting on. Later, we had a bit of software that did a multi-function share with two terminals. This worked very well, but there was one carnal rule: “Shalt not share stack!” Was not savable, ID you crashed the system horribly! Normally we have three places we could be: ALS-8 or some other running program, the basic interpreter (later version we could have two basic interpreters going), DOS for a better term. You had to coordinate your need for the disk data. We never got the North Star DOS to share. Note: The North Star floppy controller was a read only device, all data written to the controller was done with memory reads. All this is done on an Altair 8800 and an IMSAI 8080. Seen something like what you are doing in the late 70’s for banking memory, this was for a 16-bit computer system that would run in an IMSAI box (need the power make it work). The most we could get work was about 8 64K bankable memory cards before the poor power supply packed it up.
Loving this series. It brings back many fond memories (my first computer, IMSAI 8080 was Intel 8080 CPU based). The only potential problem bank-switching the lower 32K would be if you wanted to use interrupts or RST instructions as they are fixed into low memory. Also, speaking of waste, rather than tying A16 of the flash ROM low, maybe add a pull-up and a jumper to allow quick way to have 2 versions of your ROM BIOS.
Ah! The good 'ol days! As for the choice of banking the low memory region... I did it to make it match the requirements for CP/M 3. And since I'm using a Z80 running in Interrupt mode 2, the low-page restart-vectors are not really meaningful as they are on an 8080. I too am less than thrilled about wasting 1/2 of the FLASH. I could add the jumper you suggest.... probably SHOULD in fact... I'll add it to the github list of issues on Rev 3 right now. HOWEVER, if you use the in-circuit FLASH programmer (that I talk about in upcoming videos and absolutely LOVE using in contrast to pulling the chip to use a bench programmer all the time while debugging code), you won't be able to program the high-bank because you can't when A16 tied high. BUT that is absolutely NO reason to stop anyone with a stand-alone programmer to use it as you suggest.
@@JohnsBasement I haven't downloaded the Github repo yet (no spoilers), but I recall that you have a 40 pin header for onboard flash programming that's a mirror of the CPU. Could you repurpose a pin, perhaps Vcc, to allow A16 to be controlled by the RPi? As long as you drive it with an OC gate.
@@mikescott58I definitely use Vcc. So something else could go... Or I cut over to a bigger header. But the general idea isn't bad. By time this project is done it might be useful to look at changing the flash interface so that can become part of the set of memory banks.
because i want to pimp an atari 2600, i will go with a 6502 compatible device, the 65816, which has 24 bits of address bits. this way i don't need a bank switching for 512kB of RAM. however, if i want to have a minimum system, the runs with the 6507 or a 6502, i need that kind of bank switching as well. at some point i want to have a Z80 core inside as well, just for the fun of exploring CP/M stuff. however, i am glad that an affordable static ram like the AS6C4008-55PCN exist. and everything in through hole components. retro computing never was that cool and affordable. thanks for the inspiration!
This would have been revolutionary in 1982, and in fact the Trs-80 model 4 supported 128k using a similar scheme of switching 32kb banks, but pretty much useless in a 64-bit world.
I am working on my own design right now, and will use a eZ80 in z80 mode for it. I have been thinking about the paging for days now, and i settled for 4 pages of 16k each. I was thinking about using 8x8k pages, because 8k is plenty for a boot rom. But that would mean using 8 latches instead of 4. Another factor in my considerations was, MSX used 16k pages. And i would really like to be able to make my computer MSX compatible. But the most important was this: I want to have one bank with the OS in it. And i want to be able to use diffrent banks in my programs. So i need more than 2 pages. For example i could have one bank for the OS, one bank with a game, and the game could then switch the remaining 2 banks for loading level data or something like that.
Re-read the details on how the MMU works on the EZ80. Unless you do the memory banking externally, it isn't going to help you with this plan. Consider looking at the Z8S180 before you go much further.
@@JohnsBasement I know, the eZ80 has internal mechanisms for all that. It can even generate chip select signals with diffrent wait states and all that. But i want to do the paging externally anyway. My design goals for this project include not using any genuine retro parts. While i love the old stuff, i think the original chips are best left as spares to keep original hardware running. That is why i want to use the eZ80. And i found a github with the source files for a MSX-on-a-chip system. That includes VHDL sources for FPGA implementations of the VDP and all the sound chips of the MSX standard, up to MSX Turbo R. I will strip that down from a SoC to just the VDP/Sound Chips in an FPGA, combine that with the eZ80, and build the whole banking logic from 74xxx parts. I am even thinking about implementing a PS/2 port with actual shift registers, not bit-banging. Or use a MCU to provide USB ports for KB/mouse and maybe joypads. Already found a probable solution for that using PIC chips. But i just started using KiCad, so i will need more time to get used to that. And then i have to do some experiments with the laser engraver at work, because i want to use that to make the prototype PCBs.
It sounds like you are going to have a TON of fun with all this! I have been looking at expanding the Retro by adding more peripherals like PS2 ports, SNES controllers, and an upgraded video interface with VGA output. Keep us posted on your progress! I am eager to see how it goes!
@@JohnsBasement I really hope that despite the different design goals, i can contribute something to your project. Since you gave me the final inspiration and a lot of knowledge to start my own.
Is there any reason you couldn't have the low addresses stay static and have the high addresses be the switchable banks? I'm just wondering if that is mostly just a personal preference or slightly simpler logic, or if there is an architectural reason why that would be a bad idea.
Switching the hi-bank would require an inverter on A15. So it is simpler. I never considered switching the hi-bank because I planned for CP/M to run my BIOS from high addresses and need to change banks when it is running!
I understand how the bank selection works. However, could an MMU have been used with additional functionality? I have not been able to find an external MMU from DigiKey. Do you know of a compatible part and where it is available?
🤔. MMUs tend to be CPU specific. I know of none for the Z80 except for the built in ones on the EZ80 or the Z8S180. Some folks use PALs or CPLDs to make one. I'm getting ready to do one in an FPGA.
Yes, you can swap banks, but how do you run code in it and write it? The Research Machines 380Z and 480Z had a more sophisticated system in 1980. They had memory PAGES each of which was a complex combination of RAM and ROM. This enabled common memory between pages and system ROM and RAM to be hidden from the main Page 1 user TPA. Networking firmware and buffers were on Page 0 along with startup code and BASIC in ROM and HRG video RAM were located on other Pages. If you just want more memory why don't you use a Z180 (or Z181 or Z182) and get a MMU for free and be able to turn Refresh cycles off to run Z80 code faster?
I've only used the alternate banks for data so far. But running code out of it is a matter of copying it in and jumping to it from the high half of ram.
@@JohnsBasement Yes, you can do that, but what I'm talking about is having system software in hidden ROM on one Page that can be called from any Page and will return to that Page. That's a whole different level of sophistication with stack management and interrupts going on. Just copying blocks of code from ROM to RAM is a waste of RAM. We did copy vectors into the Restart addresses, RST 48 was an EMT function (like Emulated Transfer on a PDP11) and the following byte was a number to call different system functions. Storing code in positions in ROM that executes at another address can get mind bending, but I had utilities to do that. (There are some Mac MPW ones available on my website.) This is also needed for Z180 and family which has 1M of address space, but only runs in 64K Z80 space.
(I thought I replied to this, but do not see it here now...) On my Retro design, you'd have to use a trampoline in the high-bank to select the target bank and enter the requested function and then switch the bank back and return. For IRQs, I figure I'd just keep identical copies of the low-memory vector tables in every bank with pointers into handlers that reside in the high-bank. Not optimal. But within reach with the $2 bank-select design on the Retro board. With more hardware, you can simplify the code but you'd likely still have to deal with keeping the stack(s) in a safe area (or switch to a new one and back again) when switching banks to make subroutine calls.
@@JohnsBasement If you are building a general purpose commercial computer to run CP/M (which I was 45 years ago) you have to provide RAM from the bottom up, but you have to boot with ROM at the bottom and move it to near the top. The TPA starts at 100h and you don't know what a user program will do so there have to be some rules and robust context saving. We had the stack at the top and system scratchpad below that. If a user makes a system call you have to assume that there is no stack left and switch to a private one. If you have 64K RAM then there are unused blocks were the ROM goes, we decided to use all of it plus more ROMs while maximising the TPA for the user. Most of the Z80/Z180 work I have done since has been standalone devices where all the software is mine and I don't have to accommodate unknown users. I'm normally trying to get maximum performance out of high speed serial interfaces, like running six interrupt driven channels of Z80-SIO or Z8530s and having a 16K RAM buffer on each. There is a lot of information about the 380Z and 480Z on the Research Machines Users Forum. You may find some of the system manuals and schematics interesting.
It depends on the mode you use. I plan on using mode 2 with the vectors in high memory. The NMI is still problematic though. If you want to swap banks haphazardly, you'll have to copy any IRQ vector tables into each bank. You'll also have to be careful about where the stack is.
@@JohnsBasement Yep. The NMI will be tricky. About the stack, if the RAM bank switching is tied to application switching, you can use the same kind of strategy used in multi tasking kernels. Switch the stack pointer when switching RAM pages. Of course you would need some kind of application descriptor under OS control, in the top RAM bank.
@@akkudakkupl RST instructions, yes. /IRQ interrupts?... that depends on the mode that you enable. The Retro board uses mode 2, so the IRQ vector table can be placed anywhere. When I decided how to implement the bank select for the Retro board I used CP/M 3 as a guide how to make it work so it would be compatible. (It changes the low-half.) Want to bank-select the high-half of the address space?... then replace U13 with a 74HC08! 😀
I like what you have done but I am concerned that you are limiting the TPA to 32k out of the 64k of memory. I was rolling something around in my head and I was wondering, what if you switched 64k banks. Each bank would be a stand alone system. You might have CP/M 2.2 in Bank 0, CP/M 3.0 in Bank 1, spread sheet in Bank 2, etc. There are some gaps here but ...
I couldn't see how to do any better with the real estate that I had to work with without resorting to a PAL. 64K banks seem impossible without a way to copy memory or switch between them. Since CP/M 2.2 was the most popular version, I'm thinking I may stick with it and use the spare banks to hold a disk cache. I expect to have to host a bounce buffer in the BIOS region and let the TPA run up to 58K or so. See the mem map diagram in my github CP/M repo showing the TPA spanning vanks 0 and 15. Else I could remove the printer port & see if that frees enough space for 48K bank decoding logic?
They can be. If you do, you'd have to be pretty careful about switching the banks! I do not expect to have a stack in use under the 32K line when I'm switching them around. Avoiding stacks in the bottom 32K during a switch solves the easy problem. A related problem will be what happens if you ever want to switch the banks from within an interrupt handler? Being very careful about the order of operations and using the occasional interrupt-disabled critical regions would do it... but it could be error-prone and tough to validate. First draft: 1) No stacks in low-32K when changing the memory banks and 2) never, EVER, touch the GPIO output latch in an IRQ handler!!!! Note to send back to myself if I ever invent a time-machine: Don't put the printer, SD card and memory bank control bits all into one un-readable output port latch!! ;-)
@@JohnsBasement - I was wondering about that last issue during the video! Separate parts of SW will have to access that I/O byte at different times. Since you have to write the whole byte and not a bit at a time, whatever gets set as a page number can be easily overwritten by accessing the SD card or printer. What do you do about it?
@@abqlewis Good question! I keep a copy of the value last written to that output port saved in memory and then and/or values into it every time I update the port value. It is unfortunate that I don't have space for another latch in this design because, as it is, I am not going to be able to (efficiently) let an IRQ handler change the memory bank value. Alas, that is one of the sacrifices I decided to make in order to satisfy all the other wants and needs of this all discrete, all through-hole design (that is if you use an add-on board or the SD card like I showed int he first part of this series.)
😂.... Noone noticed till now! 🤣 Ya know? My handwriting is bad enough I'm gonna claim it says .512MB but the . is part of that visual noise to the left of the 5. 😁
I wanted an all thru-hole option for building the board. Otherwise it might... depending on how you want to share the memory regions. The MMU on the EZ80 is pretty anemic. Even so, we'd want the newer versions of the EZ80... that have been listed as unavailable until 2023. (The first wave of the EZ80 has a pretty big errata sheet.) So, realistically, right now, not really.
@@joefish6091 Hmmm... I need to go back and have a closer look at the Z8S180. The S180's mmu is better suited to what I'm doing than the one in the EZ80. ..and they are not out of stock!
@ADN. That is a style of teaching to which I also subscribe. I teach Summer STEM at home (for free), and since I too have a wide audience (kindergarten to 12th grade in the same class in my case) I find it helpful to explain new concepts several ways at first to "spin" the same concepts to find which way sticks the most. I made a Student Polling System that gives me real-time feedback to let me know if they are following me or not. If I see too many red lights, I can re-spin my lecture in real-time to get more green lights. And then work with the others later. In fact, John and I must be "Born Enginneers", we are like brothers from another mother. Look at how I explain to make very low cost front panels for prjects... we even have the same hand guestures.
@@estring69 Yes, but repeated rundundant statements reiterated over and over again to rephrase similar points in a familiar fashion with many recursive references to prior statements should be avoided.
John ... this is absolutely brilliant.
I needed to go through this several times, before I understood how it is that you are not throwing away half the SRAM. But now I get it. Thank you.
😀👍
Very interesting way to get beyond 64k with the z80, very cool!
I enjoyed watching this video. I used to have an Osborne Executive CP/M computer in 1983.
Waaay too rich for my blood!!
Those luggables back then were absolutely groundbreaking!
Once built a system using two 64 kB boards with RAM and a 32 kB EPROM for the startup. The system could swap out the EPROM in the low memory allowing a system using 64 Kb of RAM. CP/M of some early version as well as UCSD Pascal was used.
A memory protect was built, making it possible to protect any ram in chunks of 16 bytes I think it was.
A real time, multitasking, using priority, preemptive scheduling, time sliced, operating system was built. Those were the days...
Holy smoke! Cool!
@@JohnsBasement Thanks. Yes, it was a beast but I unfortunately scrapped it a long time ago. Pc.... Regretting it now.
Excellent explaination of bank switching
Thanks for the positive review!
John, you wrote to me a while back and I caught up to you the other day about my comments being gone when you went to read them. I think I commented on this video. If I recall, my comment was:
Typically, a Z80 address 0x0000 thru 0x0002 is a 'Jump to 16-bit Direct Address' instruction to where the Cold Reset routine starts incase its ROM (program space) is in high or low memory of 64k byte space. Thus in the ZX81 computer (to reduce components), the ROM starts at 0x0000 because it does not copy Flash to RAM for use as its ROM - it runs directly from ROM in its lower bank of memory (only 8K in the ZX81's case) and jumps to the first even address after a copy of the ISR table that is just after that adress 0 Jump instruction. So, to theoretically expand my ZX81 to use 32-bit address space of 64k banks of 64k bytes each: The first 64k (bank 0) looks like the classic ZX81 memory map (the ROM and custom ASIC in the ZX81 expects the screen memory, system variables, keyboard, ASIC registers, ISR vectors, and user RAM to be in a certain places within the Z80 64k space). By using two IO addresses to hold a 16-bit bank number, banks 1 through 65535 can then be selected where RAM can be filled with different copies of program space from Flash/ROM and/or used as data space - the actual memory space not in bank 0 being enabled only if the bank select is non zero. These other banks can even have a copy the 8k ZX81 ROM to each lower 8k of each in these banks, or use bank memory as hadware directly mapped to memory for things like high resolution displays. That should allow me to use it as a standard ZX81, but if I code in a BASIC patch to switch banks, a Flash can then be addressed to copy itself, other Flashes, and the ZX81's ROM to various other banks and then multi-task among them. When going to non-zero banks, I can command the ZX81's ASIC to stop grabbing from memory for the display (called Fast Mode), this can suspend the ZX81 ASIC from being a ZX81 or if I map/copy certain data into the upper banks from bank 0, it could be used as a multi-tasking ZX81 or a multi-tasking generic Z80 system.
Does this make sense?
Indeed it does. The Z8S180 supports much of this internally. For example it provides a 3-window memory mapping logic so that a user-defined size of low, middle, and high memory segment can be banked independently. So you can keep a ROM at the bottom & top while banking the middle.
@@JohnsBasementOh, a Z8S180 does that. I was thinking to make my own CPLD for address mapping. I have to bone up on the Z80 chip sets. Thanks.
@@paulromsky9527 Yes. It does. I have been excited about digging into one for a while myself. If you try one, please let us know how it goes!
@@JohnsBasement I just looked at the Z8S180 data sheet. The CBR, BBR, and CBAR registers are mapped internally as I/O. The data sheet was not very comprehensive but I got the jist of Common Area 0, Banked Area, and Common Area 2. This CPU can only address 1 MB of memory. My idea was to have 4 GB of memory. I could do that with this CPU but I have to study to see how expanding this to 4k (with my add-on external CPLD based Extension MMU) of 1M banks (along with the tri-space mapping of the internal MMU) would work out. This CPU is faster, lower power, and less noisy than the Z80 - I like it. It also has sync/async serial interfaces, counter/timers, and DMA Controller as well. If they could have only put in a 4K Flash and 4K of SRAM, this could have been a micro controller on steroids (for the time it was introduced). Let me sketch out some full 4GB system memory maps to see if it works to my application. I will get back to you.
@John's Basement OK, there appears to be some typos in the documentation, this doesn't surprise me, as you know, the Z80 family designs were handed over from one company to another over the years, documentation was lost, so it had to be scanned for OCR and lots of scan errors were never corrected. Also the use of terminology is not always consistent. For example for these 3 registers, they use the term "base" and "start" address in different places, which to me are the same (but are they the same for the author?) They also say something like"...is the Common Area 1 Start Address which is the Bank Area prior address." A better way to state that would be, "...is the Common Area 1 Start Address, within 1MB space on a 64KB boundary, which, minus 1, is the top (end/final) Address of the Bank Area." They basically got lazy in some parts of the documentation and just slapped down something to "tick the box", or different sections were written by different people. I have seen this in several places in the Z80 datasheets and documentation. All it takes is one typo and/or a wrong subtle term and things only partially come across correctly, then you have to read other documentation sources to find out what they meant by an "odd man out" analysis. So I should be able put 64k of ROM at the bottom of 1MB space with all other space above it as RAM, then bank that as 64K banks of 64KB to get 4GB of 32-bit address space.... I just have to play with the MMU registers to make sure I am picking up properly what they are saying.
Many engineers will do the bare minimum to document their designs because they are lazy when it comes to "un fun" tasks, and they fail to step back and describe things for a wide audience, they often write something that makes sense to them and never look at it from someone else's perspective. I teach my STEM students not to fall into that mindset. Take ownship, be thorough, and have pride in ALL your work, especially documentaion.
Thank you a lot John for this explanation. This is the solution I need for my own system.
Glad I could help!
The bank select scheme you describe is similar to what is used in DRAM microbees except that microbees can have ROM and video memory overlaid over the DRAM in the upper 32K memory space. Bank selection on an IBM PC is known as Expanded memory which comprised 16K banks with any 4 banks being mapped into the memory address map.
It is also compatible with what I believe is needed to run CP/M 3. 😉
Thanks for this video. I've always wondered how this was done. Perfect explanation.
Thanks! Glad you like it!
My little brother and I had a scheme to switch the North Star floppy controller (read only) in and out (write to RAM) while still using the high RAM it was sitting on. Later, we had a bit of software that did a multi-function share with two terminals. This worked very well, but there was one carnal rule: “Shalt not share stack!” Was not savable, ID you crashed the system horribly! Normally we have three places we could be: ALS-8 or some other running program, the basic interpreter (later version we could have two basic interpreters going), DOS for a better term. You had to coordinate your need for the disk data. We never got the North Star DOS to share. Note: The North Star floppy controller was a read only device, all data written to the controller was done with memory reads. All this is done on an Altair 8800 and an IMSAI 8080. Seen something like what you are doing in the late 70’s for banking memory, this was for a 16-bit computer system that would run in an IMSAI box (need the power make it work). The most we could get work was about 8 64K bankable memory cards before the poor power supply packed it up.
Loving this series. It brings back many fond memories (my first computer, IMSAI 8080 was Intel 8080 CPU based).
The only potential problem bank-switching the lower 32K would be if you wanted to use interrupts or RST instructions as they are fixed into low memory.
Also, speaking of waste, rather than tying A16 of the flash ROM low, maybe add a pull-up and a jumper to allow quick way to have 2 versions of your ROM BIOS.
Ah! The good 'ol days!
As for the choice of banking the low memory region... I did it to make it match the requirements for CP/M 3. And since I'm using a Z80 running in Interrupt mode 2, the low-page restart-vectors are not really meaningful as they are on an 8080.
I too am less than thrilled about wasting 1/2 of the FLASH. I could add the jumper you suggest.... probably SHOULD in fact... I'll add it to the github list of issues on Rev 3 right now.
HOWEVER, if you use the in-circuit FLASH programmer (that I talk about in upcoming videos and absolutely LOVE using in contrast to pulling the chip to use a bench programmer all the time while debugging code), you won't be able to program the high-bank because you can't when A16 tied high. BUT that is absolutely NO reason to stop anyone with a stand-alone programmer to use it as you suggest.
@@JohnsBasement I haven't downloaded the Github repo yet (no spoilers), but I recall that you have a 40 pin header for onboard flash programming that's a mirror of the CPU. Could you repurpose a pin, perhaps Vcc, to allow A16 to be controlled by the RPi? As long as you drive it with an OC gate.
@@mikescott58I definitely use Vcc. So something else could go... Or I cut over to a bigger header. But the general idea isn't bad.
By time this project is done it might be useful to look at changing the flash interface so that can become part of the set of memory banks.
Excellent John! Very instructive! Regards, RJM
Thanks for such a positive review!
Another great video, thanks John!
Thank you very much! For some reason, I found it tough to get this one togeather. Comments like this make my day! 😀
because i want to pimp an atari 2600, i will go with a 6502 compatible device, the 65816, which has 24 bits of address bits. this way i don't need a bank switching for 512kB of RAM.
however, if i want to have a minimum system, the runs with the 6507 or a 6502, i need that kind of bank switching as well.
at some point i want to have a Z80 core inside as well, just for the fun of exploring CP/M stuff.
however, i am glad that an affordable static ram like the AS6C4008-55PCN exist. and everything in through hole components. retro computing never was that cool and affordable.
thanks for the inspiration!
Thanks... and same to you! Comments like this are good fodder for the idea stew that drives all of our future projects!
Gary Kildall would be proud!
😂👍
This would have been revolutionary in 1982, and in fact the Trs-80 model 4 supported 128k using a similar scheme of switching 32kb banks, but pretty much useless in a 64-bit world.
It may well have also cost $8000! 😂
Very good Job.
Thanks!
I am working on my own design right now, and will use a eZ80 in z80 mode for it. I have been thinking about the paging for days now, and i settled for 4 pages of 16k each. I was thinking about using 8x8k pages, because 8k is plenty for a boot rom. But that would mean using 8 latches instead of 4. Another factor in my considerations was, MSX used 16k pages. And i would really like to be able to make my computer MSX compatible.
But the most important was this: I want to have one bank with the OS in it. And i want to be able to use diffrent banks in my programs. So i need more than 2 pages. For example i could have one bank for the OS, one bank with a game, and the game could then switch the remaining 2 banks for loading level data or something like that.
Re-read the details on how the MMU works on the EZ80. Unless you do the memory banking externally, it isn't going to help you with this plan.
Consider looking at the Z8S180 before you go much further.
@@JohnsBasement I know, the eZ80 has internal mechanisms for all that. It can even generate chip select signals with diffrent wait states and all that. But i want to do the paging externally anyway.
My design goals for this project include not using any genuine retro parts. While i love the old stuff, i think the original chips are best left as spares to keep original hardware running.
That is why i want to use the eZ80. And i found a github with the source files for a MSX-on-a-chip system. That includes VHDL sources for FPGA implementations of the VDP and all the sound chips of the MSX standard, up to MSX Turbo R. I will strip that down from a SoC to just the VDP/Sound Chips in an FPGA, combine that with the eZ80, and build the whole banking logic from 74xxx parts.
I am even thinking about implementing a PS/2 port with actual shift registers, not bit-banging. Or use a MCU to provide USB ports for KB/mouse and maybe joypads. Already found a probable solution for that using PIC chips.
But i just started using KiCad, so i will need more time to get used to that. And then i have to do some experiments with the laser engraver at work, because i want to use that to make the prototype PCBs.
It sounds like you are going to have a TON of fun with all this! I have been looking at expanding the Retro by adding more peripherals like PS2 ports, SNES controllers, and an upgraded video interface with VGA output.
Keep us posted on your progress! I am eager to see how it goes!
@@JohnsBasement I really hope that despite the different design goals, i can contribute something to your project. Since you gave me the final inspiration and a lot of knowledge to start my own.
@@TSteffi Such kind words! Thanks!
Is there any reason you couldn't have the low addresses stay static and have the high addresses be the switchable banks? I'm just wondering if that is mostly just a personal preference or slightly simpler logic, or if there is an architectural reason why that would be a bad idea.
Switching the hi-bank would require an inverter on A15. So it is simpler.
I never considered switching the hi-bank because I planned for CP/M to run my BIOS from high addresses and need to change banks when it is running!
I understand how the bank selection works. However, could an MMU have been used with additional functionality?
I have not been able to find an external MMU from DigiKey. Do you know of a compatible part and where it is available?
🤔. MMUs tend to be CPU specific. I know of none for the Z80 except for the built in ones on the EZ80 or the Z8S180.
Some folks use PALs or CPLDs to make one. I'm getting ready to do one in an FPGA.
Yes, you can swap banks, but how do you run code in it and write it?
The Research Machines 380Z and 480Z had a more sophisticated system in 1980. They had memory PAGES each of which was a complex combination of RAM and ROM. This enabled common memory between pages and system ROM and RAM to be hidden from the main Page 1 user TPA. Networking firmware and buffers were on Page 0 along with startup code and BASIC in ROM and HRG video RAM were located on other Pages.
If you just want more memory why don't you use a Z180 (or Z181 or Z182) and get a MMU for free and be able to turn Refresh cycles off to run Z80 code faster?
I've only used the alternate banks for data so far. But running code out of it is a matter of copying it in and jumping to it from the high half of ram.
@@JohnsBasement Yes, you can do that, but what I'm talking about is having system software in hidden ROM on one Page that can be called from any Page and will return to that Page. That's a whole different level of sophistication with stack management and interrupts going on.
Just copying blocks of code from ROM to RAM is a waste of RAM. We did copy vectors into the Restart addresses, RST 48 was an EMT function (like Emulated Transfer on a PDP11) and the following byte was a number to call different system functions.
Storing code in positions in ROM that executes at another address can get mind bending, but I had utilities to do that. (There are some Mac MPW ones available on my website.) This is also needed for Z180 and family which has 1M of address space, but only runs in 64K Z80 space.
(I thought I replied to this, but do not see it here now...) On my Retro design, you'd have to use a trampoline in the high-bank to select the target bank and enter the requested function and then switch the bank back and return.
For IRQs, I figure I'd just keep identical copies of the low-memory vector tables in every bank with pointers into handlers that reside in the high-bank. Not optimal. But within reach with the $2 bank-select design on the Retro board. With more hardware, you can simplify the code but you'd likely still have to deal with keeping the stack(s) in a safe area (or switch to a new one and back again) when switching banks to make subroutine calls.
@@JohnsBasement If you are building a general purpose commercial computer to run CP/M (which I was 45 years ago) you have to provide RAM from the bottom up, but you have to boot with ROM at the bottom and move it to near the top. The TPA starts at 100h and you don't know what a user program will do so there have to be some rules and robust context saving. We had the stack at the top and system scratchpad below that. If a user makes a system call you have to assume that there is no stack left and switch to a private one. If you have 64K RAM then there are unused blocks were the ROM goes, we decided to use all of it plus more ROMs while maximising the TPA for the user. Most of the Z80/Z180 work I have done since has been standalone devices where all the software is mine and I don't have to accommodate unknown users. I'm normally trying to get maximum performance out of high speed serial interfaces, like running six interrupt driven channels of Z80-SIO or Z8530s and having a 16K RAM buffer on each.
There is a lot of information about the 380Z and 480Z on the Research Machines Users Forum. You may find some of the system manuals and schematics interesting.
@@hintoninstruments2369 This all sounds right. My choices on how I use this board are discussed the next 40 or so videos in this series. 😇
Hi
By switching the low 32K of RAM, doesn't one risk having problems handling interrupts?
It depends on the mode you use. I plan on using mode 2 with the vectors in high memory. The NMI is still problematic though.
If you want to swap banks haphazardly, you'll have to copy any IRQ vector tables into each bank. You'll also have to be careful about where the stack is.
@@JohnsBasement
Yep.
The NMI will be tricky.
About the stack, if the RAM bank switching is tied to application switching, you can use the same kind of strategy used in multi tasking kernels. Switch the stack pointer when switching RAM pages.
Of course you would need some kind of application descriptor under OS control, in the top RAM bank.
Wouldn't it be better to have the first 32k of RAM be always available when A15 is low and access the banks with A15 high?
You are going to have to define 'better'
@@JohnsBasement Ah, I meant better in ease of coding.
From what I read Z80 has interrupt vectors and other things in low memory?
@@akkudakkupl RST instructions, yes. /IRQ interrupts?... that depends on the mode that you enable.
The Retro board uses mode 2, so the IRQ vector table can be placed anywhere.
When I decided how to implement the bank select for the Retro board I used CP/M 3 as a guide how to make it work so it would be compatible. (It changes the low-half.)
Want to bank-select the high-half of the address space?... then replace U13 with a 74HC08! 😀
I like what you have done but I am concerned that you are limiting the TPA to 32k out of the 64k of memory. I was rolling something around in my head and I was wondering, what if you switched 64k banks. Each bank would be a stand alone system. You might have CP/M 2.2 in Bank 0, CP/M 3.0 in Bank 1, spread sheet in Bank 2, etc.
There are some gaps here but ...
I couldn't see how to do any better with the real estate that I had to work with without resorting to a PAL.
64K banks seem impossible without a way to copy memory or switch between them.
Since CP/M 2.2 was the most popular version, I'm thinking I may stick with it and use the spare banks to hold a disk cache. I expect to have to host a bounce buffer in the BIOS region and let the TPA run up to 58K or so. See the mem map diagram in my github CP/M repo showing the TPA spanning vanks 0 and 15.
Else I could remove the printer port & see if that frees enough space for 48K bank decoding logic?
What about the stack and registers. Are they going to be located n the lower 23k ram space?
They can be. If you do, you'd have to be pretty careful about switching the banks!
I do not expect to have a stack in use under the 32K line when I'm switching them around.
Avoiding stacks in the bottom 32K during a switch solves the easy problem.
A related problem will be what happens if you ever want to switch the banks from within an interrupt handler?
Being very careful about the order of operations and using the occasional interrupt-disabled critical regions would do it... but it could be error-prone and tough to validate.
First draft: 1) No stacks in low-32K when changing the memory banks and 2) never, EVER, touch the GPIO output latch in an IRQ handler!!!!
Note to send back to myself if I ever invent a time-machine: Don't put the printer, SD card and memory bank control bits all into one un-readable output port latch!! ;-)
@@JohnsBasement - I was wondering about that last issue during the video! Separate parts of SW will have to access that I/O byte at different times. Since you have to write the whole byte and not a bit at a time, whatever gets set as a page number can be easily overwritten by accessing the SD card or printer. What do you do about it?
@@abqlewis Good question! I keep a copy of the value last written to that output port saved in memory and then and/or values into it every time I update the port value.
It is unfortunate that I don't have space for another latch in this design because, as it is, I am not going to be able to (efficiently) let an IRQ handler change the memory bank value. Alas, that is one of the sacrifices I decided to make in order to satisfy all the other wants and needs of this all discrete, all through-hole design (that is if you use an add-on board or the SD card like I showed int he first part of this series.)
The memory diagram says "512MB SRAM"
Lol
😂.... Noone noticed till now! 🤣
Ya know? My handwriting is bad enough I'm gonna claim it says .512MB but the . is part of that visual noise to the left of the 5. 😁
Wouldn't this be much easier on an eZ80?
I wanted an all thru-hole option for building the board. Otherwise it might... depending on how you want to share the memory regions. The MMU on the EZ80 is pretty anemic.
Even so, we'd want the newer versions of the EZ80... that have been listed as unavailable until 2023. (The first wave of the EZ80 has a pretty big errata sheet.)
So, realistically, right now, not really.
Z8S180 or HD64180
@@joefish6091 Hmmm... I need to go back and have a closer look at the Z8S180. The S180's mmu is better suited to what I'm doing than the one in the EZ80. ..and they are not out of stock!
Thanks but way too much repetitive, saying the same thing over and over again in the first half of the video!
Sometimes, not always, but sometimes, that happens.
@ADN. That is a style of teaching to which I also subscribe. I teach Summer STEM at home (for free), and since I too have a wide audience (kindergarten to 12th grade in the same class in my case) I find it helpful to explain new concepts several ways at first to "spin" the same concepts to find which way sticks the most. I made a Student Polling System that gives me real-time feedback to let me know if they are following me or not. If I see too many red lights, I can re-spin my lecture in real-time to get more green lights. And then work with the others later. In fact, John and I must be "Born Enginneers", we are like brothers from another mother. Look at how I explain to make very low cost front panels for prjects... we even have the same hand guestures.
Repetitive flag is tripped yes, but it is good for those of us who know none of this.
@@estring69 Yes, but repeated rundundant statements reiterated over and over again to rephrase similar points in a familiar fashion with many recursive references to prior statements should be avoided.