Z80 bank-switching using IORQ - Page 1
Forum section: electronics / beginners

author: nockieboy
author_rank: Super Contributor
timestamp: January 29, 2017, 03:07:30 pm
content: Hi everyone,Disclaimer: Not sure this post is in the right area (Beginners), but I AM a beginner when it comes to electronics, so here goes...I'm designing a Z80 microcomputer, based off of Grant Searle's designhttp://searle.hostei.com/grant/z80/SimpleZ80.html, but with a few refinements of my own including address, data and control bus buffering, 40-pin expansion port etc.I'm using an AS6C1008-55 128K SRAM for the memory alongside an AT27C512R 64K OTP-ROM.I've already designed switchable 8K banks for the ROM using a switch, so multiple versions of monitoring programs can be used and switched between whilst the computer is off. The ROM takes up 0000-1FFF address space, with the remaining 56K being available as RAM.What I would like to do now is switch the RAM via A16 on the SRAM chip which is beyond the 16-bit address bus of the Z80. This would, in effect, give the computer 2 banks of 56K RAM to work with (once the lower 8K for the ROM is taken into account.) It'd be easy to do this via a switch like with the ROM, but I want to do something a little neater and do it in software.I've searched for information via the old Amstrad CPC464/6128 schematics, but they're confusing enough for my inexperienced mind with all the switching that's done on the banks of old 8K chips they used.The best (only) way I can think to do it is to use the IO in a similar way to how Grant Searle does it with the 68B50 in the serial interface. That's pretty much as far as I've got, however. Oh, and this schematic:The circuit isn't complete there, obviously I haven't connected up LE or MR as I'm not too sure how to wire them up. IC2.6 and 6.4 are leftovers from other chips that I thought I'd see if I could get to work, but with the addition of the latch I'm not even sure I need them. Also, I know I need another inverter after the AND gate to make it go high with high inputs... but I'm not sure about the logic here at all anyway..To be honest, I'm fumbling in the dark. I'd like to be able to wire it so that an IO can be addressed on, say, port 70H which will switch the RAM to the upper 64K by making A16 go high, and making it low again by setting port (e.g.) 70H low. That way I could create a command in the monitor program so I could switch between the banks with a |BANK,0 or |BANK,1 command, or similar. The signal is latched via the 74HCT259 (is that overkill?)I'm rambling now anyway...Any help and guidance would be appreciated!!Thanks,Jon

author: Ian.M
author_rank: Super Contributor
timestamp: January 29, 2017, 03:50:18 pm
content: If you switch the whole RAM, its close to being useless as the only way of getting data from one half to the other is to 'hand carry' it via a CPU register + it smashes the stack so you cant use subroutines. Instead you need to either keep an area of RAM unswitched so the stack and important variables can be accessed with either bank selected, or you need to break up the banked memory into smaller pages so the physical page that currently holds the stack can be left paged in while other pages are being swapped.Seehttps://www.eevblog.com/forum/microcontrollers/retro-z80-project-memory-layout-and-software-management/for a development of this idea into a full MMU capable of mapping any 4KB page from anywhere in a 1MB (20 bit) memory address space, to any 4KB boundary block in the Z80's 64KB (16 bit) memory address space and supporting separate read and write mappings to facilitate copying ROM to RAM (or RAM to RAM) and to allow RAM pages to be made read only, and supporting 256 separate page tables so that swaps between predefined sets of pages can be made with only two instructions.Notable parts of the linked topic: the first two pages for the early development of the concept + some background on Z80 paging and reply#113 onwards on page 5 for implementation details.Quote from: nockieboy on January 29, 2017, 03:07:30 pmThat's crazy even if you've got a warehouse full of AT27C512R OTP ROMs that you are saving from the E-waste stream. OTP memory for development should be left back in the dark ages of the 70's unless you want a young mountain of useless chips that have been programmed with a small mistake somewhere in the code or have broken a pin during the programmer<=>board shuffle. For development its far saner to use FLASH, especially if it can be reprogrammed in situ. UV-EPROM is a poor substitute due to the typically 20 minute erase time, but that can be mitigated by keeping several chips in circulation so you have a large enough 'pool' of erased chips not to have to wait for a blank one when you find a bug.If you do have to shuffle chips, for %DEITY%'s sake plug a ZIF socket into the ROM socket on your board + rig a 'power on' LED right next to its locking lever, or better a microswitch that cuts power when the lever is first lifted slightly.

