News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

Understanding memory banking

Started by Munchausen, 19:00, 22 October 13

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Munchausen

Hi everyone,
I am trying to fully get to grips with how memory banking works in the CPC. As far as I understand so far:

The Z80s addressable memory is divided into four blocks: bank 0 (0-3FFF), bank 1 (4000-7FFF), bank 2 (8000-BFFF) and bank 3 (C000-FFFF).

RAM can be paged in and out by writing to gate array register 3, i.e. writing 11xxxyyy to &7Fzz (where zz is don't care). Either:

1. We just have 128k of memory. xxx is a don't care (so we set it to 0 or just mask it out?). yyy specifies which 16K blocks of the total 128K memory are mapped to which bank of Z80 address space.
2. xxx specifies a 64K RAM page in a RAM expansion, and yyy = 1yy, where yy specifies a layout for the extra 64K. In this situation does RAM_0 to RAM_3 refer to the built in RAM_0 to RAM_3 and RAM_4 to RAM_7 refer to the extra 64K page that has been selected by xxx?

Banks 0 and 3 can additionally be mapped to ROMs. When mapped to a ROM, writing to these banks will still write to whichever area of RAM is currently mapped to that block as above, but reading will read from the ROM.

To map lower/higher ROMs we use gate array register 2, writing 10vwxyzz to &7Fxx, where v is a don't care, w is interrupt control, x is 1 to enable the upper ROM and 0 to disable, y is 1 to enable the lower ROM and 0 to disable, and zz is the screen mode.

Bank 0 can only be mapped to a single ROM (ROM 0?), but bank 3 can be mapped to one of a number by writing which ROM you want to &DFxx.

You can also use kernel functions: For lower ROM call &B906 to map it, and &B909 to unmap it. For upper ROM call &B900 to map, and &B903 to unmap. To select an upper ROM, call &B90F with C loaded with the ROM number you want. I don't understand what is meant by ROM state in these functions.

I also don't understand how kernel functions interact with the rest of your memory... they appear to be mapped into RAM all over the place, so what happens if you want to use this RAM for stuff? I guess if a RAM bank is mapped in the same range you can't access those areas, so you have to juggle the RAM around?

Finally, I don't exactly understand what parts of the firmware are actually stored in the lower ROM and upper ROM 7. There seem to be conflicting statements on which contains basic, for example.

ralferoo

#1
Quote from: Munchausen on 19:00, 22 October 13
I also don't understand how kernel functions interact with the rest of your memory... they appear to be mapped into RAM all over the place, so what happens if you want to use this RAM for stuff? I guess if a RAM bank is mapped in the same range you can't access those areas, so you have to juggle the RAM around?
Best to just consider 128K RAM at first.

Have a read of AdvancedMemoryUsage - NoRecess. The banking modes &C0,&C4-C&7 are very useful as they can switch any of the extra banks into page 1. Modes &C1-C3 are also useful, but are more complicated. &C2 in particular will not allow you to use the firmware.

Quote from: Munchausen on 19:00, 22 October 13
2. xxx specifies a 64K RAM page in a RAM expansion, and yyy = 1yy, where yy specifies a layout for the extra 64K. In this situation does RAM_0 to RAM_3 refer to the built in RAM_0 to RAM_3 and RAM_4 to RAM_7 refer to the extra 64K page that has been selected by xxx?
Yes, if you have a bigger memory expansion, the xxx in your first point effectively remaps banks 4-7 to the higher banks. You don't have to use 1yy though, you're free to use the other modes too. The xxx just remaps RAM_4 to RAM_7.

If you want an idea of what each configuration looks like, check out the sources in Index of /public/mem, specifically http://voxel.angrysprite.com/public/mem/mymemtest.asm which goes through every possible combination and reports what bank is mapped.
Quote
I also don't understand how kernel functions interact with the rest of your memory... they appear to be mapped into RAM all over the place, so what happens if you want to use this RAM for stuff? I guess if a RAM bank is mapped in the same range you can't access those areas, so you have to juggle the RAM around?
The lower part of bank 0 is used for interrupt vectors and a small amount of storage. Some ROM applications (including BASIC) allocate some low memory working area from here.
The upper part of bank 2 is used for the default stack, firmware indirection table, current character maps, disk IO tables, etc. Again, ROMs (including AMSDOS) can allocate some high memory from here. User memory is whatever is left in the middle. http://voxel.angrysprite.com/public/mem/mytestrom.asm shows you how to determine this using |MEM (see do_mem_info onwards in code) and lists the roms and their high memory allocations using |ROMS (see do_list_roms).

If you're going to be switching anything into page 0 or 2, you need to not use the firmware and moreover disable interrupts.

Of course, if you don't want to use the firmware, you're free to use any memory at all, as long as you don't intend to return back to BASIC.
Quote
Finally, I don't exactly understand what parts of the firmware are actually stored in the lower ROM and upper ROM 7. There seem to be conflicting statements on which contains basic, for example.
The lower ROM is the firmware, i.e. all the system functions. Upper ROM 0 is BASIC, upper ROM 7 is AMSDOS. Technically, BASIC isn't really upper ROM 0, if any expansion device asserts ROMDIS on an upper ROM it is used, if nothing asserts it the BASIC ROM is used, so it'll actually appear at most slots. The expansion devices themselves latch the out to &DFxx and use that to determine whether to assert ROMDIS. Some devices might only decode 3 bits of the the ROM number, so they'll be repeated every 8 ROMS, others might decode all 8 bits. AMSDOS is always ROM 7 because that's where it appears on real hardware and various parts of it are hardcoded so it only works in that position. Others ROMS might be at any position. BASIC theoretically could be anywhere, but in practice tends not to work unless its in slot 0.

redbox

#2
Ralferoo has provided a nice technical answer, but it's worth going back to basics if you're just trying to get your head round it...

ROMs are banked into a part of the CPC's RAM.  The kernel (or OS) ROM is banked into &0000 to &3FFF.  AMSDOS is banked into &C000 to &FFFF.  All other background ROMs are also banked into &C000 to &FFFF.  BASIC is a special case and can in theory be banked in 'anywhere'.  When a ROM is banked in, if you READ the memory it will come from the ROM, but if you WRITE to the memory the underlying space in the CPC's RAM is written to, not the ROM.  Think of the ROM as a layer over the RAM when banked in.

Extension RAM (i.e. above 64k) can be banked into different areas, but there are limitations on the order (see the &Cx banking modes for more information).  However, both READs and WRITEs will effect the extension RAM and not the underlying main 64kb RAM in the CPC.

The banking information you provided seems correct.  It depends if you want to do it direct (i.e. OUT &7FXX etc) or via the firmware.  If you're just starting out, it's probably best to use the firmware to get to grips with it and then move onto direct code.

Quote from: Munchausen on 19:00, 22 October 13
You can also use kernel functions: For lower ROM call &B906 to map it, and &B909 to unmap it. For upper ROM call &B900 to map, and &B903 to unmap. To select an upper ROM, call &B90F with C loaded with the ROM number you want. I don't understand what is meant by ROM state in these functions.

When calling these firmware routines, on exit A holds the previous state of the ROM, i.e. was it already enabled or not.

Quote from: Munchausen on 19:00, 22 October 13
I also don't understand how kernel functions interact with the rest of your memory... they appear to be mapped into RAM all over the place, so what happens if you want to use this RAM for stuff? I guess if a RAM bank is mapped in the same range you can't access those areas, so you have to juggle the RAM around?

The firmware (routines at &B900 onwards) is just a 'jumpblock' and all the routines here do when you call them is 1) enable the lower ROM containing the OS, 2) bank it into position 0 (&0000-&3FFF), 3) jump to the relevant routine and 4) run it.

