Files

101 lines
4.3 KiB
C++

// VT1200 board register model. Deliberately free of MAME dependencies so it can
// be unit-tested with plain g++.
#pragma once
#include <cstdint>
#include <map>
// Window bases in the harness's address units (disassembly operand >> 4).
static const uint32_t VT1200_WIN0 = 0x05800000; // data port of the DMA pair
static const uint32_t VT1200_WIN1 = 0x05900000; // command port of the DMA pair
static const uint32_t VT1200_WIN2 = 0x06200000; // big: STATUS +0x10, CMD +0x20
static const uint32_t VT1200_WIN3 = 0x06400000; // big, plus the monitor switch
// Window-relative register offsets IN HARNESS UNITS.
//
// The harness address is the firmware's operand shifted right by 4 (MAME's
// TMS34010 space is word-unit here), so an operand offset of +0x10 is harness
// +0x01, and an operand offset of +0xD0 is harness +0x0d. Getting this wrong
// makes registers silently unreachable, so always use these names.
//
// firmware operand harness offset role
// +0x10 0x01 STATUS (bit 0 = ready/done)
// +0x20 0x02 COMMAND / DATA
// +0x30 0x03 (read/written in the same block)
// +0xD0 0x0d mixed I/O -- monitor switch in bits 4-6
// +0xE0 0x0e
// +0xF0 0x0f
static const uint32_t VT1200_OFF_STATUS = 0x0001;
static const uint32_t VT1200_OFF_CMD = 0x0002;
static const uint32_t VT1200_OFF_IO30 = 0x0003;
static const uint32_t VT1200_OFF_SWITCH = 0x000d;
static const uint32_t VT1200_OFF_E0 = 0x000e;
static const uint32_t VT1200_OFF_F0 = 0x000f;
class vt1200_board
{
public:
vt1200_board() = default;
// Configuration (replaces the test-time env knobs).
void set_default(uint16_t v) { m_default = v; }
void set_override(uint32_t addr, uint16_t v) { m_override[addr] = v; }
void set_model_handshake(bool on) { m_handshake = on; }
// Per-window busy counts. Each of the four windows owns its own count, so
// the two big windows (0x06200000 and 0x06400000) can be tuned
// independently. set_busy_ticks is shorthand that applies to every window.
void set_busy_ticks(int n)
{
m_busy_ticks_by_win[VT1200_WIN0] = n;
m_busy_ticks_by_win[VT1200_WIN1] = n;
m_busy_ticks_by_win[VT1200_WIN2] = n;
m_busy_ticks_by_win[VT1200_WIN3] = n;
}
void set_window_busy_ticks(uint32_t window_base, int n) { m_busy_ticks_by_win[window_base] = n; }
// DMA command/data pair at WIN0 (data) / WIN1 (command). A write to the
// command port is accepted and reads back its value for n ticks; after the
// ticks elapse the command port reads back 0. n == 0 (the default) leaves
// the pair with no DMA semantics, so the port just behaves as a latch.
void set_dma_ticks(int n) { m_dma_ticks = n; }
// Monitor switch (bits 4-6 of the switch port). The argument is accepted
// unambiguously as EITHER the raw register bits (e.g. 0x70) OR a small
// position 0-7: a value above 0x07 is taken as the raw bit pattern, any
// value <= 0x07 is a position and is shifted into bits 4-6. The input mix
// is only applied to reads after this has been called.
void set_monitor_switch(uint8_t bits_or_position)
{
m_switch_bits = (uint16_t)(bits_or_position > 0x07
? bits_or_position : ((bits_or_position & 0x07) << 4));
m_switch_set = true;
}
// Bus interface.
uint16_t read(uint32_t addr);
void write(uint32_t addr, uint16_t data);
void tick();
private:
bool is_switch_port(uint32_t addr) const;
std::map<uint32_t, uint16_t> m_store; // write-back latches
std::map<uint32_t, uint16_t> m_override; // fixed values (experiments)
uint16_t m_default = 0;
bool m_handshake = false;
// Busy state machines, keyed by window base (addr & 0xffff0000): how many
// ticks each window stays busy after a command write, and the remaining
// count for the command currently in flight.
std::map<uint32_t, int> m_busy_ticks_by_win;
std::map<uint32_t, int> m_busy_left;
// DMA command/data pair. m_dma_ticks is the configured completion time;
// m_dma_left is how many ticks remain for the command in flight; m_dma_cmd
// is the value written to the command port. All three only have meaning
// when m_dma_ticks > 0.
int m_dma_ticks = 0;
int m_dma_left = 0;
uint16_t m_dma_cmd = 0;
bool m_switch_set = false; // set_monitor_switch was called
uint16_t m_switch_bits = 0;
};