author: rstofer
author_rank: Super Contributor
timestamp: January 29, 2017, 04:36:29 pm
content: There is a separate Microprocessor/FPGA subforum...You have the right idea to use a register to select between banks. On most of the other details, I have a different point of view. Feel free to ignore it!Interrupt locations are fixed but I want to change the destination, the restart address is fixed but I probably want to change the destination, CP/M expects programs to execute from 0x0100 with a scratch buffer at 0x0080 and CCP (Console Command Processor), BDOS (the OS) and BIOS (the hardware handlers) are in high memory.Here is an excerpt of my CP/M BIOS code for a Z80:Code:003F = MSIZE EQU 63 ; 63K CP/M SYSTEM; LEAVE ROOM FOR COMPACT FLASH TABLES; EQUATES FOR LOAD ADDRESS CALCULATIONS, POINTER TO SOME GLOBAL VARIABLESAA00 = BIAS EQU (MSIZE-20) * 1024 - 512DE00 = CCP EQU BIAS + 3400HE606 = BDOS EQU CCP + 0806HF400 = BIOS EQU CCP + 1600H0004 = CDISK EQU 0004H ; CURRENT DISK NUMBER0003 = IOBYTE EQU 0003H ; INTEL IOBYTEBasically, CP/M starts at CCP and works up. It is perfectly legitimate for a user program to overwrite CCP and even BDOS if it doesn't use Disk IO. It would be bad form to overwrite the BIOS since it is the code that will reload CCP and BDOS.The Intel IOBYTE allows for swapping peripherals around and should be in RAM. CDISK is at a fixed location and MUST be in RAM.It was common to have a Monitor program in high memory but this requires a bit of ROM showing up at 0x0000 to provide the jump vector to the Monitor. The Monitor would disable the low ROM and initialize low RAM as its first function. When it came time to boot an OS (such as CP/M), the Monitor would stuff boot loader code somewhere (0x0100 is good) and the boot loader would then load CP/M to high memory (after turning off the Monitor PROM).There was no good reason to leave the Monitor in memory space after loading CP/M. But you could! Many of the Monitor programs were just 1KI certainly wouldn't use OTP PROM. My coding skills are simply not up to that. I did use a lot of EPROMs. These days I would look for a 64K RAM and a 64K EPROM and use some clever switching (a register) to determine which showed up where and when. I might generalize the mapping and just use a CPLD as a register and have it do the mapping.ETA: I would also want to substitute FLASH for EPROM even though I have the UV Eraser and a bucket load of chips (somewhere around here).One thing to watch out for: Don't switch out the page you are running from! That seems obvious but the devil is in the details when you are running from ROM and want to swap RAM over the ROM memory space. Just copy a snippet of code to some other area, branch to it, swap the memory map and branch to the new code.All of the above are for a general purpose processor. None of it applies to PacMan where various PROMs are placed in the memory space.

author: nockieboy
author_rank: Super Contributor
timestamp: January 29, 2017, 05:11:41 pm
content: Quote from: Ian.M on January 29, 2017, 03:50:18 pmI was thinking about this and had already considered the 'whole-RAM' swapping issue. I'm unlikely to be running programs that will require more than 56K to run in. To be honest, I'm not really sure what I'm thinking with it, other than making use of the extra 'wasted' RAM in the chip and being able to swap between two programs without having to load them separately.Quote from: Ian.M on January 29, 2017, 03:50:18 pmYeah, sorry, I didn't really explain it that well - I've got some EEPROMS on order (M27C256-15F1 or similar) which I was planning to use for development, with the OTP-ROM for the final (working) code. However, I hadn't considered FLASH... I'll look into that and see if it's easy enough to swap for the EEPROM (I don't mind the 20 minute wait to clear them... but then I haven't got round to writing one yet, so it could be an issue later!)I'll take a look at the link you provided - thanks for that!

author: rstofer
author_rank: Super Contributor
timestamp: January 29, 2017, 05:43:26 pm
content: The newer ez80Acclaim chips have a 16MB address space and some extra chips select lines for mapping memory and/or IO space. There may be something to learn from the documentation:Google for 'ez80acclaim user manual'. The link is too ugly to post!The idea of implementing an entire MMU is interesting. It certainly adds flexibility.