Remember, when OS (which is a ROM) is mapped in, READs from the memory area come from the ROM, but WRITEs to the area still go into the underlying RAM.

Quote from: Munchausen on 19:00, 22 October 13
Finally, I don't exactly understand what parts of the firmware are actually stored in the lower ROM and upper ROM 7. There seem to be conflicting statements on which contains basic, for example.

BASIC is contained in a separate ROM which is also banked in and acts like any other ROM.  It can read routines from the OS if it needs them.

Munchausen

#3
Thanks for the really nice explanation. :)

Quote from: ralferoo on 20:25, 22 October 13
Best to just consider 128K RAM at first.

Have a read of AdvancedMemoryUsage - NoRecess. The banking modes &C0,&C4-C&7 are very useful as they can switch any of the extra banks into page 1. Modes &C1-C3 are also useful, but are more complicated. &C2 in particular will not allow you to use the firmware.

Aha, a great link! Reading now...

Quote from: ralferoo on 20:25, 22 October 13
Yes, if you have a bigger memory expansion, the xxx in your first point effectively remaps banks 4-7 to the higher banks. You don't have to use 1yy though, you're free to use the other modes too. The xxx just remaps RAM_4 to RAM_7.

Makes sense. I got the 1yy thing from here. It says "2 Special feature bit. For this kind of RAM banking it must be set to 1." Maybe this is wrong?

