Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Paging

The ASIC maps four 16 KiB logical windows into Flash and RAM. Port 0x04 selects one of two mapping modes, ports 0x050x07 hold the page selectors, and ports 0x0E, 0x0F, 0x27, and 0x28 modify the selected pages or small subranges.

This page distinguishes behavior executed by OS 2.55MP from public hardware descriptions and emulator implementations. The ROM never gives ports 0x27 or 0x28 a nonzero value, so their physical behavior remains unconfirmed.

Evidence and scope

EvidenceWhat it establishesConfidence
ROM bytes at 00:0000029C, 3F:40004210, and the paged-RAM helpersexact selector writes, boot transitions, and OS restore values[confirmed]
Resolved TilEm boot and homescreen tracesexecuted page transitions and logical-to-physical page resolution[confirmed]
TilEm x4_io.c and x4_memory.cone emulator’s paired mode, selector masks, forced overlays, and protection order[standard]
Wabbitemu 83psehw.c and core.can independent implementation, including extended Flash pages and different overlay rules[standard]
Guarded Wabbitemu mapper runinitialized-core reset, selector readback, fixed-page handoff, paired mapping, and overlay routing[standard]
MAME 0.287 ti85.cpp and ti85_m.cppa third implementation’s bank arithmetic, reset latch, mapped I/O, and backing ranges[standard]
Guarded MAME mapper runfresh-reset latch qualifiers, selector masks, safe RAM banks, absent overlay ports, and read/write/fetch routing[standard]
Public port descriptionsintended family-wide contracts for ports 0x040x07, 0x0E, 0x0F, 0x27, and 0x28[standard]

The target ROM runs on a TI-84 Plus with 64 Flash pages and eight RAM page selectors. Family members with more Flash need the extended selector bits in ports 0x0E and 0x0F.

Page selection and execution permission are separate. The mapper can expose a RAM page in a CPU window while the execution-protection logic rejects an opcode fetch from the corresponding physical chunk. See Execution protection. [standard]

OS and analysis use

The bcall dispatcher maps a paged body through port 0x06, executes it in window A, then restores the previous page. A bcall whose body resides on fixed page 0 executes below 0x4000 without changing bank A. The page-set helper at ram:181C implements the dispatcher write. [confirmed]

cross_page_jump at ram:2B09 consumes an inline address-and-page payload and transfers control across Flash pages. Banked routines are position-fixed for window A because their logical addresses remain in 0x40000x7FFF regardless of the selected physical page. [confirmed]

Ghidra models physical Flash pages 1–63 as overlay blocks based at 0x4000. This makes every banked body statically visible while preserving its logical address. Runtime traces still need the active port-0x06 value to identify the physical page. [confirmed]

The four logical windows

The Z80 supplies a 16-bit address. The top two address bits choose a logical window; the mapper supplies the physical page.

Logical rangeWindowBase selector in independent modeNormal OS use
0x00000x3FFF0fixed Flash page 00reset vectors, interrupts, and kernel code
0x40000x7FFFAport 0x06, extended by 0x0E for Flashpaged Flash code or temporary banked RAM
0x80000xBFFFBport 0x07, extended by 0x0F for Flashnormally RAM page 81
0xC0000xFFFFCport 0x05normally RAM page 80

Window 0 stays fixed in both modes. [standard] The fixed page and the normal RAM values match the OS trace. [confirmed]

A physical page can appear in more than one window. During boot, Flash page 3F is visible through both A and B for part of the transition. Logical addresses in those windows then alias the same physical bytes at different offsets. [confirmed]

Mapper view. Window 0 remains fixed. The boot example is [confirmed]; the complete paired and independent register contract is [standard].

Mapping modes — port 0x04 bit 0

Writing port 0x04 changes the memory mode and the standard-timer rate. Its bit 0 controls the mapper. Reading the same port returns interrupt and key status, not the last mode byte. See Clock, timers, and power for the other bits. [standard]

Independent mode — bit 0 clear

Each banked window has its own selector.