author: Ian.M
author_rank: Super Contributor
timestamp: January 29, 2017, 05:48:36 pm
content: Memory mapped I/O is occasionally useful so don't be so eager to fill up your whole address space. If low memory is all ROM, its a PITA redirecting interrupts if your code needs to customise anything. The simplest paged memory map I would bother with is bottom 16K ROM and memory mapped I/O, next 16K paged RAM and top 32K fixed RAM.That lets you keep the stack at the top and let it grow down and code at 32K upwards, followed by variables and the heap growing upwards. The paged memory could then be used for data or subroutines.Decode A15 low and A14 high to dump the three bit paging latch onto the high bits of the RAM address bus. When A15 is high, A14 must drive the RAM A14 directly to get the two fixed upper pages and RAM A15 and A16 should be pulled low. The paging latch should be loaded off the databus by an IO space write. Depending on what you are doing with the rest of the I/O space, you may simplify the decoding to checking if a single address line is active + /IORQ + /WR, or you may need to decode a full 8 bit or even 16 bit address.If you are getting windowed CERDIP UV-EPROM anyway, the only reason to use the OTP PDIP version is to recover the expensive CERDIP chip for another project (or if you want to sell kits). Assuming it hasn't been abused during development, the chip in the windowed CERDIP it will last just as long as in the PDIP package as long as you stick metal foil tape over the window to totally exclude all UV.

author: nockieboy
author_rank: Super Contributor
timestamp: January 29, 2017, 06:39:35 pm
content: Okay thanks guys - there's certainly some food for thought there. There's clearly a few factors I hadn't considered with the 'swap the entire RAM-space' idea. Namely the stack and heap. That'd cause problems later if I run a program in one block, then swap over to the other and run the other program, I'm guessing.Thanks for the links - there's certainly some information for me to start sifting through there.

author: Ian.M
author_rank: Super Contributor
timestamp: January 29, 2017, 07:17:28 pm
content: Remember: stack is hardware so you have to worry about it even in assembler. heap is a software concept and is only really applicable to high level compiled or interpreted languages.Although its a PITA your original scheme would just about be usable to multitask two programs. Each would have its own stack in its own RAM bank, and the switching routine would have to push all registers to the stack, then write the stack pointer to a fixed RAM location, before switching and restoring the other bank's stack pointer and popping all the other bank program's registers.

author: rstofer
author_rank: Super Contributor
timestamp: January 29, 2017, 07:39:30 pm
content: All of this context switching is fairly well understood in larger OSes. When switching programs, you need to save the stack pointer, all registers and flags. So, you will have some context switching code somewhere in high (non-banked) memory. Basically, you save everything on the current stack, save the stack pointer somewhere (probably a task table in non-banked RAM), switch pages, restore the stack pointer for the next context, restore the regs and status from the now-current stack and away you go.ETA: MP/M 80 had memory banking to support multiple users. The documentation may be out on the Internet somewhere:https://en.wikipedia.org/wiki/MP/M

author: Ian.M
author_rank: Super Contributor
timestamp: January 29, 2017, 08:07:16 pm
content: Quote from: rstofer on January 29, 2017, 07:39:30 pmIf its anywhere, it will most likely be athttp://www.cpm.z80.de/Anyone considering building a fully featured Z80 system (i.e. with >=64K RAM, random access mass storage + an ASCII terminal, that's not intended to emulate a 'classic' Z80 based computer that uses a non CP/M or MP/M OS, should look there to see what's available. Writing a loader + a minimal BIOS to port CP/M isn't much harder than writing a usable monitor ROM, and once you have CP/M up the world's your oyster - more compilers, utilities and applications than you can shake a stick at + the possibility to do the 'heavy lifting' cross-compiling for a CP/M emulator running on your PC then when its working, clone the filesytem to physical media, patch in your BIOS and boot it on your own hardware.However if a 4x4 keypad and 8 digits of 7 segment LEDs are more your thing, then CP/M etc. wont have much to offer you.

