feilipu / yaz180

YAZ180 - Modern Single Board Z180 Computer
GNU General Public License v3.0
51 stars 7 forks source link

Questions about how the Z180 MMU works #2

Closed mosespray closed 6 years ago

mosespray commented 6 years ago

(https://github.com/feilipu/yaz180/files/1742861/yaz180.Memory.Map.-.Sheet1.pdf) In the first blog post you describe your memory map design, but it is prefaced with a statement about how it all changed. I transcribed the memory map from your blog (OLD WAY) and then from your PLD code (NEW WAY). Can you elaborate on how the new scheme works? Specifically, how does it flow? When the Z180 boots, it starts at 0000H. So, that would mean that it starts reading the yazbios at the beginning of the FLASH chip. Then what happens? Does it start banking the banks (1-13) in and out? Would it be possible to just design it such that upon reset, it reads the bios from 0000H from the FLASH, but then perform a chip select with a 74LS138 to restore the entire 1MB SRAM? I would rather have the physical be all in COMMON1, but I read somewhere that the Z180 can't deal with it being linear.

[yaz180 Memory Map - Sheet1.pdf]

Best, Dave

feilipu commented 6 years ago

There are quite a few good references to how the Z180 MMU works. I've listed a few at the bottom. I read each of them at least 10 times, and the data sheets many times too, but I still didn't understand until I had to actually write code.

The flow I'm describing is specific to both hardware and software (and also firmware in the EPLD for that matter), so it is completely configurable by anyone using the YAZ180 to bend to their own ends. But for discussion, here's my current view.

Physical Addressing

The Z180 has 20 address lines and through the MMU has 1MByte of physical address space. I have connected both a 1MByte SRAM and a 128kB/256kB/512kB Flash device to these address lines, in the normal way (excepting the comments on RAM in #3). This means that for a significant proportion of the physical address space there are two devices available.

The /CE or /OE pins of the RAM and Flash devices are controlled by the EPLD code, and in this way we only enable ONE of the two devices for each physical address. In programming mode this control issue is compounded by needing to allow a physical address space for fake USB provided memory, but let's ignore that for now.

The current (and final, IMHO) physical assignment is RAM from 0x0C000 up to the lower limit of the Flash, and Flash from 0xFFFFF down to its full capacity, less the first 64kBytes, 48kBytes of which appear in the first page from 0x00000 to 0x0BFFF.

For example, for a 128kB Flash device, the lower page boundary is at 0xF0000. For a 256kB Flash device it is at 0xD0000. Note that these descriptions of "pages" are purely arbitrary, and are only relevant because the Z80 thinks in 64kByte chunks, so it is easiest to think in the same way.

Logical Addressing

I've learned quite a bit since I started this project, and my ideas around how to manage the logical address space have matured substantially, I believe.

It is important to note that the Z180 is just a Z80 with a MMU. A Z80 only supports 64kByte of logical address space. The MMU is responsible for mapping segments of the physical address space into the Z80 logical address space. Compared to later x86 MMUs, the Z180 MMU is very simple and limited.

Initially I had the idea of trying to maintain a small CA0 address space for the "Page 0" vectors and a global stack at the bottom of the logical address space, and use the BANK and CA1 logical address spaces to allow reference to the parts of the physical address space as needed. I was trying to keep things simple, but this was naive.

The yabios now uses just two logical address spaces, BANK and CA1, with the CA1 being as small as possible at the top of the logical address space. Currently this is 0xF000 to 0xFFFF, and it looks as if this provides enough space for both interrupt code that must run irrespective of which bank of logical memory is configured in the BANK address space, and for buffers for I/O for the serial ports, and the Am9511A APU.

When the Z180 initially starts up, the MMU registers set the logical address space to match the first 64kBytes of the physical address space. That is why the physical address space needs to have some Flash in the lowest page (or 64kBytes), starting from 0x0000 logically and 0x00000 physically.

The first thing I do is to create the split between BANK and CA1 areas. Then the physical starting addresses for the two logical address spaces are set. Now we have a fixed RAM in CA1 which is both logically and physically at 0x0F000 to 0x0FFFF, and a banked logical address space from 0x0000 to 0xEFFF, and depending on the setting of the BBR can be any part of the physical address space.

FOR CONVENIENCE I always ensure that the BBR setting is on a 64kByte page boundary. Doing this wastes RAM / Flash because the memory in every page from 0xnF000 through to 0xnFFFF is always masked by the RAM maintained in CA1 in 0x0F000 to 0x0FFFF.

When doing a bank swap with this memory layout requires the programmer to think about both the contents of the "Page 0", and the location of the current stack.

The "Page 0" in Z80 is the 256 bytes at the bottom of the address space from 0x0000 through to 0x0100 (although in reality only up to 0x0068 is really necessary, it is convenient to think in terms of pages). The "Page 0" contains the interrupt vectors and these must always remain valid, if you want your Z80 processor to keep working. In the Z180 with the ability to change the "Page 0" contents by remapping the logical address space, it is essential to ensure the new or incoming "Page 0" is created correctly before doing a bank swap.

Also, when doing a bank swap the stack pointer SP needs to be managed. If the SP points to the wrong physical address location or has the wrong contents, because you changed the logical address map, then things go bad quickly.

That is why I've implemented a location in "Page 0" of each bank to store the contents of the SP when the bank is changed. The lowest page of memory where the yabios is maintained has a system stack, and I maintain a the contents of the system stack pointer in a different location in CA1 memory, so it is available to each bank's code to push things onto the system stack if they need to. Note that these locations are NOT the SP. They are locations provided to store the contents of the SP when that bank is NOT active. The mechanism is shown in the _call_far function, and in the _system_rst function.

DMAC

Note that both of the the Z180 DMA Controllers don't care about the logical address space. They are programmed based on the physical address space. That is why it is convenient to maintain the 64kByte mapping for the BBR, to allow simple creation of 20 bit addresses for the DMAC simply by bit shifting the BBR value.

Also, using the DMAC we can recover the RAM or flash hidden by the CA1 logical address mapping by copying to and from the masked physical addresses, if there is a need for an application to use that extra 4kByte per page. So far I've not had a need to do this, but the _memcpy_far function already supports this capability.

References

The Ganssle Group - Z180 Memory Management Z180 FAQ

mosespray commented 6 years ago

Thank you for the quick and thorough responses. In my quest to understand how the Z180 works, I encountered and read/re-read both of those references many times. However, with the added explanations above, which are excellent, btw, I will read them again with them in mind. I feel a lot better knowing that you had to read the docs over and over. I really appreciate that you are so helpful and share your knowledge and designs.