WindowSourceResult
A, 0x40000x7FFFports 0x06 and 0x0Eone Flash or RAM page
B, 0x80000xBFFFports 0x07 and 0x0Fone Flash or RAM page
C, 0xC0000xFFFFport 0x05one RAM page

The OS normally writes 0x06 to port 0x04, selecting independent mode and the slowest standard-timer rate. Its bcall dispatcher maps a target Flash page through port 0x06. Paged-RAM helpers use ports 0x05 and 0x07 as a pair. [confirmed]

Paired mode — bit 0 set

Port 0x06 supplies an adjacent page pair, and port 0x07 moves to window C. Port 0x05 does not select a visible window in this mode. [standard]

WindowSourcePage rule
A, 0x40000x7FFFport 0x06selected physical page with bit 0 cleared
B, 0x80000xBFFFport 0x06the adjacent page with bit 0 set
C, 0xC0000xFFFFport 0x07the page selected by port 0x07

For example, the TI-84 Plus reset selector 0x3F produces Flash page 3E in window A and page 3F in window B. The boot trace begins at logical 0x8000, which therefore executes retail_boot_reset_stub at 3F:4000. [confirmed]

Changing bit 0 reinterprets all three banked windows at once. Code that changes the mode must execute from fixed page 0 or from a physical page visible at the next logical PC under both mappings. The boot transition uses the latter method. [confirmed]

Selector encoding

Ports 0x06 and 0x07

Bit 7 chooses the memory type. On the TI-84 Plus, these selector rules match the trace, TilEm, and Wabbitemu: [confirmed] for executed OS values; [standard] for the complete register contract. MAME matches the OS-used Flash values and RAM selectors 0x800x86, but does not wrap higher RAM values.