author: bson
author_rank: Unknown
timestamp: January 29, 2017, 08:25:43 pm
content: The last time I used EPROMs, sometime in the 90s with 80186 based SoCs (AMD AM186ES series), I used an EPROM emulator. This hooked up to a printer port (egads) at one end and went into an EPROM ZIF socket at the other. The emulator had a couple of programmable I/O pins and a /RST output that was handy for the common program-reset-debug workflow; when the firmware worked I'd put it into an actual live EPROM and verify it still worked as intended. The code was a custom threaded RT executive with a deadline scheduler (this was back when writing thread-hot code was still exotic), plus a bit of RT application code. An emulator would be my go-to tool of choice; it's almost as handy as a modern JTAG except of course doesn't have quite the same debugging support. I see such things are still made though, these days with USB. For example,https://www.eetools.com/index.cfm/product/314/eprom-emulator.cfm- $295 seems cheap but I'm sure even cheaper ones can be found.

author: daybyter
author_rank: Frequent Contributor
timestamp: January 29, 2017, 08:37:55 pm
content: There is a z180 stamp project with a cp/m port using more than 64k ram.

author: nockieboy
author_rank: Super Contributor
timestamp: January 29, 2017, 08:40:58 pm
content: Quote from: bson on January 29, 2017, 08:25:43 pmThat's a lovely piece of kit and as versatile a solution as I could hope for. Sadly it's massively out of my price range (I'm a hobbyist at best). Good point though bson, perhaps that's something I can keep my eye out for en eBay or something to see if a cheaper used item turns up.Well, if I've learned anything so far it's that the bank switching is probably more hassle than it's worth - at least at my current stage of development. I've only got my Z80 up and running in a test configuration, wired up to the SRAM and running NOPs or whatever else the SRAM is passing it from its startup state. I'm still waiting on my EEPROM programmer to arrive (suspect that'll take a while) before I can get the ROM sorted out. I will, however, take a closer look at FLASH to replace the EEPROM. But in any case, I'll get the basic system up and running first, then consider bank switching later. I think that in my naivety I thought it'd be relatively simple to set up (maybe it is to you guys, but I'm a beginner and getting lost in all this already!)I'm intending on using a USB/TTL connection to my PC via an F68B50 ACIA (in Grant Searle's design) or a Z80 SIO (if I work out how best to wire it in) to interact with the Z80 system via a console. That way I will have a much better solution than a hex keypad and some 7-seg displays, but can build up a proper display adaptor and keyboard interface later on.

author: rstofer
author_rank: Super Contributor
timestamp: January 29, 2017, 10:38:51 pm
content: Quote from: Ian.M on January 29, 2017, 08:07:16 pmIt is worth Googling for 22NICE as it provides a Z80 environment on a PC and will run the CP/M software. This makes it possible to use the Macro Assembler to write the BIOS. For obvious reasons, it is no longer supported but it should still be available (actually it is!):http://www.cpm80.com/The last time I used 22NICE, I was using WinXP so I have no idea where things stand.

author: Ian.M
author_rank: Super Contributor
timestamp: January 29, 2017, 11:15:46 pm
content: Another toolchain option if you want to treat the Z80 board more as an embedded system (though it can also target CP/M) is the PC hostedZ88DKC cross-compiler and Assembler for Z80. Its actively maintained so should be a lot less hassle on modern LINUX or Windows PCs than most of the PC side CP/M tools.

author: rstofer
author_rank: Super Contributor
timestamp: January 30, 2017, 04:20:50 pm
content: There are a number of side issues in bringing up CP/M (or anything else) on a bare board. So, cool, you have the code output on your PC. Now what?There is a specific disk layout for CP/M and it is pretty easy to use the Linux 'dd' command to write the image file (including the BIOS code) to something like a compact flash. In fact, you can set the remainder of the entire CF to 0xE8 and if your Large Block Addressing works properly for 16 drives, you just created all of them, 15 of which are blank.Believe it or not, Kermit can be used to transfer the CP/M object files to the working Z80 system. I suspect the clever programmer would figure out how to include all the files in the original CF image but all I did was get Kermit running (I have forgotten how I did that!).When the project is far enough along, post a question re: porting CP/M and I'll see if I can dig out how I did this for the ezAcclaim. At one point, I was using my CompuPro Z80 with dual 8" floppies along with Kermit to transfer everything I owned to the new system. Yup! The 8" dual drive still works. As does the 6 MHz CompuPro and, with a wee bit of effort, my Altair 8800.

author: nockieboy
author_rank: Super Contributor
timestamp: January 30, 2017, 08:37:31 pm
content: Quote from: rstofer on January 30, 2017, 04:20:50 pmThanks rstofer - I will surely do that when I get to that stage!Firstly, I'm waiting on my EEPROM programmer so I can get the ROM sorted and the computer up and running.