Quote from: ralferoo on 20:25, 22 October 13
If you want an idea of what each configuration looks like, check out the sources in Index of /public/mem, specifically http://voxel.angrysprite.com/public/mem/mymemtest.asm which goes through every possible combination and reports what bank is mapped.The lower part of bank 0 is used for interrupt vectors and a small amount of storage. Some ROM applications (including BASIC) allocate some low memory working area from here.

Another great link... and a useful application (was looking for a memory tester recently)!

Quote from: ralferoo on 20:25, 22 October 13
The upper part of bank 2 is used for the default stack, firmware indirection table, current character maps, disk IO tables, etc. Again, ROMs (including AMSDOS) can allocate some high memory from here. User memory is whatever is left in the middle. http://voxel.angrysprite.com/public/mem/mytestrom.asm shows you how to determine this using |MEM (see do_mem_info onwards in code) and lists the roms and their high memory allocations using |ROMS (see do_list_roms).

Wow, I didn't even think about that the stack will get messed up when you move banks around... at least register pressure doesn't seem too bad on the z80, but must remember to keep an eye on that!

Quote from: ralferoo on 20:25, 22 October 13
If you're going to be switching anything into page 0 or 2, you need to not use the firmware and moreover disable interrupts.

Amazingly useful to know to avoid swapping out banks 0 and 2. But I guess you can still use interrupts if you've got your own interrupt routine and do: disable interrupts, switch RAM banks, stick "jp my_handler" into &38 of whatever RAM you put in page 0, then renable interrupts, right?

Quote from: ralferoo on 20:25, 22 October 13
The lower ROM is the firmware, i.e. all the system functions. Upper ROM 0 is BASIC, upper ROM 7 is AMSDOS. Technically, BASIC isn't really upper ROM 0, if any expansion device asserts ROMDIS on an upper ROM it is used, if nothing asserts it the BASIC ROM is used, so it'll actually appear at most slots. The expansion devices themselves latch the out to &DFxx and use that to determine whether to assert ROMDIS. Some devices might only decode 3 bits of the the ROM number, so they'll be repeated every 8 ROMS, others might decode all 8 bits. AMSDOS is always ROM 7 because that's where it appears on real hardware and various parts of it are hardcoded so it only works in that position. Others ROMS might be at any position. BASIC theoretically could be anywhere, but in practice tends not to work unless its in slot 0.

The best explanation I've seen :) . I was getting highly confused between the upper rom 0 and the lower rom, so maybe I haven't seen conflicting stuff after all.

So, for example, on my symbiface if I put something into (upper) ROM slot 0 it wont work because the symbiface doesn't assert ROMDIS? And the symbiface can do nothing when it comes to the LowerROM?

I also have a LowerROM board which can have basic and firmware on it (as I understand), so I take it that the lower rom and upper rom 0 are on the same chip normally?

Munchausen

#4
Thanks for your explanation too redbox, I think between you you've covered almost all aspects of memory access! :)

Quote from: redbox on 20:43, 22 October 13
When calling these firmware routines, on exit A holds the previous state of the ROM, i.e. was it already enabled or not.

Cool, this was confusing me. So it's like A=1 means it was already enabled, 0 means it wasn't? For the upper ROM does this refer to the specific ROM being enabled or just the upper ROM in general?

Quote from: redbox on 20:43, 22 October 13
The firmware (routines at &B900 onwards) is just a 'jumpblock' and all the routines here do when you call them is 1) enable the lower ROM containing the OS, 2) bank it into position 0 (&0000-&3FFF), 3) jump to the relevant routine and 4) run it.

Aha, another neat explanation of something that was mysterious before. I realised there was trampolining going on, but not that the lower ROM was enabled/banked before (and presumably removed again afterwards, if it had not previously been banked?)