SelectorPhysical page
bit 7 clearFlash page, low six bits on this 64-page calculator
bit 7 setRAM page `0x80

The hardware-facing 0x800x87 RAM notation distinguishes RAM selectors from Flash page numbers. It does not mean that RAM has 128 pages. See RAM pages for physical aliasing and OS use.

Port 0x05

Port 0x05 always selects RAM. On the TI-84 Plus, its low three bits select RAM page 0x80 | (value & 7). The normal value 0x00 therefore maps RAM page 80 into window C in independent mode. [confirmed]

TilEm stores four low bits for port readback but uses only three in its page calculation. Wabbitemu reduces the low seven bits by the model’s RAM page count. MAME stores the low three bits. The arithmetic in all three selects the same eight page numbers, although MAME’s backing range omits the last page as described below. [standard]

Extended Flash bits — ports 0x0E and 0x0F

Public descriptions and Wabbitemu model these registers as two high Flash-page bits. Port 0x0E extends port 0x06; port 0x0F extends port 0x07: [standard]

$$ P_A = ((p_6 \bmod 128) + 128(p_{0E} \bmod 4)) \bmod N_F $$

$$ P_B = ((p_7 \bmod 128) + 128(p_{0F} \bmod 4)) \bmod N_F $$

Here $N_F$ is the number of physical Flash pages. The high registers apply only when bit 7 of the corresponding low selector is clear. A RAM selector ignores them. [standard]

For the 64-page TI-84 Plus, every contribution from ports 0x0E and 0x0F is a multiple of 128 and disappears after the page mask. The boot ROM still writes 3 to each register while selecting its highest boot page, then clears both during normal mapper initialization. [confirmed]

TilEm’s TI-84 Plus mapper stores and reads the low two bits but does not feed them into its 64-page calculation. Wabbitemu uses the family-wide formula and masks the result by the configured Flash size. These implementations agree for this target. MAME does not map ports 0x0E or 0x0F; writes reach no handler. Its TI-84 Plus port-0x06 and port-0x07 handlers instead truncate every Flash selector below 0x80 to six bits. [standard]

Emulator mapper comparison

The source-level comparison below describes the pinned implementations, not the ASIC. Agreement is useful corroboration of an intended rule; disagreement is a test target rather than a vote. [standard]

DetailTilEmWabbitemuMAME 0.287jsTIfied 20170706a
Mapper ports0x040x07, 0x0E, 0x0F, 0x27, 0x28sameonly 0x040x070x040x07, 0x0E, 0x0F, 0x27, 0x28
Declared driver statususable mapperusable mapperMACHINE_NOT_WORKINGbrowser emulator source model
port 0x05 writestores low four bits; maps low threereduces low seven bits by RAM-page countstores low three bitsselects window C on TI-84 Plus
TI-84 Plus Flash selectorlow six bitsextended formula, then Flash-size masklow six bits for values below 0x80low selector plus ports 0x0E/0x0F extensions
RAM selectorlow three bitslow bits masked by RAM-page countraw value 0x800xFF becomes the bank number0x80 flag plus low three-bit page
paired Aport-0x06 page with bit 0 clearsamesameeven member selected from port 0x06
paired Bport-0x06 page with bit 0 setsee expression bug belowport-0x06 page with bit 0 setadjacent odd member
paired Cport-0x07 pagesamesameport-0x07 page
paired reads from 0x050x07stored register valuesactive C/A/B page valuesstored register valuesstored selector state
forced-RAM overlaysboth modesindependent mode onlyabsentimplemented

Wabbitemu’s reads are therefore not register snapshots in paired mode. Port 0x06 reads visible A, port 0x07 reads visible B, and port 0x05 reads the physical page visible in C without a RAM-type bit. A routine that writes an even page to port 0x06 and reads port 0x07 receives that duplicated even page under the pinned implementation. TilEm and MAME instead return their stored selector bytes from ports 0x050x07. [standard]

Wabbitemu’s paired-B expression

Wabbitemu’s update_bootmap_pages intends to construct the second member of the pair, but the pinned source assigns it with: [standard]

page = normal_page | (!flash_version == 1);

Every supported Plus-family initializer gives flash_version a nonzero value. C operator precedence therefore evaluates !flash_version first, producing zero, and then compares zero with one, again producing zero. The expression is effectively page | 0. An odd port-0x06 selection still produces the usual even/odd pair because A clears its low bit and B preserves the already-set bit. An even selection duplicates the even page into both A and B. TilEm and MAME instead produce the adjacent odd B page. [standard]

This is a Wabbitemu implementation result, not evidence that the ASIC duplicates even pages. [hypothesis] for physical behavior until a hardware test exercises an even selector in paired mode.

MAME’s raw RAM banks and short backing range

For TI-84 Plus Flash values below 0x80, MAME stores value & 0x3F. For RAM values at or above 0x80, it stores the complete byte and passes that byte directly to the address-map bank. It does not reduce the selector modulo eight. Port 0x05 is the exception because its handler stores value & 7. [standard]

The TI-84 Plus banked map provides Flash at offsets 0x0000000x0FFFFF and RAM at 0x2000000x21BFFF. The latter is seven, not eight, 16 KiB pages. Selectors 0x800x86 reach RAM; selector 0x87, port-0x05 = 7, and every higher raw RAM selector land outside the mapped backing range. This boundary follows directly from the MAME address map and is an emulator defect, not a claim that TI-84 Plus RAM page 87 is absent. [standard]

Reset entry and fixed-page handoff

The three emulators do not begin at the same logical address: [standard]

ImplementationReset PCInitial visible pages 0/A/B/CFixed-page handoff
TilEm0x8000Flash 00/3E/3F/3Fnone; page 0 is already fixed
Wabbitemu0x0000Flash 3F/00/00, RAM 80first qualifying opcode fetch in A, or B while paired, changes fixed page 3F to 00
MAME 0.2870x0000Flash 3F/00/01/00a read from A, or from B while paired, clears the boot latch before returning the byte

MAME’s reset initializes selectors 0x050x07 to zero, port 0x04 to one, and m_booting to true. Its fixed window consequently starts on page 3F, while paired A/B are pages 00/01 and C is Flash page 00. The handoff is implemented in read handlers, despite a comment saying it should apply only to opcode fetches. [standard]

The pinned MAME source also swaps model constants in two machine-start functions: the ti83pse start assigns TI84PSE, and ti84pse assigns TI83PSE. The ti84p start correctly assigns TI84P, so the six-bit selector mask described here does execute for this article’s target. The swapped names still make cross-model inferences from this driver unsafe without checking the actual machine configuration and m_model branch. MAME registers the TI-84 Plus driver with MACHINE_NOT_WORKING; this comparison treats its source as an implementation oracle, not a fidelity endorsement. [standard]

Boot mapping transition

The retail boot page contains retail_boot_reset_stub at 3F:4000. Under TilEm’s reset mapping it executes at logical 0x8000: [confirmed]

3F:4000  LD A,0x07
3F:4002  OUT (0x04),A     ; paired mode
3F:4004  LD A,0x7F
3F:4006  OUT (0x06),A     ; A=page 3E, B=page 3F
3F:4008  LD A,0x03
3F:400A  OUT (0x0E),A
3F:400C  JP 0x812C       ; continue on page 3F in window B

Page 0 also contains a restart path at 00:000000:028C. It tests port 0x02 bit 7, writes either 0x1F or 0x03 to port 0x0E, writes 0x7F to port 0x06, selects paired mode, and jumps to the same logical 0x812C. Both values written to 0x0E have low two bits equal to three. [confirmed]

boot_os_entry at 3F:412C changes to independent mode without paging out its next instruction: [confirmed]

3F:412C  IM 1
          ; stack/RAM probe omitted
3F:4142  LD A,0x03
3F:4144  OUT (0x0F),A
3F:4146  LD A,0x7F
3F:4148  OUT (0x07),A     ; C=page 3F while still paired
3F:414A  LD A,0x06
3F:414C  OUT (0x04),A     ; independent: A=3F, B=3F, C=RAM 80
3F:414E  JP 0x4151       ; page 3F remains visible in window A

Boot then maps 0x81 through port 0x07, probes writable RAM at 0xC000 and 0x8000, and programs the execution-protection registers. At 3F:4208 it clears ports 0x0E, 0x0F, and 0x05, writes page 0x3F to port 0x06, and later maps RAM through port 0x07. [confirmed]

The resolved trace records the complete transition:

OUT (0x04) <- 07   paired mode
OUT (0x06) <- 7F   A=page 3E, B=page 3F
OUT (0x0E) <- 03
OUT (0x0F) <- 03
OUT (0x07) <- 7F   C=page 3F
OUT (0x04) <- 06   independent mode
OUT (0x07) <- 81   B=RAM page 81
OUT (0x0E) <- 00
OUT (0x0F) <- 00
OUT (0x05) <- 00   C=RAM page 80
OUT (0x06) <- 3F   A=Flash page 3F
OUT (0x07) <- 80   B=RAM page 80

This sequence shows why a mode change cannot be modeled as three independent port assignments. The meaning of the already-written 0x06 and 0x07 selectors changes when port 0x04 bit 0 changes.

Why RAM helpers clear port 0x0F

Several OS helpers clear port 0x0F immediately before selecting RAM through port 0x07. Representative sites include ram:0B78, 05:5B66, 2F:45A9, 36:74F8, 37:44CA, and 38:7782. They then compute a page pair: [confirmed]

    XOR A
    OUT (0x0F),A
    LD A,B
    SLA A
    OUT (0x05),A       ; even RAM page in window C
    INC A
    OR 0x80
    OUT (0x07),A       ; odd RAM page in window B

Bit 7 of the port-0x07 value is set, so the extended Flash bits do not participate in the resulting RAM page under the public contract, TilEm, or Wabbitemu. MAME has no extended selectors to clear. The clear may be defensive state normalization or compatibility with another ASIC revision. The ROM does not establish that it is required. [hypothesis]

Forced RAM subranges — ports 0x27 and 0x28

The public descriptions and TilEm implement two 64-byte-granularity overlays. For a byte value $n$: [standard]

PortForced logical rangePhysical page
0x270x10000 - 64n through 0xFFFFRAM page 80
0x280x8000 through 0x8000 + 64n - 1RAM page 81

A zero value disables the corresponding overlay. The maximum byte value, 0xFF, leaves one 64-byte block of its 16 KiB window outside the forced range.

OS 2.55MP writes zero to both ports in mode_default_init at 37:6D3A and 37:6D3E. It also clears port 0x27 before RAM-bank tests at 37:72D3 and 3F:45F5. No immediate or dynamic write in the analyzed ROM gives either port a nonzero value. These writes confirm that the OS disables the feature, but they do not confirm the nonzero mapping formula. [confirmed]

Emulator disagreement

The three emulator implementations disagree at the point most useful for a hardware test: [standard]

DetailTilEmWabbitemuMAME 0.287
Overlay active in paired modeyesno; checks !boot_mappedno overlay model
Port 0x28 rangecomplete formula abovecomplete formula above in independent modeport unmapped
Port 0x27 rangecomplete formula abovealso requires the logical address to be at least 0xFB64port unmapped
Read, write, and instruction fetchall resolve through the overlaydata reads/writes use the overlay; execution checks retain some underlying-bank logicunderlying bank only

WikiTI’s historical description says these ports have no effect in paired mode, which agrees with Wabbitemu and disagrees with TilEm. None of these software sources proves the ASIC behavior. Whether the overlays operate in physical paired mode remains a hypothesis. [hypothesis]

Native Wabbitemu mapper edges

A guarded initialized-core run invokes the eight registered mapper handlers and the pinned core’s memory paths directly. Reset reads are 0x08 from port 0x04 and zero from ports 0x050x07, 0x0E, 0x0F, 0x27, and 0x28. The 0x08 is interrupt status, not the mapping mode. The visible reset windows are Flash 3F/00/00 and RAM 80, with independent mode active and hasChangedPage0 clear. [standard]

A data read at 0x4000 leaves fixed page 3F and the handoff flag unchanged. Executing a NOP from the same address changes fixed page 3F to 00, sets hasChangedPage0, and advances the PC to 0x4001. This confirms that Wabbitemu’s fixed-page handoff is an opcode-fetch effect. [standard]

Writing 0xFF to ports 0x0E and 0x0F reads back 0x03. With those high fields set, a raw Flash selector of 0x7F remains stored internally but ports 0x06 and 0x07 read the visible 64-page result 0x3F. RAM selectors 0xFF and 0xFE remain stored while the visible windows read 0x87 and 0x86. Port 0x05 = 0xFF maps and reads RAM page 7 as 0x07. [standard]

The paired-mode case writes C/A/B selectors 0x05, 0x02, and 0x83. Ports 0x050x07 then read 0x03, 0x02, and 0x02; the visible windows are Flash page 2, duplicate Flash page 2, and RAM page 3. Port 0x04 still reads interrupt status 0x08. This exercises the paired-B expression through the registered port handlers. [standard]

Directly seeded backing bytes isolate the two forced ranges. In independent mode with 0x28 = 1 and 0x27 = 0xFF, reads at 0x8000, 0x803F, and 0x8040 return markers 0xB0 and 0xB1 from RAM page 1, then underlying Flash marker 0xA2. Reads at 0xFB63 and 0xFB64 return marker 0xC3 from underlying RAM page 5 and marker 0xD4 from forced RAM page 0. Low-level writes change RAM pages 1 and 0 while leaving the two underlying windows unchanged. A NOP in forced RAM over an underlying Flash HALT executes the NOP. [standard]

Switching only to paired mode changes those five reads to underlying markers 0xE0, 0xE1, 0xE2, 0xF3, and 0xF4. Low-level writes modify the underlying Flash pages while both forced RAM markers remain unchanged. The same NOP/HALT discriminator executes the underlying HALT. These writes call Wabbitemu’s low-level mapper function; they test address routing, not Flash command acceptance. The run establishes emulator behavior only. [standard]

Native MAME mapper edges

A guarded MAME 0.287 run uses five fresh processes so each handoff case starts with m_booting set. The untouched process reports PC = 0x0000, port reads 08 00 00 00 for 0x040x07, and visible Flash prefixes 3E 07, DB 02, 44 6F, and DB 02 in windows 0, A, B, and C. These prefixes identify pages 3F, 00, 01, and 00 in the exact OS 2.55MP image. [standard]

Reading A through Lua’s CPU program space changes the window-0 prefix from page 3F’s 3E 07 to page 00’s DB 02. This MAME Lua access carries read side effects; it is not a side-effect-free debugger peek. Three tiny programs in RAM then perform actual Z80 data reads in separate processes. An independent B read returns page-02 byte 0E and leaves page 3F fixed. An A read returns page-01 byte 44 and fixes page 00. A paired B read returns page-03 byte 02 and also fixes page 00. Each program reaches the expected HALT at 0xC008. [standard]

The selector cases exercise only mapped backing. Flash write 0x41 reads back 01 and exposes page 01; 0x7F reads back 3F and exposes page 3F. RAM selectors 0x80, 0x85, and 0x86 reach seeded pages 0, 5, and 6. Port 0x05 = 0xFE reads back 06 and reaches RAM page 6. In paired mode, port 0x06 = 0x02 exposes adjacent Flash pages 02 and 03, while port 0x07 = 0x83 maps RAM page 3 into C. The probe omits selector 0x87; the pinned address map places that bank beyond its seven mapped RAM pages. [standard]

Ports 0x0E, 0x0F, 0x27, and 0x28 return zero before and after patterned writes. With underlying RAM pages 2 and 3 in B and C, writes at 0x8000 and 0xFB64 change those pages while seeded candidate overlay bytes in RAM pages 1 and 0 remain unchanged. A fetched discriminator executes marker 22 from underlying RAM page 2 rather than marker 11 from candidate overlay page 1. The run therefore covers MAME read, write, and instruction-fetch routing without treating the missing overlay as ASIC evidence. [standard]

Interaction with execution protection

Ports 0x210x26 control Flash and RAM execution permissions. They do not select pages; see Execution protection for their write gate, equations, and boundary discrepancies.

TilEm first resolves a port-0x27 or port-0x28 overlay, then applies the execution rule for the resulting physical RAM page. A fetch forced from a Flash-backed window into RAM is therefore checked as RAM in TilEm. [standard]

Wabbitemu’s fetch check chooses its Flash-versus-RAM branch from the underlying window before adjusting a RAM address for the overlay. A forced RAM range over an underlying Flash page can therefore follow different protection logic from TilEm. This is an emulator fidelity difference, not evidence for either ASIC ordering. [standard]

The analyzed OS leaves both overlays disabled before normal execution, so this difference does not affect the traced boot and homescreen paths. [confirmed]

Safe mapper use

  • Preserve every selector that the routine changes. Ports 0x05, 0x06, 0x07, 0x0E, 0x0F, 0x27, and 0x28 have readable state in the public contract, TilEm, and Wabbitemu. MAME does not implement the latter four. [standard]
  • Do not use IN A,(0x04) to save the memory mode. Reads return interrupt status. Code entered under TI-OS can rely on its documented normal independent mode or must receive the mode from its caller. [standard]
  • Disable interrupts around a temporary mapping unless the interrupt path can run with that mapping. The OS page-83 helpers preserve interrupt state for this reason. [confirmed]
  • When changing paired mode, ensure the next instruction remains mapped. Fixed page 0 is the least state-dependent place to perform the transition. [standard]
  • On family members with more than 128 Flash pages, preserve the matching high selector with each low Flash selector. Restoring only port 0x06 or 0x07 can restore the wrong physical page. [standard]
  • Restore normal TI-84 Plus RAM windows with port 0x07 = 0x81 and port 0x05 = 0x00 when the caller follows the ordinary OS convention. For a general library, restore the values read on entry instead. See RAM pages.

Reproducing the mapping

tools/ti84re/hardware/memory_mapper.py contains explicit documented, tilem, wabbitemu, and mame profiles. tools/ti84re/hardware/describe_memory_mapping.py applies writes and reads, compares profiles, and can emit JSON. List the pinned coverage first:

nix develop -c python3 -m ti84re.hardware.describe_memory_mapping profiles

This reproduces the final TilEm boot state shown above:

nix develop -c python3 -m ti84re.hardware.describe_memory_mapping \
  map --profile tilem \
  --write 0x0e=3 --write 6=0x7f \
  --write 0x0f=3 --write 7=0x7f --write 4=6 \
  --write 7=0x81 --write 0x0e=0 --write 0x0f=0 \
  --write 5=0 --write 6=0x3f --write 7=0x80

An even paired selector exposes Wabbitemu’s duplicated B page while also showing MAME’s ignored high-selector and overlay writes:

nix develop -c python3 -m ti84re.hardware.describe_memory_mapping compare \
  --write 4=1 --write 6=2 \
  --write 0x0e=3 --write 0x27=0xff --write 0x28=1

To reproduce MAME’s fixed-page read latch and machine-read the result:

nix develop -c python3 -m ti84re.hardware.describe_memory_mapping --json \
  map --profile mame --read 0x4000

The trace resolver uses the same library. To show the executed boot writes:

nix develop -c python3 -m ti84re.trace.resolve /tmp/boot.trace \
  --initial-mapping ti84p-reset --page-switches \
  --io-ports 04-07,0e-0f,27-28

Static whole-ROM port scans are candidate generators because data can decode as instructions. Add context and verify control flow before treating a hit as code:

nix develop -c python3 -m ti84re.rom.analyze_io \
  --before 8 --after 8 0x0e-0x0f,0x27-0x28

tools/ti84re/emulators/wabbitemu/mapper_probe.py derives the native edge expectations from the same mapper profile. tools/ti84re/emulators/wabbitemu/run_mapper_edge_probe.py requires the exact OS 2.55MP ROM and writes a hash-complete JSON manifest.

tools/ti84re/emulators/mame/mapper.py derives the corresponding MAME oracle from the reusable profile and pinned ROM prefixes. The guarded CLI runs every latch case from a fresh machine:

mame_mapper_parent=$(mktemp -d /tmp/ti84-mame-mapper.XXXXXX)
nix shell nixpkgs#mame --command python3 -m ti84re.emulators.mame.run_mapper_probe \
  --expected-mame-sha256 \
    fc5f4aba1aa6eb115d66decad13bb3f5313b9f3be9cff7c785d8d88e3fca0b91 \
  --output-dir "$mame_mapper_parent/run" --json

Open physical tests

  • Write nonzero values to ports 0x27 and 0x28 in independent mode and test both range boundaries with reads and writes.
  • Repeat the boundary tests in paired mode to distinguish TilEm from Wabbitemu and the historical WikiTI claim.
  • Execute controlled code on each side of an overlay boundary while varying ports 0x210x26; record whether protection follows the underlying window or the forced RAM page.
  • Test port 0x27 below 0xFB64 to determine whether Wabbitemu’s additional cutoff models hardware or is an emulator-specific restriction.
  • Read ports 0x0E and 0x0F after writing values with upper bits set on TA2, TA3, and larger-Flash family members.
  • Select an even Flash page through port 0x06 in paired mode and verify that window B exposes the adjacent odd page rather than Wabbitemu’s duplicate.
  • Select RAM page 87 through ports 0x05, 0x06, and 0x07; this confirms the physical page independently of MAME’s seven-page backing-map defect.

Sources

SourceUse
OS 2.55MP rom.bin, especially 00:0000029C, 3F:40004210, 37:44AE, and 37:6D33executed selector sequences and reset values
TilEm x4_io.c and x4_memory.cmapping modes, 64-page masks, overlays, and protection order
Wabbitemu 83psehw.c and core.cextended selectors, paired mode, overlays, and independent comparison
MAME 0.287 ti85.cpp and ti85_m.cppmapped ports, bank backing, selector writes, reset mapping, and read-latch behavior
jsTIfied deployed 20170706a artifact and readable mirrorfourth source implementation of selector, paired-mode, and overlay routing; the deployed artifact is pinned by tools/ti84re/emulators/jstified.py
WikiTI port 0x04, 0x0E, 0x0F, 0x27, and 0x28historical public register descriptions checked against ROM and emulators