mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
docs: address units resolved from MAME source (map is in BITS; bytes = bit>>3) + two corrections
This commit is contained in:
1 parent
93fb92d807
commit
99ca146fe3
2 files changed
+114
-60
No files matched your search
@@ -721,9 +721,57 @@ cross-check: run the catch-all and a layered proxy over the **same** range in th
|
||||
run, and see which one reports. Whichever is trustworthy calibrates the rest; the other gets
|
||||
fixed or discarded.
|
||||
|
||||
## ADDRESS UNITS RESOLVED — the map is in BITS (2026-10-16)
|
||||
|
||||
Authoritative, from MAME's own source rather than inference:
|
||||
|
||||
```
|
||||
src/devices/cpu/tms34010/tms34010.h:991
|
||||
memory_access<32, 1, 3, ENDIANNESS_LITTLE>::specific m_program;
|
||||
^ data_width = 1 BIT
|
||||
|
||||
src/emu/emumem.h:2078
|
||||
inline offs_t addr2byte(offs_t address) const {
|
||||
return (m_addr_shift < 0) ? (address << -m_addr_shift) : (address >> m_addr_shift);
|
||||
}
|
||||
```
|
||||
|
||||
* The TMS34010 program space declares **`data_width = 1`**, so **address-map units are
|
||||
BITS**, not bytes and not words.
|
||||
* `addr2byte(addr) = addr >> 3` → **bytes = bit address / 8**.
|
||||
* This reconciles the measurement that a `.ram()` over `0x00000000-0x01FFFFFF` reports
|
||||
`bytes() == 0x400000`: `0x2000000 >> 3 == 0x400000` (4 MiB). The units were consistent
|
||||
all along; only my interpretation of them was not.
|
||||
|
||||
**Read every address in this file, in the driver's map, and in the logs as a BIT address,
|
||||
and divide by 8 for bytes.** So the video-region traffic the catch-all reported at
|
||||
`0x400000`-`0x40D7FF` means bytes `0x80000`-`0x81AFF` — a **64 KiB** region, which is a
|
||||
plausible VRAM size and the first time that number has rested on something solid.
|
||||
|
||||
### Two corrections this forced
|
||||
|
||||
1. **`DETECT_OVERLAPPING_MEMORY` is `(0)`** (`src/emu/addrmap.cpp:20`). MAME silently
|
||||
permits overlapping map entries and never warns. An earlier step in this project used
|
||||
"no overlap warning appeared" as evidence that two entries did not overlap — **that
|
||||
evidence was void.**
|
||||
2. **Handlers receive the offset within their own entry.** `populate_map_entry` installs
|
||||
entries in list order (`emumem_mview.cpp:478-481`) and MAME subtracts the entry's start,
|
||||
so a start-`0` entry (RAM, the catch-all, the calibration proxies) sees the absolute
|
||||
address, while the board windows (start `0x06200000`) see `address - 0x06200000`.
|
||||
|
||||
### Still open — and now sharply posed
|
||||
|
||||
With bit units, RAM genuinely covers bit `0x400000`, so the catch-all should never have seen
|
||||
traffic there; yet it logged 123,411 accesses. The precedence rule must be subtler than
|
||||
"later wins". MAME has a distinct path, `populate_mismatched(...)`, for handler-tree
|
||||
conflicts (`emumem_mview.cpp:257` and `:293`) — the open question is whether resolution
|
||||
differs when the overlapping handlers have the **same** width versus **different** widths.
|
||||
A dedicated cross-check is measuring exactly that.
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
CLOSE THE INSTRUMENT DISAGREEMENT FIRST (one cross-check run).
|
||||
Then model video memory and re-run the level-1 check via the console capture.
|
||||
1. Settle the overlap/precedence rule (cross-check in flight).
|
||||
2. Model video memory using BIT addresses; the region is ~64 KiB starting at bit 0x400000.
|
||||
3. Re-run the level-1 console check after each change.
|
||||
+64
-58
@@ -70,6 +70,7 @@
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "vt1200_board.h"
|
||||
@@ -160,21 +161,28 @@ private:
|
||||
optional_shared_ptr<u16> m_vram;
|
||||
|
||||
// VT1200_CAL=<path>
|
||||
// Address-unit and map-precedence calibration. Registers a PROXY over:
|
||||
// (a) a low-RAM slice 0x00000000-0x0000FFFF -- functionally identical to
|
||||
// RAM (a backing array) but logging. If this logs, later entries win
|
||||
// over earlier ones and handlers can be layered; if it never logs,
|
||||
// earlier entries win.
|
||||
// (b) three candidate encodings of the video region, to discover which one
|
||||
// the blitter actually addresses.
|
||||
// All registered at the END of program_map so precedence is unambiguous.
|
||||
// Address-unit and map-precedence cross-check. Each probe is registered at
|
||||
// the END of program_map (so, if precedence is last-wins, it wins its
|
||||
// slice) and logs the delegate offset `off` it is handed. It also prints
|
||||
// the space address reconstructed under the two candidate unit rules:
|
||||
// space4 = base + (off << 4) (delegate off = space-bit-address >> 4)
|
||||
// space0 = base + off (delegate off = space-bit-address)
|
||||
// Whichever rule yields a coherent picture for the positive control is the
|
||||
// real one. See XCROSS_REPORT.md.
|
||||
FILE *m_cal_log = nullptr;
|
||||
std::map<std::pair<u32, u32>, u32> m_cal_seen;
|
||||
std::map<std::tuple<u32, u32, u32>, u32> m_cal_seen; // (base, off, pc) -> count
|
||||
std::vector<u16> m_cal_ram;
|
||||
int m_cal_ram_lo = 0;
|
||||
u16 cal_r(offs_t off);
|
||||
void cal_w(offs_t off, u16 data);
|
||||
void log_cal(const char *tag, char kind, u32 addr);
|
||||
void log_probe(const char *tag, char kind, u32 off, u32 base);
|
||||
|
||||
// One read/write pair per probe so each knows its own base address. These
|
||||
// bases are SPACE (bit) addresses, matching the driver's map entries.
|
||||
u16 calctrl_r(offs_t off); void calctrl_w(offs_t off, u16 data); // 0x00000000 control
|
||||
u16 calvida_r(offs_t off); void calvida_w(offs_t off, u16 data); // 0x00400000 (old VID-A)
|
||||
u16 calvid4m_r(offs_t off); void calvid4m_w(offs_t off, u16 data); // 0x04000000 (0x400000<<4)
|
||||
u16 calram80_r(offs_t off); void calram80_w(offs_t off, u16 data); // 0x00800000
|
||||
u16 calram100_r(offs_t off); void calram100_w(offs_t off, u16 data); // 0x01000000
|
||||
u16 calram180_r(offs_t off); void calram180_w(offs_t off, u16 data); // 0x01800000
|
||||
u16 calram200_r(offs_t off); void calram200_w(offs_t off, u16 data); // 0x02000000 (outside RAM)
|
||||
|
||||
// VT1200_LOG_UNMAPPED=<path>
|
||||
// A catch-all mapping over the whole address space, registered FIRST so every
|
||||
@@ -294,54 +302,46 @@ void vt1200_state::machine_start()
|
||||
m_log ? "on" : "off", m_render ? 1 : 0, m_dump_frame);
|
||||
}
|
||||
|
||||
void vt1200_state::log_cal(const char *tag, char kind, u32 addr)
|
||||
void vt1200_state::log_probe(const char *tag, char kind, u32 off, u32 base)
|
||||
{
|
||||
if (!m_cal_log)
|
||||
return;
|
||||
const u32 p = (u32)m_maincpu->state_int(TMS34010_PC);
|
||||
auto key = std::make_pair(addr, ((p << 8) | (u8)kind));
|
||||
auto key = std::make_tuple(base, off, (p << 8) | (u8)kind);
|
||||
if (m_cal_seen.find(key) == m_cal_seen.end())
|
||||
{
|
||||
m_cal_seen.emplace(key, 1);
|
||||
fprintf(m_cal_log, "%s %c %08X pc=%08X\n", tag, kind, addr, p);
|
||||
// space4: the rule "delegate off = space address >> 4". space0: off is
|
||||
// already the space address. Only one of them can be right for a run.
|
||||
fprintf(m_cal_log, "%s %c off=%08X space4=%08X space0=%08X pc=%08X\n",
|
||||
tag, kind, off, base + (off << 4), base + off, p);
|
||||
fflush(m_cal_log);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *cal_tag(u32 addr)
|
||||
{
|
||||
if (addr >= 0x00400000 && addr <= 0x00400fff) return "VID-A";
|
||||
if (addr >= 0x00040000 && addr <= 0x00040fff) return "VID-B";
|
||||
if (addr >= 0x00004000 && addr <= 0x00004fff) return "VID-C";
|
||||
// Catch-all address 0x400000 (reported in bits) divided by 8:
|
||||
if (addr >= 0x00080000 && addr <= 0x00080fff) return "VID-D";
|
||||
if (addr >= 0x00020000 && addr <= 0x00020fff) return "VID-E";
|
||||
return "ABOVE2M";
|
||||
}
|
||||
// The control probe shadows the very bottom of RAM (bit 0..0xffff = byte
|
||||
// 0..0x1fff). It behaves like RAM via a small backing array so it perturbs as
|
||||
// little as possible, and it MUST fire if last-wins precedence holds.
|
||||
u16 vt1200_state::calctrl_r(offs_t off) { log_probe("CTRL", 'R', (u32)off, 0x00000000); return m_cal_ram[(u32)off % m_cal_ram.size()]; }
|
||||
void vt1200_state::calctrl_w(offs_t off, u16 data) { log_probe("CTRL", 'W', (u32)off, 0x00000000); m_cal_ram[(u32)off % m_cal_ram.size()] = data; }
|
||||
|
||||
u16 vt1200_state::cal_r(offs_t off)
|
||||
{
|
||||
const u32 addr = (u32)off;
|
||||
if (addr < 0x10000)
|
||||
{
|
||||
log_cal("RAMSLICE", 'R', addr);
|
||||
return m_cal_ram[addr];
|
||||
}
|
||||
log_cal(cal_tag(addr), 'R', addr);
|
||||
return 0;
|
||||
}
|
||||
u16 vt1200_state::calvida_r(offs_t off) { log_probe("VID-A-0x00400000", 'R', (u32)off, 0x00400000); return 0; }
|
||||
void vt1200_state::calvida_w(offs_t off, u16 data) { log_probe("VID-A-0x00400000", 'W', (u32)off, 0x00400000); }
|
||||
|
||||
void vt1200_state::cal_w(offs_t off, u16 data)
|
||||
{
|
||||
const u32 addr = (u32)off;
|
||||
if (addr < 0x10000)
|
||||
{
|
||||
log_cal("RAMSLICE", 'W', addr);
|
||||
m_cal_ram[addr] = data;
|
||||
return;
|
||||
}
|
||||
log_cal(cal_tag(addr), 'W', addr);
|
||||
}
|
||||
u16 vt1200_state::calvid4m_r(offs_t off) { log_probe("VID-4M-0x04000000", 'R', (u32)off, 0x04000000); return 0; }
|
||||
void vt1200_state::calvid4m_w(offs_t off, u16 data) { log_probe("VID-4M-0x04000000", 'W', (u32)off, 0x04000000); }
|
||||
|
||||
u16 vt1200_state::calram80_r(offs_t off) { log_probe("RAM-0x00800000", 'R', (u32)off, 0x00800000); return 0; }
|
||||
void vt1200_state::calram80_w(offs_t off, u16 data) { log_probe("RAM-0x00800000", 'W', (u32)off, 0x00800000); }
|
||||
|
||||
u16 vt1200_state::calram100_r(offs_t off) { log_probe("RAM-0x01000000", 'R', (u32)off, 0x01000000); return 0; }
|
||||
void vt1200_state::calram100_w(offs_t off, u16 data) { log_probe("RAM-0x01000000", 'W', (u32)off, 0x01000000); }
|
||||
|
||||
u16 vt1200_state::calram180_r(offs_t off) { log_probe("RAM-0x01800000", 'R', (u32)off, 0x01800000); return 0; }
|
||||
void vt1200_state::calram180_w(offs_t off, u16 data) { log_probe("RAM-0x01800000", 'W', (u32)off, 0x01800000); }
|
||||
|
||||
u16 vt1200_state::calram200_r(offs_t off) { log_probe("RAM-0x02000000", 'R', (u32)off, 0x02000000); return 0; }
|
||||
void vt1200_state::calram200_w(offs_t off, u16 data) { log_probe("RAM-0x02000000", 'W', (u32)off, 0x02000000); }
|
||||
|
||||
void vt1200_state::machine_reset()
|
||||
{
|
||||
@@ -417,19 +417,25 @@ void vt1200_state::program_map(address_map &map)
|
||||
map(0xbf200000, 0xbfffffff).rom().region("maincpu", 0);
|
||||
map(0xff200000, 0xffffffff).rom().region("maincpu", 0);
|
||||
|
||||
// Calibration probes. Registered last so precedence is unambiguous.
|
||||
// Calibration cross-check. Every probe is registered LAST, so under
|
||||
// last-wins it wins its own slice. Bases are SPACE (bit) addresses.
|
||||
if (getenv("VT1200_CAL"))
|
||||
{
|
||||
m_cal_ram.assign(0x10000, 0);
|
||||
map(0x00000000, 0x0000ffff).rw(FUNC(vt1200_state::cal_r), FUNC(vt1200_state::cal_w));
|
||||
map(0x00400000, 0x00400fff).rw(FUNC(vt1200_state::cal_r), FUNC(vt1200_state::cal_w));
|
||||
map(0x00040000, 0x00040fff).rw(FUNC(vt1200_state::cal_r), FUNC(vt1200_state::cal_w));
|
||||
map(0x00004000, 0x00004fff).rw(FUNC(vt1200_state::cal_r), FUNC(vt1200_state::cal_w));
|
||||
map(0x00080000, 0x00080fff).rw(FUNC(vt1200_state::cal_r), FUNC(vt1200_state::cal_w));
|
||||
map(0x00020000, 0x00020fff).rw(FUNC(vt1200_state::cal_r), FUNC(vt1200_state::cal_w));
|
||||
// Broad net: everything above 2 MiB that we do not already map. RAM
|
||||
// rarely reaches here, so a log-only proxy is survivable.
|
||||
map(0x00200000, 0x01ffffff).rw(FUNC(vt1200_state::cal_r), FUNC(vt1200_state::cal_w));
|
||||
// Positive control: proven to fire. Last-wins -> this shadows the
|
||||
// bottom 64K bits of RAM.
|
||||
map(0x00000000, 0x0000ffff).rw(FUNC(vt1200_state::calctrl_r), FUNC(vt1200_state::calctrl_w));
|
||||
// The original disputed "video" range (a space address inside RAM).
|
||||
map(0x00400000, 0x004fffff).rw(FUNC(vt1200_state::calvida_r), FUNC(vt1200_state::calvida_w));
|
||||
// The catch-all's logged 0x400000 read as a space address, times 16:
|
||||
// 0x400000 << 4 = 0x04000000.
|
||||
map(0x04000000, 0x040fffff).rw(FUNC(vt1200_state::calvid4m_r), FUNC(vt1200_state::calvid4m_w));
|
||||
// Where does RAM actually end? Probes at three MiB marks of the
|
||||
// declared 4 MiB range, plus one OUTSIDE it (0x02000000).
|
||||
map(0x00800000, 0x00800fff).rw(FUNC(vt1200_state::calram80_r), FUNC(vt1200_state::calram80_w));
|
||||
map(0x01000000, 0x01000fff).rw(FUNC(vt1200_state::calram100_r), FUNC(vt1200_state::calram100_w));
|
||||
map(0x01800000, 0x01800fff).rw(FUNC(vt1200_state::calram180_r), FUNC(vt1200_state::calram180_w));
|
||||
map(0x02000000, 0x02000fff).rw(FUNC(vt1200_state::calram200_r), FUNC(vt1200_state::calram200_w));
|
||||
}
|
||||
|
||||
// Undecoded board windows. Left unmapped unless an experiment asks for
|
||||
|
||||
Reference in new issue
Block a user