redbox

Quote from: Munchausen on 21:16, 22 October 13
Cool, this was confusing me. So it's like A=1 means it was already enabled, 0 means it wasn't? For the upper ROM does this refer to the specific ROM being enabled or just the upper ROM in general?


Pretty sure it's Upper ROM in general, but I'd check it if I were you ;)

Quote from: Munchausen on 21:16, 22 October 13Aha, another neat explanation of something that was mysterious before. I realised there was trampolining going on, but not that the lower ROM was enabled/banked before (and presumably removed again afterwards, if it had not previously been banked?)

Yes, it's banked out once finished.  The jumpblock is useful because all CALL addresses are the same across the CPCs, where as the actual routine locations in the OS ROMs differs on the 464/664/6128.

arnoldemu

Quote from: Munchausen on 19:00, 22 October 13
Finally, I don't exactly understand what parts of the firmware are actually stored in the lower ROM and upper ROM 7. There seem to be conflicting statements on which contains basic, for example.
The firmware is in the lower ROM. Firmware handles reading of keyboard and cassette and contains many functions for controlling the cpc (setting mode, installing interrupt handlers, paging roms in/out, drawing lines, playing sounds). It does most of the work.

BASIC contains the BASIC interpreter, but calls the firmware to handle most basic functionatity (e.g. MODE goes to the firmware to set the mode).

ROM 7/AMSDOS, contains functions for accessing the 765 floppy disc controller including read/write sectors, moving to a track. It also contains part of the CPM 2.2 BIOS, and the code to BOOT from track 0 sector 41. When it's started it patches the firmware jumpblock in RAM so it can redirect the firmware "CAS" functions to read/write from disc. The | commands |TAPE, |DISC in the AMSDOS ROM allow it to patch the functions for cassette or disc operation. So this ROM also contains the disc versions of CAS IN OPEN, CAS IN DIRECT, CAS IN CLOSE etc.

Also, just because they wanted to. On all AMSDOS (except Plus), it also contains a chunk of CP/M 2.2 Logo in it. The Logo code also calls the firmware to do drawing of lines etc.

On Plus, it's muddied a little. The firmware calls into the AMSDOS rom in the cart. Code in the AMSDOS rom then displays a menu. Depending on the choice it pages in another part of the cart and executes the Burnin' Rubber game, OR it calls back to the firmware to continue initialisation and go into basic.

In terms of the CPC, the lower rom/firmware does the majority of the work. In order that functions can be redirected, overridden etc, it uses part of the RAM to store a "jump block". Normally these jump into the ROM, but you can change them to jump to your functions if you want control first.

The lower jump block is 0-&40, includes the Z80 interrupt mode 1 vector at &0038. But also uses some of the RST instructions (one of which becomes a special kind of call, and this is the one in the main firmware jumpblock).

&ae00 to &b900 or so, are variables the firmware and basic uses. &b900-&be00 is the jump block with the jumps to do the functions. &be00-&c000 is the stack.

When AMSDOS starts, it reserves some ram and so &a700-&ae00 is then used by it for variables.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

TFM

The best is to consider 576 KB first. A raw of 16 KB Blocks ;-)


Just imagine you switch 16 KB blocks in, between &4000-&7FFF.


All other variants won't get used that often.
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

SOS

Sorry for the old thread, but i think (hope), my question goes correcty in this thread:
The &7F-Port is Write-Only.
Is there a way/trick how to get the actual RAM-Config?
(i write something to Bank &C6 but after that i want to restore the original config e.g. C0,C3,C6,...)

andycadley

The usual way is to keep track of the banking as you switch it, so you can restore it when you need. That only works if your code is totally responsible for the banking, of course.


An alternate strategy is to write some specific, unusual, sequence of bytes somewhere in the bank first (taking a backup of whatever was there) and then, when you're ready to switch back, cycle through different pages until you find the one with your key sequence in it and then write back the "correct" values.

Prodatron

Quote from: SOS on 10:05, 14 April 19Is there a way/trick how to get the actual RAM-Config?
Simple answer: No (unfortunately).You will have to store the actual banking config somewhere, if you need it later (I am using the I-register for this  :D ).

GRAPHICAL Z80 MULTITASKING OPERATING SYSTEM

Powered by SMFPacks Menu Editor Mod