JNEXT
Skip to content

Banked code, and which memory a line is in

A Next program pages code in and out, so one address can hold different code at different times. This page is how the Source tab, the Call Stack and the Breakpoints panel cope with that, how to read the memory tag next to an address, and what z88dk's __banked needs. The build commands for __banked are in Building programs with z88dk.

Pages, and the page a line is built for

Each source record names the 8K RAM page its code was built for, and the debugger matches the RAM page that supplies that address now: the Source tab, the Call Stack and the Breakpoints panel never show a line of code that is not the one in memory. Code supplied by ROM or by an overlay (DivMMC — including the instruction at which its automatic paging switches on or off —, the Multiface, the Layer 2 read mapping, the boot ROM) is not any RAM page, so page-tagged records never describe it; the Source tab names that memory (ROM0, DIVROM) and says there is no source mapping. Labels follow the page too: a label assembled for a bank names its address only while that bank is mapped there, in the disassembly, the Breakpoints and Call Stack panels, and a remote debugger's monitor sym; a label assembled for no bank names it always.

A statement covers every byte up to the next one: the data of a DB after an instruction belongs to that instruction's statement, and so does everything after the last statement of a page up to the end of that 8K page. Only addresses below a page's first statement, and pages with no statement at all, are unmapped.

Code your program copies somewhere else at run time (a routine moved out of a bank into low memory, say) has no record where it runs unless your build made one, and shows as unmapped there.

Reading the tag

The line above the Source tab's text ends with the memory the opcode comes from:

The Source tab stopped in banked code

banked.c:9 $C01B P14 is the line, the CPU address and the memory: P14 is RAM page 0x14, which z88dk calls PAGE_20 (it counts in decimal, the tags in hex), mapped at $C000. The picture is the -run build of the banked example from Building programs with z88dk, stopped by a breakpoint on banked.c:9. A program that is not banked reads main.c:19 $8CB5 P04: a NEX program's code at $8000 is page 0x04. In the Breakpoints panel the address column spells it the same way ($8CB5 P04), and a breakpoint on a line of banked code is tied to that memory: it fires only while that memory supplies the address, and the disassembly gutter shows it only then.

The tags are the debugger's own: P0E (RAM page 0x0E), ROM0 to ROM3, BOOT, DIVROM, DIVRAM3, MFROM, MFRAM, ALTROM0, L2P12, CFG17, FLOAT, explained in which memory an address is in. The same tags are in the trace log and in monitor src over the GDB server: on the banked example monitor sym banked_add answers banked_add = $C000 P14.

Debug ▸ Physical Addresses replaces the tag by the place the byte sits in the Next's memory (--set debugger.physical_addresses=true does it for one run). RAM page n is at (n + 0x20) × 8 KB in the SRAM (except pages 0x0A, 0x0B and 0x0E, the block RAMs, which read BRAM5+$0000, BRAM5+$2000 and BRAM7+$0000, as in monitor mmu), so page 0x04 is $048000 (the GDB server's monitor mmu prints it so for the slot at $8000 of a NEX program) and page 0x14 is $068000. The setting changes nothing on a machine that is not a Next.

What z88dk's __banked needs

A function in a PAGE_n or BANK_n section is found only while its 8K page is mapped where it runs. The map's address for a BANK_n section carries the bank in its high bits; JNEXT reads the page from the section and the address, and the map's symbols follow the page as its lines do (@name and the disassembly name a banked symbol only while its page is mapped); the 24-bit __PAGE_<n>_head that the pragma produces is read by its low 16 bits.

z88dk's __banked on newlib +zxn needs -pragma-define:CRT_ORG_PAGE_<n>=0x<page><org> (the page in the top byte, for example 0x14C000 for PAGE_20) and a stack below the banking segment (-pragma-define:REGISTER_SP=0xC000): without them the program itself calls page 0 or loses its stack. Over and Out step across banked_call and the -debug helpers; Out lands on the calling line at the return address (mid-statement), as gdb's finish does.

Code in a section that names no page (CODE, code_compiler, the program itself) is tied to the RAM page the MMU maps at that address when the program is in memory (page 4 at $8000 for a NEX).

DivMMC sections (DIV_n) have no fixed bank (the program, or a dotn command's allocator, chooses it when it runs): a line in one is refused, with the line named, rather than attached half. The exception is a NextZXOS dot command, see Dot commands.