#include "vt1200_board.h" bool vt1200_board::is_switch_port(uint32_t addr) const { // The monitor-selection switch lives in bits 4-6 of window 3's +0xD0 // register (harness offset 0x0d). return addr == (VT1200_WIN3 + VT1200_OFF_SWITCH); } uint16_t vt1200_board::read(uint32_t addr) { auto ov = m_override.find(addr); if (ov != m_override.end()) return ov->second; uint16_t value = m_default; auto st = m_store.find(addr); if (st != m_store.end()) value = st->second; // DMA command port: while a command is in flight the port reads back the // latched command; once the configured ticks elapse it reads back 0. if (m_dma_ticks > 0 && (addr & 0xffff0000) == VT1200_WIN1) return (m_dma_left > 0) ? m_dma_cmd : (uint16_t)0x0000; if (m_switch_set && is_switch_port(addr)) return (uint16_t)((value & 0xff8f) | (m_switch_bits & 0x0070)); if (m_handshake && (addr & 0xffff) == VT1200_OFF_STATUS) { auto busy = m_busy_left.find(addr & 0xffff0000); if (busy != m_busy_left.end() && busy->second > 0) value |= 0x0001; else value &= ~0x0001; } return value; } void vt1200_board::write(uint32_t addr, uint16_t data) { m_store[addr] = data; if (m_handshake && (addr & 0xffff) == VT1200_OFF_CMD) { const uint32_t win = addr & 0xffff0000; auto ticks = m_busy_ticks_by_win.find(win); m_busy_left[win] = (ticks != m_busy_ticks_by_win.end()) ? ticks->second : 0; } // A command written to the DMA command port (WIN1) is latched and, when the // DMA model is configured, starts its completion timer. if ((addr & 0xffff0000) == VT1200_WIN1) { m_dma_cmd = data; if (m_dma_ticks > 0) m_dma_left = m_dma_ticks; } } void vt1200_board::tick() { // Advance every window's state machine, not just the one last touched. for (auto &entry : m_busy_left) if (entry.second > 0) entry.second--; // Merge the DMA pair's timer into the same tick. if (m_dma_left > 0) m_dma_left--; }