diff options
author | Michael Zapf <Michael.Zapf@mizapf.de> | 2018-03-14 18:17:00 +0100 |
---|---|---|
committer | Michael Zapf <Michael.Zapf@mizapf.de> | 2018-03-31 00:38:31 +0200 |
commit | fda26ee7dded25d83e4936d906984bf40a2ae980 (patch) | |
tree | c50e7428c1ddf7050df047fb58013088dff747a5 | |
parent | bdc4288fe117b65ee11438e1e1e5601219e859f7 (diff) |
ti99: Hexbus floppy system; logging updates
-rw-r--r-- | scripts/src/bus.lua | 2 | ||||
-rw-r--r-- | src/devices/bus/hexbus/hexbus.cpp | 83 | ||||
-rw-r--r-- | src/devices/bus/hexbus/hexbus.h | 24 | ||||
-rw-r--r-- | src/devices/bus/hexbus/hx5102.cpp | 665 | ||||
-rw-r--r-- | src/devices/bus/hexbus/hx5102.h | 79 | ||||
-rw-r--r-- | src/devices/bus/hexbus/tp0370.cpp | 340 | ||||
-rw-r--r-- | src/devices/bus/hexbus/tp0370.h | 85 | ||||
-rw-r--r-- | src/devices/bus/ti99/internal/998board.cpp | 435 | ||||
-rw-r--r-- | src/devices/bus/ti99/internal/998board.h | 63 | ||||
-rw-r--r-- | src/devices/cpu/tms9900/tms9995.cpp | 301 |
10 files changed, 1703 insertions, 374 deletions
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 95761c42aef..5dc09dceda3 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -870,6 +870,8 @@ if (BUSES["HEXBUS"]~=null) then MAME_DIR .. "src/devices/bus/hexbus/hexbus.h", MAME_DIR .. "src/devices/bus/hexbus/hx5102.cpp", MAME_DIR .. "src/devices/bus/hexbus/hx5102.h", + MAME_DIR .. "src/devices/bus/hexbus/tp0370.cpp", + MAME_DIR .. "src/devices/bus/hexbus/tp0370.h", } end diff --git a/src/devices/bus/hexbus/hexbus.cpp b/src/devices/bus/hexbus/hexbus.cpp index 907c77fa745..257a82b5054 100644 --- a/src/devices/bus/hexbus/hexbus.cpp +++ b/src/devices/bus/hexbus/hexbus.cpp @@ -128,6 +128,11 @@ By default, instances of "hexbus_chained_device" own an outbound hexbus slot as a subdevice; this may be overwritten by subclasses. + Line state received via the Hexbus + +------+------+------+------+------+------+------+------+ + | ADB3 | ADB2 | - | HSK* | 0 | BAV* | ADB1 | ADB0 | + +------+------+------+------+------+------+------+------+ + References ---------- @@ -145,8 +150,14 @@ // Devices #include "hx5102.h" +#define LOG_WRITE (1U<<1) // Write operation + +#define VERBOSE ( LOG_GENERAL ) + +#include "logmacro.h" + // Hexbus instance -DEFINE_DEVICE_TYPE_NS(HEXBUS, bus::hexbus, hexbus_device, "hexbus", "Hexbus") +DEFINE_DEVICE_TYPE_NS(HEXBUS, bus::hexbus, hexbus_device, "hexbus", "Hexbus connector") namespace bus { namespace hexbus { @@ -226,24 +237,20 @@ void hexbus_chained_device::hexbus_write(uint8_t data) { m_myvalue = data; - uint8_t inbound_value = 0xff; - uint8_t outbound_value = 0xff; - - // Determine the current bus level from the values of the - // other devices left and right from us - if (m_hexbus_inbound != nullptr) - inbound_value = m_hexbus_inbound->read(INBOUND); - - if (m_hexbus_outbound != nullptr) - outbound_value = m_hexbus_outbound->read(OUTBOUND); + uint8_t otherval = hexbus_get_levels(); + // LOGMASKED(LOG_WRITE, ".. otherval=%02x\n", otherval); // What is the new bus level? - uint8_t newvalue = inbound_value & outbound_value & m_myvalue; + // The data lines are not supposed to be set by multiple devices + // We assume that sending data overrides all data line levels. + // This is emulated by pulling the data lines to ones. + uint8_t newvalue = (otherval | 0xc3) & m_myvalue; // If it changed, propagate to both directions. if (newvalue != m_current_bus_value) { - hexbus_value_changed(newvalue); + LOGMASKED(LOG_WRITE, "Trying to write %02x, actually: %02x (current=%02x)\n", data, newvalue, m_current_bus_value); + m_current_bus_value = newvalue; if (m_hexbus_inbound != nullptr) @@ -251,10 +258,29 @@ void hexbus_chained_device::hexbus_write(uint8_t data) if (m_hexbus_outbound != nullptr) m_hexbus_outbound->write(OUTBOUND, m_current_bus_value); + } } /* + Get levels from other devices (without changing anything). +*/ +uint8_t hexbus_chained_device::hexbus_get_levels() +{ + uint8_t inbound_value = 0xff; + uint8_t outbound_value = 0xff; + + // other devices left and right from us + if (m_hexbus_inbound != nullptr) + inbound_value = m_hexbus_inbound->read(INBOUND); + + if (m_hexbus_outbound != nullptr) + outbound_value = m_hexbus_outbound->read(OUTBOUND); + + return (inbound_value & outbound_value); +} + +/* Called from the Hexbus user, that is, the device that subclasses hexbus_chained_device, like the HX5102 */ @@ -284,20 +310,33 @@ void hexbus_chained_device::bus_write(int dir, uint8_t data) { hexbus_device* hexbuscont = (dir == INBOUND)? m_hexbus_inbound : m_hexbus_outbound; - // Notify device - if (data != m_current_bus_value) - hexbus_value_changed(data); + // Propagate this value first + if (hexbuscont != nullptr) + hexbuscont->write(dir, data); + uint8_t oldvalue = m_current_bus_value; m_current_bus_value = data; - // Propagate - if (hexbuscont != nullptr) - hexbuscont->write(dir, data); + // Notify device + // Caution: Calling hexbus_value_changed may cause further activities + // that change the bus again + if (data != oldvalue) + { + LOGMASKED(LOG_WRITE, "Hexbus value changed: %02x -> %02x\n", oldvalue, data); + hexbus_value_changed(data); + } } -MACHINE_CONFIG_START(hexbus_chained_device::device_add_mconfig) - MCFG_HEXBUS_ADD("hexbus") -MACHINE_CONFIG_END +/* + Convenience function to calculate the bus value. Used by subclasses. +*/ +uint8_t hexbus_chained_device::to_line_state(uint8_t data, bool bav, bool hsk) +{ + uint8_t lines = ((data & 0x0c)<<4) | (data & 0x03); + if (!bav) lines |= 0x04; + if (!hsk) lines |= 0x10; + return lines; +} // ------------------------------------------------------------------------ diff --git a/src/devices/bus/hexbus/hexbus.h b/src/devices/bus/hexbus/hexbus.h index 3c3280cca91..d94a91c47a5 100644 --- a/src/devices/bus/hexbus/hexbus.h +++ b/src/devices/bus/hexbus/hexbus.h @@ -23,6 +23,15 @@ enum OUTBOUND = 1 }; +/* Line */ +enum +{ + HEXBUS_LINE_HSK = 0x10, + HEXBUS_LINE_BAV = 0x04, + HEXBUS_LINE_BIT32 = 0xc0, + HEXBUS_LINE_BIT10 = 0x03 +}; + class hexbus_device; class hexbus_chained_device; @@ -54,8 +63,6 @@ public: virtual void device_start() override; protected: - virtual void device_add_mconfig(machine_config &config) override; - void set_outbound_hexbus(hexbus_device *outbound) { m_hexbus_outbound = outbound; } // Link to the inbound Hexbus (if not null, see Oso chip) @@ -72,13 +79,24 @@ protected: virtual void bus_write(int dir, uint8_t data) override; // Methods to be used from subclasses + // Write a byte to the Hexbus. Returns the actual line state. + // This is important because the bus is a wired-and bus. void hexbus_write(uint8_t data); + + // Levels on the bus, except for this device + uint8_t hexbus_get_levels(); + + // Read hexbus uint8_t hexbus_read(); - // For interrupts + // Callback for changes on the hexbus virtual void hexbus_value_changed(uint8_t data) { }; + // Levels of the lines at this device. 0 means pull down, 1 means release. uint8_t m_myvalue; + + // Utility method to create a Hexbus line state + uint8_t to_line_state(uint8_t data, bool bav, bool hsk); }; // ------------------------------------------------------------------------ diff --git a/src/devices/bus/hexbus/hx5102.cpp b/src/devices/bus/hexbus/hx5102.cpp index 71fe674506f..03d00497741 100644 --- a/src/devices/bus/hexbus/hx5102.cpp +++ b/src/devices/bus/hexbus/hx5102.cpp @@ -5,30 +5,683 @@ Hexbus floppy disk drive HX5102 - Work in progress + Memory map + 0000 - 1FFF: ROM1 (8 KiB, circuit u25, EPROM 2564) + 2000 - 3FFF: ROM2 (8 KiB, circuit u29, EPROM 2564) + 4000 - DFFF: Mirrors of ROM1/ROM2 + E000 - EFFF: SRAM (4 KiB) + F000 - F0F9: On-Chip RAM (TMS9995) + F7E0 - F7EF: Memory-mapped access to NEC uPD765 / Intel 8272A + F7F0 - F7FF: Memory-mapped access to IBC + F800 - FFF9: Unmapped + FFFA - FFFF: On-Chip RAM (TMS9995) + + NEC uPD765 / Intel 8272A + F7E0 R Main status register (MSR) + F7E4 R Data register (FIFO read) + F7E8 W Command register (FIFO write) + + Supporting circuitry + F7E2 R DMA read + F7E6 - - + F7EA W DMA write + F7EC W Ready lock + F7EE - - + + Intelligent Bus Controller (Hexbus) + F7F0 R Received data + F7F2 R Status register + F7F4 - + F7F6 - + F7F8 W Transmit data + F7FA W Control register + F7FC - + F7FE - + + Ports (CRU bit): read + 17E0 (0): Controller INT line + 17E2 (1): Motor spinning (monoflop 1) + 17E4 (2): Timeout for disk operations (monoflop 2) + 17E6 (3): - + 17E8 (4): Drive 0 cylinder count (0=40, 1=77) + 17EA (5): Drive 1 cylinder count + 17EC (6): Drive 2 cylinder count + 17EE (7): Drive 3 cylinder count + + Ports (CRU bit): write + 17E0 (0): Precompensation + 17E2 (1): Motor trigger + 17E4 (2): - + 17E6 (3): Step dir (1=inwards) + 17E8 (4): When 1, assert DACK* (set to 0) + 17EA (5): Step pulse (up) + 17EC (6): Timeout flipflop trigger + 17EE (7): RESET* the controller (goes to RESET input, inverted) + 17F0 (8): Drive select drive 0 (DSK1) + 17F2 (9): Drive select drive 1 (DSK2) + 17F4 (10): Drive select drive 2 (DSK3) + 17F6 (11): Drive select drive 3 (DSK4) + 17F8 (12): Separate Motor line for internal drive (not used) + 17FA (13): Not connected; turned on before sector I/O, format track, reset drives; turned off once when reporting status + 17FC (14): Arm READY circuit + 17FE (15): Not connected; possibly in test mode only Michael Zapf - June 2017 + March 2018 *****************************************************************************/ #include "emu.h" #include "hx5102.h" +#include "formats/ti99_dsk.h" + +#define LOG_HEXBUS (1U<<1) // Hexbus operation +#define LOG_RESET (1U<<2) // Reset +#define LOG_WARN (1U<<3) // Warnings +#define LOG_READY (1U<<4) // READY +#define LOG_SIGNALS (1U<<5) // IRQ/DRQ +#define LOG_CRU (1U<<6) // CRU +#define LOG_RAM (1U<<7) // RAM +#define LOG_DMA (1U<<8) // DMA +#define LOG_MOTOR (1U<<9) // Motor activity +#define LOG_STATUS (1U<<10) // Main status register +#define LOG_FIFO (1U<<11) // Data register + +// Minimum log should be config and warnings +#define VERBOSE ( LOG_GENERAL | LOG_WARN ) + +#include "logmacro.h" -#define TRACE_HEXBUS 0 +#define TMS9995_TAG "drivecpu" +#define DSR_TAG "dsr" +#define FDC_TAG "i8272a" +#define IBC_TAG "ibc_1052911" +#define MTRD_TAG "u24_motor_mf" +#define MTSPD_TAG "u24_motor_speed_mf" +#define READYFF_TAG "u21_ready_ff" +#define RAM1_TAG "u12_ram" +#define RAM2_TAG "u19_ram" +#define ROM1_TAG "u25_rom" +#define ROM2_TAG "u29_rom" -DEFINE_DEVICE_TYPE_NS(HX5102, bus::hexbus, hx5102_device, "hx5102", "TI Hexbus Floppy") +#define MOTOR_TIMER 1 + +DEFINE_DEVICE_TYPE_NS(HX5102, bus::hexbus, hx5102_device, "ti_hx5102", "TI Hexbus Floppy Drive") namespace bus { namespace hexbus { +ADDRESS_MAP_START(hx5102_device::memmap) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(read, write) +ADDRESS_MAP_END + +/* + CRU access to CRU addresses 1700 - 17FE) +*/ +ADDRESS_MAP_START(hx5102_device::crumap) + AM_RANGE(0x17e0>>4,0x17fe>>4) AM_READ(cruread) + AM_RANGE(0x17e0>>1,0x17fe>>1) AM_WRITE(cruwrite) +ADDRESS_MAP_END + hx5102_device::hx5102_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock): - hexbus_chained_device(mconfig, HX5102, tag, owner, clock) + hexbus_chained_device(mconfig, HX5102, tag, owner, clock), + m_flopcpu(*this, TMS9995_TAG), + m_ready_old(CLEAR_LINE), + m_motor_on(false), + m_mspeed_on(false), + m_pending_int(false), + m_dcs(false), + m_dack(false), + m_dacken(false), + m_wait(false), + m_hexbus_ctrl(*this, IBC_TAG), + m_floppy_ctrl(*this, FDC_TAG), + m_motormf(*this, MTRD_TAG), + m_speedmf(*this, MTSPD_TAG), + m_readyff(*this, READYFF_TAG), + m_ram1(*this, RAM1_TAG), + m_ram2(*this, RAM2_TAG) +{ +} + +WRITE8_MEMBER( hx5102_device::external_operation ) +{ + static const char* extop[8] = { "inv1", "inv2", "IDLE", "RSET", "inv3", "CKON", "CKOF", "LREX" }; + if (offset != IDLE_OP) LOGMASKED(LOG_WARN, "External operation %s not implemented on HX5102 board\n", extop[offset]); +} + + +/* + Read operation. We cannot use the convenient address maps because the + READY circuit requires a flag created from the address lines (m_dcs) which + must be reset on accesses outside of the i8272a memory mapping area. + + V1 = A0 & A1 (A0=MSB) 11.. .... .... .... + V2 = A4* & A5 & A6 & A7 & A8 & A9 & A10 .... 0111 111. .... + + PAL equations + ROM1 = MEM & V1* & A2* & WE* = 0000..1FFF, 4000..5FFF, 8000..9FFF + ROM2 = MEM & V1* & A2 & WE* = 2000..3FFF, 6000..7FFF, A000..BFFF + RAM = MEM & V1 & A2 & A3* = E000..EFFF + DCS = MEM & V1 & A2 & A3 & A15* & V2 & A11* & A14* = F7E0,F7E4,F7E8,F7EC + HCS = MEM & V1 & A2 & A3 & A15* & V2 & A11 & A13* = F7F0,F7F2,F7F8,F7FA + DACK = MEM & V1 & A2 & A3 & A15* & V2 & A11* & A13* & A14 = F7E2,F7EA + AZ = MEM & V1 & A2 & A3 & A15* & V2 & A11* & A12* & A13* & A14* = F7E0 + CRU = MEM* & V1* & A2* & A3 & V2 = 17E0..17FE + RD = MEM & V1 & A2 & A3 & A15* & V2 & A12* & DBIN = F7E0,F7E2,F7E4,F7E6,F7F0,F7F2,F7F4,F7F6 + | MEM & V1 & A2 & A3* & DBIN = E000-EFFF + WR = MEM & V1 & A2 & A3 & A15* & V2 & A12 & A13* & WE = F7E8,F7EA,F7F8,F7FA + | MEM & V1 & A2 & A3* & WE = E000-EFFF + +*/ + +/* + Reading from the address space of the drive. +*/ +READ8_MEMBER( hx5102_device::read ) +{ + bool ramen1 = ((offset & 0xf800)==0xe000); + bool ramen2 = ((offset & 0xf800)==0xe800); + bool romen1 = ((offset & 0xc000)!=0xc000) && ((offset & 0x2000)==0); + bool romen2 = ((offset & 0xc000)!=0xc000) && ((offset & 0x2000)!=0); + bool hcs = ((offset & 0xfff5)==0xf7f0); + + m_dcs = ((offset & 0xfff3)==0xf7e0); + m_dack = ((offset & 0xfff7)==0xf7e2); + + // RAM 1 + uint8_t val; + if (ramen1) + { + val = m_ram1->pointer()[offset & 0x07ff]; + LOGMASKED(LOG_RAM, "RAM %04x -> %02x\n", (offset & 0x07ff)|0xe000, val); + return val; + } + + // RAM 2 + if (ramen2) + { + val = m_ram2->pointer()[offset & 0x07ff]; + LOGMASKED(LOG_RAM, "RAM %04x -> %02x\n", (offset & 0x07ff)|0xe800, val); + return val; + } + + // ROM 1 + if (romen1) + return m_rom1[offset & 0x1fff]; + + // ROM 2 + if (romen2) + return m_rom2[offset & 0x1fff]; + + // Floppy drive controller + if (m_dcs) + return fdc_read(space, offset&0x000f); + + // Hexbus controller + if (hcs) + return ibc_read(space, offset&0x000f); + + // DMA + if (m_dack) + { + // Pick DMA byte from the controller; this automatically signals DACK* + // Thus the drive CPU is the target for the DMA transfer + uint8_t val = m_floppy_ctrl->dma_r(); + LOGMASKED(LOG_DMA, "i8272a.dma -> %02x '%c'\n", val, (val>33 && val<127)? val : '.'); + return val; + } + + if ((offset & 1)==0) LOGMASKED(LOG_WARN, "Unmapped read access: %04x\n", offset); + return 0; +} + +/* + Writing into the address space of the drive. +*/ +WRITE8_MEMBER( hx5102_device::write ) { + bool ramen1 = ((offset & 0xf800)==0xe000); + bool ramen2 = ((offset & 0xf800)==0xe800); + bool hcs = ((offset & 0xfff5)==0xf7f0); + m_dcs = ((offset & 0xfff3)==0xf7e0); + m_dack = ((offset & 0xfff7)==0xf7e2); + + // RAM 1 + if (ramen1) + { + LOGMASKED(LOG_RAM, "RAM %04x <- %02x\n", (offset & 0x07ff)|0xe000, data); + m_ram1->pointer()[offset & 0x07ff] = data; + return; + } + + // RAM 2 + if (ramen2) + { + LOGMASKED(LOG_RAM, "RAM %04x <- %02x\n", (offset & 0x07ff)|0xe800, data); + m_ram2->pointer()[offset & 0x07ff] = data; + return; + } + + // Floppy drive controller + if (m_dcs) + { + fdc_write(space, offset&0x000f, data); + return; + } + + // Hexbus controller + if (hcs) + { + ibc_write(space, offset&0x000f, data); + return; + } + + // DMA + if (m_dack) + { + m_floppy_ctrl->dma_w(data); + LOGMASKED(LOG_DMA, "i8272a.dma <- %02x '%c'\n", data, (data>33 && data<127)? data : '.'); + return; + } + + if ((offset & 1)==0) LOGMASKED(LOG_WARN, "Unmapped write access: %04x\n", offset); } + +/* + Clock line from the CPU. Used to control wait state generation. +*/ +WRITE_LINE_MEMBER( hx5102_device::clock_out ) +{ + m_readyff->clock_w(state); +} + +/* + Input from the Hexbus +*/ void hx5102_device::hexbus_value_changed(uint8_t data) { - if (TRACE_HEXBUS) logerror("Hexbus value changed to %02x\n", data); + m_hexbus_ctrl->from_hexbus(data); +} + +/* + Propagate READY signals to the CPU. This is used to hold the CPU + during DMA accesses. +*/ +WRITE_LINE_MEMBER( hx5102_device::board_ready ) +{ + if (m_ready_old != state) + { + LOGMASKED(LOG_READY, "READY = %d\n", state); + } + + m_ready_old = (line_state)state; + m_flopcpu->ready_line(state); +} + +/* + Trigger RESET. +*/ +WRITE_LINE_MEMBER( hx5102_device::board_reset ) +{ + LOGMASKED(LOG_RESET, "Incoming RESET line = %d\n", state); + + if (machine().phase() != machine_phase::INIT) + { + // Setting ready to true so that automatic wait states are disabled + m_flopcpu->ready_line(ASSERT_LINE); + m_flopcpu->reset_line(ASSERT_LINE); + } +} + +/* + Effect from the motor monoflop. +*/ +WRITE_LINE_MEMBER( hx5102_device::motor_w ) +{ + m_motor_on = (state==ASSERT_LINE); + LOGMASKED(LOG_MOTOR, "Motor %s\n", m_motor_on? "start" : "stop"); + m_floppy->mon_w(m_motor_on? 0 : 1); + update_readyff_input(); +} + +/* + Effect from the speed monoflop. This is essentially a watchdog to + check whether the lock on the CPU must be released due to an error. +*/ +WRITE_LINE_MEMBER( hx5102_device::mspeed_w ) +{ + m_mspeed_on = (state==ASSERT_LINE); + LOGMASKED(LOG_READY, "Speedcheck %s\n", m_mspeed_on? "on" : "off"); + update_readyff_input(); +} + +/* + Read access to the floppy controller +*/ +READ8_MEMBER(hx5102_device::fdc_read) +{ + uint8_t val = 0; + switch (offset) + { + case 0: + // Main status register + val = m_floppy_ctrl->msr_r(); + LOGMASKED(LOG_STATUS, "i8272A.msr -> %02x\n", val); + break; + case 4: + // FIFO read + val = m_floppy_ctrl->fifo_r(); + LOGMASKED(LOG_FIFO, "i8272A.fifo -> %02x\n", val); + break; + } + return val; +} + +/* + Write access to the floppy controller +*/ +WRITE8_MEMBER(hx5102_device::fdc_write) +{ + m_dcs = ((offset & 0x0003)==0); + + switch (offset) + { + case 0x08: + // Command register (FIFO write) + LOGMASKED(LOG_STATUS, "i8272A.fifo <- %02x\n", data); + m_floppy_ctrl->fifo_w(data); + break; + case 0x0c: + // DMA lock + LOGMASKED(LOG_READY, "Lock READY\n", data); + update_readyff_input(); + break; + } +} + +void hx5102_device::update_readyff_input() +{ + LOGMASKED(LOG_READY, "MON=%d, MSP=%d, WAIT=%d, INT*=%d, DRQ*=%d, DCS=%d\n", m_motor_on, m_mspeed_on, m_wait, !m_pending_int, !m_pending_drq, m_dcs); + m_readyff->d_w(m_motor_on && m_mspeed_on && m_wait && !m_pending_int && !m_pending_drq && m_dcs); +} + +/* + Access to the Hexbus controller +*/ +READ8_MEMBER(hx5102_device::ibc_read) +{ + if ((offset & 1)==0) + return m_hexbus_ctrl->read(space, (offset>>1)&1); + else + return 0; +} + +WRITE8_MEMBER(hx5102_device::ibc_write) +{ + if ((offset & 1)==0) + m_hexbus_ctrl->write(space, (offset>>1)&1, data); +} + +WRITE8_MEMBER(hx5102_device::hexbus_out) +{ + LOGMASKED(LOG_HEXBUS, "hexbus out: %02x\n", data); + + // Get the other levels and set our own states + uint8_t newlevel = hexbus_get_levels() & data; + m_hexbus_ctrl->update_lines((newlevel & 0x04)==0, (newlevel & 0x10)==0); + + // Now set the bus. This may entail further changes, incoming via hexbus_value_changed. + hexbus_write(data); +} + +/* + Latch the HSK* to low. +*/ +WRITE_LINE_MEMBER(hx5102_device::hsklatch_out) +{ + LOGMASKED(LOG_HEXBUS, "Latching HSK*\n"); + m_myvalue &= ~HEXBUS_LINE_HSK; +} + +/* + CRU read access. + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | TD3 | TD2 | TD1 | TD0 | 0 | TIM | MON | INT | + +-----+-----+-----+-----+-----+-----+-----+-----+ + + TDx = Tracks for drive x; 0 = 40, 1 = 77 + TIM = Timeout + MON = Motor on + INT = Interrupt from i8272A +*/ +READ8_MEMBER(hx5102_device::cruread) +{ + uint8_t crubits = 0; + // LOGMASKED(LOG_CRU, "Reading CRU addresses %04x-%04x\n", 0x17e0 + (offset<<4), 0x17ee + (offset<<4)); + if (m_pending_int) crubits |= 0x01; + if (m_motor_on) crubits |= 0x02; + if (m_mspeed_on) crubits |= 0x04; + return crubits; +} + +/* + CRU write access. +*/ +WRITE8_MEMBER(hx5102_device::cruwrite) +{ + // LOG("Writing CRU address %04x: %x\n", 0x17e0 + (offset<<1), data); + switch (offset) + { + case 0: + LOGMASKED(LOG_CRU, "Set precompensation = %d\n", data); + break; + case 1: + if (data==1) + { + LOGMASKED(LOG_CRU, "Trigger motor monoflop\n"); + } + m_motormf->b_w(data); + break; + case 2: + LOGMASKED(LOG_CRU, "Set undefined CRU bit 2 to %d\n", data); + break; + case 3: + LOGMASKED(LOG_CRU, "Set step direction = %d\n", data); + m_floppy->dir_w((data==0)? 1 : 0); + break; + case 4: + if (data==1) + { + LOGMASKED(LOG_CRU, "Assert DACK*\n"); + m_dacken = (data != 0); + } + break; + case 5: + if (data==1) + { + LOGMASKED(LOG_CRU, "Step pulse\n"); + } + m_floppy->stp_w((data==0)? 1 : 0); + break; + case 6: + if (data==1) + { + LOGMASKED(LOG_CRU, "Start watchdog\n"); + } + m_speedmf->b_w(data); + break; + case 7: + if (data==0) + { + LOGMASKED(LOG_CRU, "Reset i8272A controller\n"); + m_floppy_ctrl->soft_reset(); + } + break; + case 8: + LOGMASKED(LOG_CRU, "Set drive select 0 to %d\n", data); + break; + case 9: + LOGMASKED(LOG_CRU, "Set drive select 1 to %d\n", data); + break; + case 10: + LOGMASKED(LOG_CRU, "Set drive select 2 to %d\n", data); + break; + case 11: + LOGMASKED(LOG_CRU, "Set drive select 3 to %d\n", data); + break; + case 12: + LOGMASKED(LOG_CRU, "Set auxiliary motor line to %d\n", data); + break; + case 13: + LOGMASKED(LOG_CRU, "Set CRU bit 13 to %d (unused)\n", data); + break; + case 14: + m_wait = (data!=0); + LOGMASKED(LOG_CRU, "READY circuit %s\n", m_wait? "active" : "inactive" ); + update_readyff_input(); + break; + case 15: + LOGMASKED(LOG_CRU, "Set CRU bit 15 to %d (unused)\n", data); + break; + } +} + +/* + Device lifecycle. +*/ +void hx5102_device::device_start() +{ + m_floppy = static_cast<floppy_image_device*>(subdevice("d0")->subdevices().first()); + + m_rom1 = (uint8_t*)memregion(DSR_TAG)->base(); + m_rom2 = (uint8_t*)memregion(DSR_TAG)->base() + 0x2000; +} + +/* + Device lifecycle. +*/ +void hx5102_device::device_reset() +{ + board_reset(ASSERT_LINE); + board_ready(ASSERT_LINE); + // set_floppy must be here, because upd765_family_device::device_start + // resets the device links to null + m_floppy_ctrl->set_floppy(m_floppy); +} + +/* + Callbacks from the i8272A chip + Interrupt +*/ +WRITE_LINE_MEMBER( hx5102_device::fdc_irq_w ) +{ + line_state irq = state? ASSERT_LINE : CLEAR_LINE; + LOGMASKED(LOG_SIGNALS, "INTRQ callback = %d\n", irq); + m_pending_int = state; + update_readyff_input(); +} + +/* + Callbacks from the i8272A chip + DMA request +*/ +WRITE_LINE_MEMBER( hx5102_device::fdc_drq_w ) +{ + line_state drq = state? ASSERT_LINE : CLEAR_LINE; + LOGMASKED(LOG_SIGNALS, "DRQ callback = %d\n", drq); + m_pending_drq = state; + update_readyff_input(); +} + +/* + Define the floppy formats. +*/ +FLOPPY_FORMATS_MEMBER(hx5102_device::floppy_formats) + FLOPPY_TI99_SDF_FORMAT, + FLOPPY_TI99_TDF_FORMAT +FLOPPY_FORMATS_END + +/* + Only one fixed floppy drive in the device. + External connectors are available, though. +*/ +static SLOT_INTERFACE_START( hx5102_drive ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) +SLOT_INTERFACE_END + +/* + HX5102 configuration +*/ +MACHINE_CONFIG_START(hx5102_device::device_add_mconfig) + // Hexbus controller + MCFG_DEVICE_ADD(IBC_TAG, IBC, 0) + MCFG_IBC_HEXBUS_OUT_CALLBACK(WRITE8(hx5102_device, hexbus_out)) + MCFG_IBC_HSKLATCH_CALLBACK(WRITELINE(hx5102_device, hsklatch_out)) + + // Outgoing socket for downstream devices + MCFG_HEXBUS_ADD("hexbus") + + // TMS9995 CPU @ 12.0 MHz + MCFG_TMS99xx_ADD(TMS9995_TAG, TMS9995, XTAL(12'000'000), memmap, crumap) + MCFG_TMS9995_EXTOP_HANDLER( WRITE8(hx5102_device, external_operation) ) + MCFG_TMS9995_CLKOUT_HANDLER( WRITELINE(hx5102_device, clock_out) ) + + // Disk controller i8272A + // Not connected: Select lines (DS0, DS1), Head load (HDL), VCO + // Tied to 1: READY + // Tied to 0: TC + MCFG_I8272A_ADD(FDC_TAG, false) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(hx5102_device, fdc_irq_w)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(hx5102_device, fdc_drq_w)) + MCFG_FLOPPY_DRIVE_ADD("d0", hx5102_drive, "525dd", hx5102_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + + // Monoflops + MCFG_DEVICE_ADD(MTRD_TAG, TTL74123, 0) + MCFG_TTL74123_CONNECTION_TYPE(TTL74123_GROUNDED) + MCFG_TTL74123_RESISTOR_VALUE(RES_K(200)) + MCFG_TTL74123_CAPACITOR_VALUE(CAP_U(47)) + MCFG_TTL74123_A_PIN_VALUE(0) + MCFG_TTL74123_B_PIN_VALUE(1) + MCFG_TTL74123_CLEAR_PIN_VALUE(1) + MCFG_TTL74123_OUTPUT_CHANGED_CB(WRITELINE(hx5102_device, motor_w)) + + MCFG_DEVICE_ADD(MTSPD_TAG, TTL74123, 0) + MCFG_TTL74123_CONNECTION_TYPE(TTL74123_GROUNDED) + MCFG_TTL74123_RESISTOR_VALUE(RES_K(200)) + MCFG_TTL74123_CAPACITOR_VALUE(CAP_U(10)) + MCFG_TTL74123_A_PIN_VALUE(0) + MCFG_TTL74123_B_PIN_VALUE(1) + MCFG_TTL74123_CLEAR_PIN_VALUE(1) + MCFG_TTL74123_OUTPUT_CHANGED_CB(WRITELINE(hx5102_device, mspeed_w)) + + // READY flipflop + MCFG_DEVICE_ADD(READYFF_TAG, TTL7474, 0) + MCFG_7474_COMP_OUTPUT_CB(WRITELINE(hx5102_device, board_ready)) + + // RAM + MCFG_RAM_ADD(RAM1_TAG) + MCFG_RAM_DEFAULT_SIZE("2048") + MCFG_RAM_DEFAULT_VALUE(0) + + MCFG_RAM_ADD(RAM2_TAG) + MCFG_RAM_DEFAULT_SIZE("2048") + MCFG_RAM_DEFAULT_VALUE(0) + +MACHINE_CONFIG_END + +ROM_START( hx5102 ) + ROM_REGION( 0x4000, DSR_TAG, 0 ) + ROM_LOAD( "hx5102_rom1.u25", 0x0000, 0x2000, CRC(40621a77) SHA1(1532f6f23e0104326c21909cb0ec46936242a12a) ) + ROM_LOAD( "hx5102_rom2.u29", 0x2000, 0x2000, CRC(57c2603b) SHA1(2f1d01378943436f0abd5b20710f6c8c175fde13) ) +ROM_END + +const tiny_rom_entry *hx5102_device::device_rom_region() const +{ + return ROM_NAME( hx5102 ); } } } // end namespace bus::hexbus diff --git a/src/devices/bus/hexbus/hx5102.h b/src/devices/bus/hexbus/hx5102.h index fdb0c198f8d..d554497bc65 100644 --- a/src/devices/bus/hexbus/hx5102.h +++ b/src/devices/bus/hexbus/hx5102.h @@ -18,6 +18,14 @@ #pragma once #include "hexbus.h" +#include "cpu/tms9900/tms9995.h" +#include "machine/upd765.h" +#include "machine/7474.h" +#include "machine/74123.h" +#include "machine/rescap.h" +#include "machine/ram.h" +#include "imagedev/floppy.h" +#include "tp0370.h" namespace bus { namespace hexbus { @@ -25,7 +33,76 @@ class hx5102_device : public hexbus_chained_device { public: hx5102_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - void hexbus_value_changed(uint8_t data) override; + +protected: + virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_add_mconfig(machine_config &config) override; + void crumap(address_map &map); + void memmap(address_map &map); + DECLARE_WRITE8_MEMBER(external_operation); + DECLARE_WRITE_LINE_MEMBER( clock_out ); + DECLARE_WRITE_LINE_MEMBER( board_ready ); + DECLARE_WRITE_LINE_MEMBER( board_reset ); + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + void device_start() override; + void device_reset() override; + virtual void hexbus_value_changed(uint8_t data) override; + +private: + required_device<tms9995_device> m_flopcpu; + line_state m_ready_old; + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_WRITE_LINE_MEMBER(fdc_irq_w); + DECLARE_WRITE_LINE_MEMBER(fdc_drq_w); + DECLARE_WRITE_LINE_MEMBER(motor_w); + DECLARE_WRITE_LINE_MEMBER(mspeed_w); + + DECLARE_READ8_MEMBER(fdc_read); + DECLARE_WRITE8_MEMBER(fdc_write); + DECLARE_READ8_MEMBER(ibc_read); + DECLARE_WRITE8_MEMBER(ibc_write); + DECLARE_WRITE8_MEMBER(hexbus_out); + DECLARE_WRITE_LINE_MEMBER(hsklatch_out); + + DECLARE_READ8_MEMBER(cruread); + DECLARE_WRITE8_MEMBER(cruwrite); + + // Operate the floppy motors + bool m_motor_on; + bool m_mspeed_on; + + bool m_pending_int; + bool m_pending_drq; + + bool m_dcs; + + bool m_dack; + bool m_dacken; + + bool m_wait; + + void update_readyff_input(); + + // Link to the attached floppy drive + floppy_image_device* m_floppy; + + required_device<ibc_device> m_hexbus_ctrl; + required_device<i8272a_device> m_floppy_ctrl; + required_device<ttl74123_device> m_motormf; + required_device<ttl74123_device> m_speedmf; + required_device<ttl7474_device> m_readyff; + + // RAM + required_device<ram_device> m_ram1; + required_device<ram_device> m_ram2; + + // System ROM + uint8_t* m_rom1; + uint8_t* m_rom2; }; } } // end namespace bus::hexbus diff --git a/src/devices/bus/hexbus/tp0370.cpp b/src/devices/bus/hexbus/tp0370.cpp new file mode 100644 index 00000000000..6753f387015 --- /dev/null +++ b/src/devices/bus/hexbus/tp0370.cpp @@ -0,0 +1,340 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + + Intelligent peripheral bus controller (IBC) + + This is a simple circuit used to connect to the Hexbus infrastructure. + + Two variants are known, with the only difference being the voltage pins + and a split of incoming/outgoing lines from/to the Hexbus. + + The 22-pin version is the earlier one, but it is used in the HX5102 + floppy drive. + + 22-pin 28-pin + +-----------+ +-----------+ + I/O-0 | 1 \/ 22| O-2 I/O-0 | 1 \/ 28| Vcc + I/O-1 | 2 21| O-1 I/O-1 | 2 27| O-0 + I/O-2 | 3 20| O-0 I/O-2 | 3 26| O-1 + I/O-3 | 4 19| Vdd I/O-3 | 4 25| O-2 + BAV | 5 18| MS BAVI | 5 24| O-3,R/W + HSK | 6 17| D-3 BAV | 6 23| D-3I + IRQ | 7 16| D-2 HSKI | 7 22| D-3 + E | 8 15| D-1 HSK | 8 21| D-2I + Vss | 9 14| D-0 IRQ | 9 20| D-2 + RES |10 13| RS E |10 19| D-1I + R/W,O-3 |11 12| CS CS |11 18| D-1 + +-----------+ RES |12 17| D-0I + 1052911 MS |13 16| D-0 + GND |14 15| RS + +-----------+ + TP0370 + + Pins Dir Meaning (MS=0) Dir Meaning (MS=1) + ------------------------------------------------------------------- + I/O-0 i/o Data lines (Host) in Data lines (Host) + I/O-1 i/o Data lines (Host) in Data lines (Host) + I/O-2 i/o Data lines (Host) in Data lines (Host) + I/O-3 i/o Data lines (Host) in Data lines (Host) + BAV i/o Bus available (Hexbus) i/o Bus available (Hexbus) + HSK i/o Handshake line (Hexbus) i/o Handshake line (Hexbus) + IRQ out Interrupt out Interrupt + E in See below in Write strobe + MS in Mode select=0 in Mode select=1 + RS in Register select in Register select + CS in Chip select in Chip select + RES in Reset in Reset + O-0 in Option select out Data output (Host) + O-1 in Option select out Data output (Host) + O-2 in Option select out Data output (Host) + R/W in Read/write select out Data output (Host, O-3) + D-0 i/o Data lines (Hexbus) i/o Data lines (Hexbus) + D-1 i/o Data lines (Hexbus) i/o Data lines (Hexbus) + D-2 i/o Data lines (Hexbus) i/o Data lines (Hexbus) + D-3 i/o Data lines (Hexbus) i/o Data lines (Hexbus) + Vss + Vdd + Vcc +5V + GND 0V + + Options for MS=0 + O-2 O-1 O-0 + ----------- + 0 0 0 TMS7000 mode (E active low) + 0 0 1 6500 mode (E active high, using R/W) + 0 1 0 8048/8085 mode (WR*->R/W, RD*->E) + 1 * * Multiplexed A/D Buses (ALATCH/ALE->RS) + + MS=1 is used for 4-bit MPUs which do not have a bidirectional bus + (e.g. TMS1000). + + + All registers are 4-bit wide + + RS Dir Access + --------------------------------- + 0 Read Receive data register + 0 Write Transmit data register + 1 Read Status register + 1 Write Control register + + Control register + MSB 3 DISABLE: 1->Disable clearing of Inhibit by new BAV + 2 INHIBIT: 1->Inhibit latching of HSK and IRQ until new BAV + 1 BAV: 1-> Assert BAV* line; 0->Release BAV* when HSK* low + LSB 0 HSK: 1-> Assert HSK* line, clear IRQ; 0->Release HSK* + + Special: 1100 -> Hardware reset + + + Status register + MSB 3 \_ 00 = Enable state; 01 = Inhibit/disable state; + 2 / 10 = Active IRQ; 11 = Start of message + 1 BAV* asserted (1=low) + LSB 0 HSK* asserted (1=low) + + Special: 01** after hardware reset + + [1] Texas Instruments Consumer Products Group: Hexbus(TM) specifications, + Sep 1983 +*/ + +#include "emu.h" +#include "hexbus.h" + +// Devices +#include "tp0370.h" + +#define LOG_DATA (1U<<1) // Data transfer +#define LOG_DETAIL (1U<<2) +#define LOG_WRITE (1U<<3) +#define LOG_LINES (1U<<4) +#define LOG_STATUS (1U<<5) +#define LOG_MODE (1U<<6) + +// Minimum log should be config and warnings +#define VERBOSE ( LOG_GENERAL ) + +enum +{ + CTRL_DISABLE=0x80, + CTRL_INHIBIT=0x40, + CTRL_BAV=0x20, + CTRL_HSK=0x10 +}; + + +#include "logmacro.h" + +// Hexbus instance +DEFINE_DEVICE_TYPE_NS(IBC, bus::hexbus, ibc_device, "ibc", "Intelligent Peripheral Bus Controller") + +namespace bus { namespace hexbus { + +ibc_device::ibc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, IBC, tag, owner, clock), + m_int(*this), + m_hexout(*this), + m_latch(*this), + m_inhibit(false), + m_disable(true), + m_bavold(true), + m_hskold(true), + m_int_pending(false), + m_incoming_message(false), + m_message_started(false), + m_data(0), + m_transmit(0xff) +{ +} + +/* + Reading from host +*/ +READ8_MEMBER( ibc_device::read ) +{ + uint8_t status = 0; + switch (offset) + { + case 0: + LOGMASKED(LOG_DATA, "Data reg -> %01x\n", m_data&0x0f); + return (m_data<<4)&0xf0; // returned in the first 4 bits + case 1: + if (m_message_started) + status |= 0xc0; + else + { + if (m_int_pending) + status |= 0x80; + else + { + if (m_disable || m_inhibit) + status |= 0x40; + } + } + if (m_bav) status |= 0x20; + if (m_hsk) status |= 0x10; + + LOGMASKED(LOG_STATUS, "Status -> %02x\n", status); + + // Reset flag + m_message_started = false; + return status; + + default: + LOG("Unknown read address: %02x\n", offset); + break; + } + return 0; +} + +/* + Writing from host +*/ +WRITE8_MEMBER( ibc_device::write ) +{ + switch (offset) + { + case 0: + LOGMASKED(LOG_WRITE, "Writing transmit data %02x\n", data); + m_transmit = data; + break; + case 1: + set_disable_inhibit((data & CTRL_DISABLE)!=0, (data & CTRL_INHIBIT)!=0); + if ((data & CTRL_HSK)!=0 && m_int_pending) + { + // Reset INT + LOGMASKED(LOG_DETAIL, "Reset Interrupt\n"); + m_int_pending = false; + m_int(CLEAR_LINE); + } + else + { + set_lines((data & CTRL_BAV)!=0, (data & CTRL_HSK)!=0); + } + + break; + default: + LOG("Unknown write address: %02x\n", offset); + break; + } +} + +void ibc_device::set_disable_inhibit(bool dis, bool inh) +{ + LOGMASKED(LOG_MODE, "Setting disable=%s, inhibit=%s\n", dis? "on" : "off", inh? "on" : "off"); + m_disable = dis; + m_inhibit = inh; +} + +/* + Called from the HSK latch or by command. +*/ +void ibc_device::set_lines(bool bav, bool hsk) +{ + LOGMASKED(LOG_LINES, "%s BAV*, %s HSK*\n", bav? "Pull down" : "Release", hsk? "Pull down" : "Release"); + + // Assert HSK* (110 0 0111) + // Release HSK* (110 1 0111) + // Assert BAV* (11010 0 11) + // Release BAv* (11010 1 11) + uint8_t val = (m_transmit & 0xc0)|((m_transmit & 0x30)>>4); + if (!bav) val |= 0x04; + if (!hsk) val |= 0x10; + if (m_transmit != 0xff) LOGMASKED(LOG_LINES, "Data = %01x\n", m_transmit>>4); + + m_hexout(val); + m_transmit=0xff; // TODO: Check this +} + +/* + Line state received via the Hexbus + +------+------+------+------+------+------+------+------+ + | ADB3 | ADB2 | - | HSK* | 0 | BAV* | ADB1 | ADB0 | + +------+------+------+------+------+------+------+------+ +*/ +void ibc_device::from_hexbus(uint8_t val) +{ + uint8_t data = ((val >> 4)&0x0c) | (val & 0x03); + + m_bavold = m_bav; + m_hskold = m_hsk; + + m_hsk = ((val & 0x10)==0); + m_bav = ((val & 0x04)==0); + LOGMASKED(LOG_LINES, "Hexbus -> BAV*=%x, HSK*=%x, HSKold*=%x, DATA=%1x\n", m_bav? 0:1, m_hsk? 0:1, m_hskold? 0:1, data); + + if (m_disable) + { + // When disabled, do not latch HSK + LOGMASKED(LOG_MODE, "Disabled, not latching HSK*\n"); + } + else + { + // Falling edge of BAV* + // Reset inhibit flag + if (m_bav && !m_bavold) + { + LOGMASKED(LOG_LINES, "Bus acquired\n"); + m_inhibit = false; + m_incoming_message = true; + } + + // The message may combine a change of BAV* and of HSK*. + if (!m_inhibit) + { + // Falling edge of HSK* + if (m_hsk && !m_hskold) + { + // On this falling edge, the nibble is supposed to be stable, + // so keep it + m_data = data; + if (m_incoming_message && !m_message_started) + { + // Set flag for new message + m_incoming_message = false; + m_message_started = true; + LOGMASKED(LOG_DETAIL, "New message started\n", data); + } + else + m_message_started = false; + + LOGMASKED(LOG_DETAIL, "Data reg <- %1x\n", data); + + // set the latch + m_latch(ASSERT_LINE); + + // and set interrupt + m_int_pending = true; + m_int(ASSERT_LINE); + } + } + } +} + +/* + Called from the hexbus_chained_device. +*/ +void ibc_device::update_lines(bool bav, bool hsk) +{ + LOGMASKED(LOG_LINES, "Actual Hexbus line states: BAV*=%d, HSK*=%d\n", bav? 0:1, hsk? 0:1); + m_bav = bav; + m_hsk = hsk; +} + +void ibc_device::device_start() +{ + m_int.resolve_safe(); + m_hexout.resolve_safe(); + m_latch.resolve_safe(); +} + +void ibc_device::device_reset() +{ + m_inhibit = true; + m_disable = true; +} + +} } + diff --git a/src/devices/bus/hexbus/tp0370.h b/src/devices/bus/hexbus/tp0370.h new file mode 100644 index 00000000000..94d32a5b87c --- /dev/null +++ b/src/devices/bus/hexbus/tp0370.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/**************************************************************************** + + Intelligent peripheral bus controller (IBC) + + This is a simple circuit used to connect to the Hexbus infrastructure. + + See tp0370.cpp for documentation + + Michael Zapf + +*****************************************************************************/ +#ifndef MAME_BUS_HEXBUS_TP0370_H +#define MAME_BUS_HEXBUS_TP0370_H + +#pragma once + +namespace bus { namespace hexbus { + +class ibc_device : public device_t +{ +public: + ibc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + void device_start() override; + void device_reset() override; + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + template <class Object> static devcb_base &set_ibc_int_callback(device_t &device, Object &&cb) { return downcast<ibc_device &>(device).m_int.set_callback(std::forward<Object>(cb)); } + template <class Object> static devcb_base &set_hexbus_wr_callback(device_t &device, Object &&cb) { return downcast<ibc_device &>(device).m_hexout.set_callback(std::forward<Object>(cb)); } + template <class Object> static devcb_base &set_hsklatch_wr_callback(device_t &device, Object &&cb) { return downcast<ibc_device &>(device).m_latch.set_callback(std::forward<Object>(cb)); } + + // INT line + devcb_write_line m_int; + + // Outgoing connection to Hexbus + devcb_write8 m_hexout; + + // Callback to set the HSK latch + devcb_write_line m_latch; + + // Incoming connection + void from_hexbus(uint8_t val); + + // Update the lines from the Hexbus + void update_lines(bool bav, bool hsk); + +private: + bool m_inhibit; + bool m_disable; + bool m_bav; + bool m_hsk; + bool m_bavold; + bool m_hskold; + bool m_int_pending; + bool m_incoming_message; + bool m_message_started; + + uint8_t m_data; + uint8_t m_transmit; + + void set_disable_inhibit(bool dis, bool inh); + void set_lines(bool bav, bool hsk); +}; + +} } + + +/* + Links to outside +*/ + +#define MCFG_IBC_HEXBUS_OUT_CALLBACK(_write) \ + devcb = &ibc_device::set_hexbus_wr_callback(*device, DEVCB_##_write); + +#define MCFG_IBC_HSKLATCH_CALLBACK(_write) \ + devcb = &ibc_device::set_hsklatch_wr_callback(*device, DEVCB_##_write); + +#define MCFG_IBC_INT_CALLBACK(_write) \ + devcb = &ibc_device::set_ibc_int_callback(*device, DEVCB_##_write); + +DECLARE_DEVICE_TYPE_NS(IBC, bus::hexbus, ibc_device) +#endif diff --git a/src/devices/bus/ti99/internal/998board.cpp b/src/devices/bus/ti99/internal/998board.cpp index 486130d5ac9..9a4fc5cca8e 100644 --- a/src/devices/bus/ti99/internal/998board.cpp +++ b/src/devices/bus/ti99/internal/998board.cpp @@ -106,6 +106,26 @@ #include "emu.h" #include "998board.h" +#define LOG_DETAIL (1U<<1) // More detail +#define LOG_CRU (1U<<2) // CRU logging +#define LOG_ADDRESS (1U<<3) // Address bus +#define LOG_MEM (1U<<4) // Memory access +#define LOG_MAP (1U<<5) // Mapper +#define LOG_READY (1U<<6) // READY line +#define LOG_CLOCK (1U<<7) // CLKOUT +#define LOG_MOFETTA (1U<<8) // Mofetta operation +#define LOG_AMIGO (1U<<9) // Amigo operation +#define LOG_OSO (1U<<10) // Oso operation +#define LOG_HEXBUS (1U<<11) // Hexbus operation +#define LOG_WS (1U<<12) // Wait states +#define LOG_CPURY (1U<<13) // Combined ready line +#define LOG_GROM (1U<<14) // GROM operation +#define LOG_PUNMAP (1U<<15) // Unmapped physical addresss + +#define VERBOSE ( LOG_GENERAL ) + +#include "logmacro.h" + DEFINE_DEVICE_TYPE_NS(TI99_MAINBOARD8, bus::ti99::internal, mainboard8_device, "ti998_mainboard", "TI-99/8 Mainboard") DEFINE_DEVICE_TYPE_NS(TI99_VAQUERRO, bus::ti99::internal, vaquerro_device, "ti998_vaquerro", "TI-99/8 Logical Address Space Decoder") DEFINE_DEVICE_TYPE_NS(TI99_MOFETTA, bus::ti99::internal, mofetta_device, "ti998_mofetta", "TI-99/8 Physical Address Space Decoder") @@ -114,22 +134,6 @@ DEFINE_DEVICE_TYPE_NS(TI99_AMIGO, bus::ti99::internal, amigo_device, "ti998_amig namespace bus { namespace ti99 { namespace internal { -#define TRACE_CRU 0 -#define TRACE_ADDRESS 0 -#define TRACE_MAP 0 -#define TRACE_OSO 0 -#define TRACE_DECODE 0 -#define TRACE_READY 0 -#define TRACE_MEM 0 -#define TRACE_CLOCK 0 -#define TRACE_DETAIL 0 -#define TRACE_MOFETTA 0 -#define TRACE_AMIGO 0 -#define TRACE_WS 0 -#define TRACE_CPURY 0 -#define TRACE_GROM 0 -#define TRACE_PUNMAP 0 - enum { SGMSEL = 1, @@ -345,7 +349,7 @@ WRITE_LINE_MEMBER( mainboard8_device::dbin_in ) SETOFFSET_MEMBER( mainboard8_device::setoffset ) { - if (TRACE_ADDRESS) logerror("set %s %04x\n", (m_dbin_level==ASSERT_LINE)? "R" : "W", offset); + LOGMASKED(LOG_ADDRESS, "set %s %04x\n", (m_dbin_level==ASSERT_LINE)? "R" : "W", offset); // No data is waiting on the data bus m_pending_write = false; @@ -407,7 +411,7 @@ WRITE_LINE_MEMBER( mainboard8_device::holda_line ) */ WRITE_LINE_MEMBER( mainboard8_device::clock_in ) { - if (TRACE_CLOCK) logerror("CLKOUT = %d\n", state); + LOGMASKED(LOG_CLOCK, "CLKOUT = %d\n", state); // Propagate to Vaquerro; may change GGRDY (trailing edge) and the GROM select lines m_vaquerro->clock_in((line_state)state); @@ -469,7 +473,7 @@ WRITE_LINE_MEMBER( mainboard8_device::clock_in ) if (m_A14_set) m_video->register_write(*m_space, 0, m_latched_data); else m_video->vram_write(*m_space, 0, m_latched_data); m_pending_write = false; - if (TRACE_MEM) logerror("Write %04x (video) <- %02x\n", m_logical_address, m_latched_data); + LOGMASKED(LOG_MEM, "Write %04x (video) <- %02x\n", m_logical_address, m_latched_data); cycle_end(); return; } @@ -486,14 +490,14 @@ WRITE_LINE_MEMBER( mainboard8_device::clock_in ) { m_dram->pointer()[m_physical_address & 0xffff] = m_latched_data; m_pending_write = false; - if (TRACE_MEM) logerror("Write %04x (phys %06x, DRAM) <- %02x\n", m_logical_address, m_physical_address, m_latched_data); + LOGMASKED(LOG_MEM, "Write %04x (phys %06x, DRAM) <- %02x\n", m_logical_address, m_physical_address, m_latched_data); } if (m_mofetta->alccs_out()==ASSERT_LINE) { m_oso->write(*m_space, m_physical_address>>1, m_latched_data); m_pending_write = false; - if (TRACE_MEM) logerror("Write %04x (phys %06x, OSO) <- %02x\n", m_logical_address, m_physical_address, m_latched_data); + LOGMASKED(LOG_MEM, "Write %04x (phys %06x, OSO) <- %02x\n", m_logical_address, m_physical_address, m_latched_data); } if (m_mofetta->cmas_out()==ASSERT_LINE) @@ -501,7 +505,7 @@ WRITE_LINE_MEMBER( mainboard8_device::clock_in ) m_gromport->romgq_line(ASSERT_LINE); m_gromport->write(*m_space, m_physical_address & 0x3fff, m_latched_data); m_pending_write = false; - if (TRACE_MEM) logerror("Write %04x (phys %06x, cartridge) <- %02x\n", m_logical_address, m_physical_address, m_latched_data); + LOGMASKED(LOG_MEM, "Write %04x (phys %06x, cartridge) <- %02x\n", m_logical_address, m_physical_address, m_latched_data); } else { @@ -512,7 +516,7 @@ WRITE_LINE_MEMBER( mainboard8_device::clock_in ) { m_ioport->write(*m_space, m_physical_address, m_latched_data); m_pending_write = false; - if (TRACE_MEM) logerror("Write %04x (phys %06x, PEB) <- %02x\n", m_logical_address, m_physical_address, m_latched_data); + LOGMASKED(LOG_MEM, "Write %04x (phys %06x, PEB) <- %02x\n", m_logical_address, m_physical_address, m_latched_data); } } @@ -553,7 +557,7 @@ void mainboard8_device::select_groms() for (int i=0; i < 3; i++) m_p3grom[i]->set_lines(*m_space, lines, select & P3GSEL); - // Write to the cartridge port. The GROMs on cartridges are accesses as system GROMs + // Write to the cartridge port. The GROMs on cartridges are accessed as system GROMs if (select & SGMSEL) m_gromport->romgq_line(CLEAR_LINE); m_gromport->set_gromlines(*m_space, lines, select & SGMSEL); } @@ -569,7 +573,7 @@ void mainboard8_device::select_groms() { m_sgrom[i]->write(*m_space, 0, m_latched_data); } - if (TRACE_MEM) logerror("Write GS <- %02x\n", m_latched_data); + LOGMASKED(LOG_MEM, "Write GS <- %02x\n", m_latched_data); m_gromport->write(*m_space, 0, m_latched_data); break; @@ -578,7 +582,7 @@ void mainboard8_device::select_groms() { m_tsgrom[i]->write(*m_space, 0, m_latched_data); } - if (TRACE_MEM) logerror("Write GT <- %02x\n", m_latched_data); + LOGMASKED(LOG_MEM, "Write GT <- %02x\n", m_latched_data); break; case P8GSEL: @@ -586,7 +590,7 @@ void mainboard8_device::select_groms() { m_p8grom[i]->write(*m_space, 0, m_latched_data); } - if (TRACE_MEM) logerror("Write G8 <- %02x\n", m_latched_data); + LOGMASKED(LOG_MEM, "Write G8 <- %02x\n", m_latched_data); break; case P3GSEL: @@ -594,7 +598,7 @@ void mainboard8_device::select_groms() { m_p3grom[i]->write(*m_space, 0, m_latched_data); } - if (TRACE_MEM) logerror("Write G3 <- %02x\n", m_latched_data); + LOGMASKED(LOG_MEM, "Write G3 <- %02x\n", m_latched_data); break; default: @@ -608,7 +612,7 @@ void mainboard8_device::set_paddress(int address) { // Keep this value as the current address m_physical_address = (m_physical_address << 16) | address; - if (TRACE_DETAIL) logerror("Setting physical address %06x\n", m_physical_address); + LOGMASKED(LOG_DETAIL, "Setting physical address %06x\n", m_physical_address); m_mofetta->set_address(*m_space, address, m_dbin_level); m_ioport->setaddress_dbin(*m_space, address, m_dbin_level); @@ -616,7 +620,7 @@ void mainboard8_device::set_paddress(int address) WRITE_LINE_MEMBER( mainboard8_device::msast_in ) { - if (TRACE_DETAIL) logerror("msast = %d\n", state); + LOGMASKED(LOG_DETAIL, "msast = %d\n", state); // Start physical space cycle on the trailing edge if (state==CLEAR_LINE) @@ -692,7 +696,7 @@ READ8_MEMBER( mainboard8_device::read ) m_sgrom[i]->readz(space, 0, &value); } m_gromport->readz(space, 0, &value); - if (TRACE_GROM && !m_A14_set) logerror("GS>%04x\n", m_sgrom[0]->debug_get_address()-1); + if (!m_A14_set) LOGMASKED(LOG_GROM, "GS>%04x\n", m_sgrom[0]->debug_get_address()-1); what = "system GROM"; goto readdone; @@ -702,7 +706,7 @@ READ8_MEMBER( mainboard8_device::read ) { m_tsgrom[i]->readz(space, 0, &value); } - if (TRACE_GROM && !m_A14_set) logerror("GT>%04x\n", m_tsgrom[0]->debug_get_address()-1); + if (!m_A14_set) LOGMASKED(LOG_GROM, "GT>%04x\n", m_tsgrom[0]->debug_get_address()-1); what = "TTS GROM"; goto readdone; @@ -712,7 +716,7 @@ READ8_MEMBER( mainboard8_device::read ) { m_p8grom[i]->readz(space, 0, &value); } - if (TRACE_GROM && !m_A14_set) logerror("G8>%04x\n", m_p8grom[0]->debug_get_address()-1); + if (!m_A14_set) LOGMASKED(LOG_GROM, "G8>%04x\n", m_p8grom[0]->debug_get_address()-1); what = "P8 GROM"; goto readdone; @@ -722,7 +726,7 @@ READ8_MEMBER( mainboard8_device::read ) { m_p3grom[i]->readz(space, 0, &value); } - if (TRACE_GROM && !m_A14_set) logerror("G3>%04x\n", m_p3grom[0]->debug_get_address()-1); + if (!m_A14_set) LOGMASKED(LOG_GROM, "G3>%04x\n", m_p3grom[0]->debug_get_address()-1); what = "P3 GROM"; goto readdone; default: @@ -758,7 +762,7 @@ READ8_MEMBER( mainboard8_device::read ) if (m_mofetta->rom1al_out()==ASSERT_LINE) address |= 0x2000; value = m_rom1[address]; - if (TRACE_MEM) logerror("Read %04x (ROM1@%04x) -> %02x\n", m_logical_address, address, value); + LOGMASKED(LOG_MEM, "Read %04x (ROM1@%04x) -> %02x\n", m_logical_address, address, value); cycle_end(); return value; } @@ -792,7 +796,7 @@ READ8_MEMBER( mainboard8_device::read ) goto readdonephys; } - if (TRACE_PUNMAP) logerror("Read %04x (phys %06x, unmapped) ignored\n", m_logical_address, m_physical_address); + LOGMASKED(LOG_PUNMAP, "Read %04x (phys %06x, unmapped) ignored\n", m_logical_address, m_physical_address); // Memory cycle ends cycle_end(); @@ -801,12 +805,12 @@ READ8_MEMBER( mainboard8_device::read ) readdone: - if (TRACE_MEM) logerror("Read %04x (%s) -> %02x\n", m_logical_address, what, value); + LOGMASKED(LOG_MEM, "Read %04x (%s) -> %02x\n", m_logical_address, what, value); cycle_end(); return value; readdonephys: - if (TRACE_MEM) logerror("Read %04x (phys %06x, %s) -> %02x\n", m_logical_address, m_physical_address, what, value); + LOGMASKED(LOG_MEM, "Read %04x (phys %06x, %s) -> %02x\n", m_logical_address, m_physical_address, what, value); cycle_end(); return value; } @@ -841,7 +845,7 @@ WRITE8_MEMBER( mainboard8_device::write ) // GROMs and video must wait to be selected if (m_amigo->mapper_accessed()) { - if (TRACE_MEM) logerror("Write %04x (mapper) <- %02x\n", m_logical_address, data); + LOGMASKED(LOG_MEM, "Write %04x (mapper) <- %02x\n", m_logical_address, data); m_amigo->write(space, 0, data); m_pending_write = false; } @@ -850,7 +854,7 @@ WRITE8_MEMBER( mainboard8_device::write ) // sound address lies within the SRAM area if (m_vaquerro->sccs_out()==ASSERT_LINE) { - if (TRACE_MEM) logerror("Write %04x (sound) <- %02x\n", m_logical_address, data); + LOGMASKED(LOG_MEM, "Write %04x (sound) <- %02x\n", m_logical_address, data); m_sound->write(space, 0, data); // Sound chip will lower READY after this access m_pending_write = false; } @@ -859,7 +863,7 @@ WRITE8_MEMBER( mainboard8_device::write ) // SRAM if (m_amigo->sramcs_out()==ASSERT_LINE) { - if (TRACE_MEM) logerror("Write %04x (SRAM) <- %02x\n", m_logical_address, data); + LOGMASKED(LOG_MEM, "Write %04x (SRAM) <- %02x\n", m_logical_address, data); m_sram->pointer()[m_logical_address & 0x07ff] = data; m_pending_write = false; } @@ -868,7 +872,7 @@ WRITE8_MEMBER( mainboard8_device::write ) // Speech if (m_vaquerro->spwt_out()==ASSERT_LINE) { - if (TRACE_MEM) logerror("Write %04x (speech) <- %02x\n", m_logical_address, data); + LOGMASKED(LOG_MEM, "Write %04x (speech) <- %02x\n", m_logical_address, data); m_speech->data_w(space, 0, data); m_pending_write = false; } @@ -884,7 +888,7 @@ WRITE8_MEMBER( mainboard8_device::write ) */ WRITE_LINE_MEMBER( mainboard8_device::crus_in ) { - if (TRACE_CRU) logerror("%s CRUS\n", (state==1)? "Assert" : "Clear"); + LOGMASKED(LOG_CRU, "%s CRUS\n", (state==1)? "Assert" : "Clear"); m_vaquerro->crus_in(state); m_amigo->crus_in(state); m_crus_debug = (line_state)state; @@ -896,7 +900,7 @@ WRITE_LINE_MEMBER( mainboard8_device::crus_in ) */ WRITE_LINE_MEMBER( mainboard8_device::ptgen_in ) { - if (TRACE_CRU) logerror("%s PTGEN*\n", (state==0)? "Assert" : "Clear"); + LOGMASKED(LOG_CRU, "%s PTGEN*\n", (state==0)? "Assert" : "Clear"); m_vaquerro->crusgl_in((state==0)? ASSERT_LINE : CLEAR_LINE); } @@ -1124,7 +1128,7 @@ SETADDRESS_DBIN_MEMBER( vaquerro_device::set_address ) // =================== TI (compatibility) mode ====================== if (m_crus == ASSERT_LINE) { - if (TRACE_DETAIL) logerror("Compatibility mode\n"); + LOGMASKED(LOG_DETAIL, "Compatibility mode\n"); // SPRD (Speech read) m_sprd = ((offbase==0x9000) && reading); @@ -1147,7 +1151,7 @@ SETADDRESS_DBIN_MEMBER( vaquerro_device::set_address ) // ====================== Native mode ====================== else { - if (TRACE_DETAIL) logerror("Native mode\n"); + LOGMASKED(LOG_DETAIL, "Native mode\n"); // SPRD (Speech read) m_sprd = ((offbase==0xf820) && reading); @@ -1176,7 +1180,7 @@ SETADDRESS_DBIN_MEMBER( vaquerro_device::set_address ) m_lasreq = (m_sprd || m_spwt || m_sccs || m_sromcs || m_grom_or_video); - if (TRACE_DETAIL) logerror("sgfap=%d tsgfap=%d p8gfap=%d p3gfap=%d vfap=%d\n", sgfap, tsgfap, p8gfap, p3gfap, vfap); + LOGMASKED(LOG_DETAIL, "sgfap=%d tsgfap=%d p8gfap=%d p3gfap=%d vfap=%d\n", sgfap, tsgfap, p8gfap, p3gfap, vfap); // Pass the selection to the wait state generators // and pick up the current select line states @@ -1195,7 +1199,7 @@ SETADDRESS_DBIN_MEMBER( vaquerro_device::set_address ) { // We don't see the current selection now; only with next clock pulse. m_mainboard->ggrdy_in(m_sry); - if (TRACE_READY) logerror("GGRDY = %d\n", m_sry); + LOGMASKED(LOG_READY, "GGRDY = %d\n", m_sry); } } @@ -1227,25 +1231,25 @@ READ_LINE_MEMBER( vaquerro_device::lascsq_out ) */ WRITE_LINE_MEMBER( vaquerro_device::sgmry ) { - if (TRACE_READY) logerror("Incoming SGMRY = %d\n", state); + LOGMASKED(LOG_READY, "Incoming SGMRY = %d\n", state); m_sgmws.ready_in((line_state)state); } WRITE_LINE_MEMBER( vaquerro_device::tsgry ) { - if (TRACE_READY) logerror("Incoming TSGRY = %d\n", state); + LOGMASKED(LOG_READY, "Incoming TSGRY = %d\n", state); m_tsgws.ready_in((line_state)state); } WRITE_LINE_MEMBER( vaquerro_device::p8gry ) { - if (TRACE_READY) logerror("Incoming 8GRY = %d\n", state); + LOGMASKED(LOG_READY, "Incoming 8GRY = %d\n", state); m_p8gws.ready_in((line_state)state); } WRITE_LINE_MEMBER( vaquerro_device::p3gry ) { - if (TRACE_READY) logerror("Incoming P3GRY = %d\n", state); + LOGMASKED(LOG_READY, "Incoming P3GRY = %d\n", state); m_p3gws.ready_in((line_state)state); } @@ -1254,7 +1258,7 @@ WRITE_LINE_MEMBER( vaquerro_device::p3gry ) */ READ_LINE_MEMBER( vaquerro_device::ggrdy_out ) { - if (TRACE_READY) logerror("GGRDY out = %d\n", m_ggrdy); + LOGMASKED(LOG_READY, "GGRDY out = %d\n", m_ggrdy); return m_ggrdy; } @@ -1335,7 +1339,7 @@ WRITE_LINE_MEMBER( vaquerro_device::clock_in ) if (level==CLEAR_LINE) { m_sry = m_sgmws.ready_out() || m_tsgws.ready_out() || m_p8gws.ready_out() || m_p3gws.ready_out() || m_vidws.ready_out(); - if (TRACE_WS) logerror("ready_out = (%d, %d, %d, %d, %d)\n", m_sgmws.ready_out(), m_tsgws.ready_out(), m_p8gws.ready_out(), m_p3gws.ready_out(),m_vidws.ready_out()); + LOGMASKED(LOG_WS, "ready_out = (%d, %d, %d, %d, %d)\n", m_sgmws.ready_out(), m_tsgws.ready_out(), m_p8gws.ready_out(), m_p3gws.ready_out(),m_vidws.ready_out()); } // If the output gate is closed, propagate ASSERT_LINE (pulled up) @@ -1345,7 +1349,6 @@ WRITE_LINE_MEMBER( vaquerro_device::clock_in ) void vaquerro_device::device_start() { - logerror("Starting\n"); m_mainboard = downcast<mainboard8_device*>(owner()); m_sgmws.init(SGMSEL); m_tsgws.init(TSGSEL); @@ -1558,13 +1561,13 @@ SETADDRESS_DBIN_MEMBER( mofetta_device::set_address ) if (!m_gotfirstword) { // Store the first word and wait for clearing of MSAST - if (TRACE_MOFETTA) logerror("Got the upper word of the address: %04x\n", offset); + LOGMASKED(LOG_MOFETTA, "Got the upper word of the address: %04x\n", offset); m_address_latch = offset; } else { // Second part - now decode the address - if (TRACE_MOFETTA) logerror("Got the lower word of the address: %04x\n", offset); + LOGMASKED(LOG_MOFETTA, "Got the lower word of the address: %04x\n", offset); bool acs, tcs, rcs, acsx; bool reading = (state==ASSERT_LINE); @@ -1685,14 +1688,14 @@ WRITE8_MEMBER(mofetta_device::cruwrite) { // SWRST (Software reset) // Value seems to be irrelevant - if (TRACE_CRU) logerror("Doing a software reset by SBO 2702\n"); + LOGMASKED(LOG_CRU, "Doing a software reset by SBO 2702\n"); m_mainboard->reset_console(ASSERT_LINE); m_mainboard->reset_console(CLEAR_LINE); } else { m_txspg = (data!=0); // CRU>2700 - if (TRACE_CRU) logerror("Turning %s CRU>2700\n", m_txspg? "on" : "off"); + LOGMASKED(LOG_CRU, "Turning %s CRU>2700\n", m_txspg? "on" : "off"); } } else @@ -1700,7 +1703,7 @@ WRITE8_MEMBER(mofetta_device::cruwrite) if ((offset & 0xff00)==0x1700) { m_alcpg = (data!=0); // CRU>1700 - if (TRACE_CRU) logerror("Turning %s CRU>1700\n", m_alcpg? "on" : "off"); + LOGMASKED(LOG_CRU, "Turning %s CRU>1700\n", m_alcpg? "on" : "off"); } } } @@ -1740,7 +1743,6 @@ WRITE_LINE_MEMBER( mofetta_device::skdrcs_in ) void mofetta_device::device_start() { - logerror("Starting\n"); m_mainboard = downcast<mainboard8_device*>(owner()); save_item(NAME(m_pmemen)); @@ -1873,13 +1875,13 @@ int amigo_device::get_physical_address_debug(offs_t offset) */ WRITE_LINE_MEMBER( amigo_device::srdy_in ) { - if (TRACE_READY) logerror("Incoming SRDY = %d\n", state); + LOGMASKED(LOG_READY, "Incoming SRDY = %d\n", state); m_srdy = (line_state)state; // If the access is going to logical space, pass through the READY line if (m_logical_space) { - if (TRACE_CPURY) logerror("Setting CPURY = %d (SRDY)\n", m_ready_out); + LOGMASKED(LOG_CPURY, "Setting CPURY = %d (SRDY)\n", m_ready_out); m_ready_out = m_srdy; } } @@ -1958,7 +1960,7 @@ SETOFFSET_MEMBER( amigo_device::set_address ) // Is the address not in the logical address space? if (!m_logical_space) { - if (TRACE_AMIGO) logerror("Amigo decoding; %04x is a physical address.\n", offset); + LOGMASKED(LOG_AMIGO, "Amigo decoding; %04x is a physical address.\n", offset); // Build the physical address // The first three bits are the protection bits (Write, Execute, Read) // Theoretically, the addition of the logical address could mess up those @@ -1979,7 +1981,7 @@ SETOFFSET_MEMBER( amigo_device::set_address ) // Pull down READY m_ready_out = CLEAR_LINE; - if (TRACE_CPURY) logerror("Setting CPURY = %d (PAS)\n", m_ready_out); + LOGMASKED(LOG_CPURY, "Setting CPURY = %d (PAS)\n", m_ready_out); } else { @@ -1987,7 +1989,7 @@ SETOFFSET_MEMBER( amigo_device::set_address ) m_dram_accessed = false; m_amstate = IDLE; m_ready_out = m_srdy; - if (TRACE_CPURY) logerror("Setting CPURY = %d (LAS)\n", m_ready_out); + LOGMASKED(LOG_CPURY, "Setting CPURY = %d (LAS)\n", m_ready_out); } } @@ -2066,7 +2068,7 @@ void amigo_device::mapper_load() if ((m_sram_address & 0x03)==0) { - if (TRACE_MAP) logerror("Loaded basereg %02d = %08x\n", m_basereg, m_mapvalue); + LOGMASKED(LOG_MAP, "Loaded basereg %02d = %08x\n", m_basereg, m_mapvalue); m_base_register[m_basereg++] = m_mapvalue; } if (m_basereg == 16) @@ -2089,7 +2091,7 @@ void amigo_device::mapper_save() else { m_mapvalue = m_base_register[m_basereg]; - if (TRACE_MAP) logerror("Saving basereg %02d = %08x\n", m_basereg, m_mapvalue); + LOGMASKED(LOG_MAP, "Saving basereg %02d = %08x\n", m_basereg, m_mapvalue); m_basereg++; } } @@ -2131,13 +2133,12 @@ void amigo_device::mapper_access_debug(int data) WRITE_LINE_MEMBER( amigo_device::holda_in ) { - if (TRACE_MAP) logerror("HOLD acknowledged = %d\n", state); + LOGMASKED(LOG_MAP, "HOLD acknowledged = %d\n", state); m_hold_acknowledged = (state==ASSERT_LINE); } void amigo_device::device_start() { - logerror("Starting\n"); m_mainboard = downcast<mainboard8_device*>(owner()); save_item(NAME(m_memen)); @@ -2210,67 +2211,28 @@ void amigo_device::device_reset() | 8 | 7 | 6 | 5 | 8 = ADB3; 7 = ADB2; 6 = nc; 5 = HSK* +---+---+---+---+ - TODO: This is just a preliminary implementation to satisfy the operating - system. When completed we can hopefully emulate a Hexbus floppy and - use it in Extended Basic II which refuses to work with the PEB cards. - The Hexbus should then be designed as a slot device. - ****************************************************************************/ -/* Status register bits */ -enum -{ - HSKWT = 0x80, - HSKRD = 0x40, - BAVIAS = 0x20, - BAVAIS = 0x10, - SBAV = 0x08, - WBUSY = 0x04, - RBUSY = 0x02, - SHSK = 0x01 -}; - -/* Control register bits */ -enum -{ - WIEN = 0x80, - RIEN = 0x40, - BAVIAEN = 0x20, - BAVAIEN = 0x10, - BAVC = 0x08, - WEN = 0x04, - REN = 0x02, - CR7 = 0x01 -}; - -/* Line */ -enum -{ - LINE_HSK = 0x10, - LINE_BAV = 0x04, - LINE_BIT32 = 0xc0, - LINE_BIT10 = 0x03 -}; - oso_device::oso_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : bus::hexbus::hexbus_chained_device(mconfig, TI99_OSO, tag, owner, clock), m_int(*this), m_data(0), m_status(0xff), m_control(0), - m_xmit(0), m_lasthxvalue(0x01), - m_bav(false), m_sbav(false), m_sbavold(false), m_bavhold(false), - m_hsk(false), m_shsk(false), m_shskold(false), m_hskhold(false), + m_xmit(0), + m_bav(false), m_sbav(false), m_sbavold(false), m_bavold(false), + m_hsk(false), m_hsklocal(false), m_shsk(false), m_hskold(false), m_wq1(false), m_wq1old(false), m_wq2(false), m_wq2old(false), - m_wnp(false), m_wbusyold(false), m_sendbyte(false), + m_wnp(false), m_wbusy(false), m_wbusyold(false), m_sendbyte(false), m_wrset(false), m_counting(false), m_clkcount(0), m_rq1(false), m_rq2(false), m_rq2old(false), m_rnib(false), m_rnibcold(false), m_rdset(false), m_rdsetold(false), m_msns(false), m_lsns(false), - m_rhsus(false) + m_rhsus(false), m_rbusy(false), + m_phi3(false), + m_oldvalue(0xff) { - (void)m_shskold; m_hexbus_inbound = nullptr; m_hexbus_outbound = nullptr; } @@ -2283,8 +2245,8 @@ READ8_MEMBER( oso_device::read ) { case 0: // read 5FF8: read data register - if (TRACE_OSO) logerror("Read data register = %02x\n", value); value = m_data; + LOGMASKED(LOG_OSO, "Read data register = %02x\n", value); // Release the handshake m_rhsus = false; break; @@ -2292,7 +2254,7 @@ READ8_MEMBER( oso_device::read ) // read 5FFA: read status register value = m_status; clear_int_status(); - if (TRACE_OSO) logerror("Read status %02x (HSKWT=%d,HSKRD=%d,BAVIAS=%d,BAVAIS=%d,SBAV=%d,WBUSY=%d,RBUSY=%d,SHSK=%d)\n", value, + LOGMASKED(LOG_OSO, "Read status %02x (HSKWT=%d,HSKRD=%d,BAVIAS=%d,BAVAIS=%d,SBAV=%d,WBUSY=%d,RBUSY=%d,SHSK=%d)\n", value, (value&HSKWT)? 1:0, (value&HSKRD)? 1:0, (value&BAVIAS)? 1:0, (value&BAVAIS)? 1:0, (value&SBAV)? 1:0, (value&WBUSY)? 1:0, (value&RBUSY)? 1:0,(value&SHSK)? 1:0); @@ -2300,12 +2262,12 @@ READ8_MEMBER( oso_device::read ) case 2: // read 5FFC: read control register value = m_control; - if (TRACE_OSO) logerror("Read control register = %02x\n", value); + LOGMASKED(LOG_OSO, "Read control register = %02x\n", value); break; case 3: // read 5FFE: read transmit register value = m_xmit; - if (TRACE_OSO) logerror("Read transmit register = %02x\n", value); + LOGMASKED(LOG_OSO, "Read transmit register = %02x\n", value); break; } return value; @@ -2318,7 +2280,7 @@ WRITE8_MEMBER( oso_device::write ) { case 0: // write 5FF8: write transmit register - if (TRACE_OSO) logerror("Write transmit register %02x\n", data); + LOGMASKED(LOG_OSO, "Write transmit register %02x\n", data); // trigger some actions in the write subsystem m_sendbyte = true; @@ -2332,10 +2294,11 @@ WRITE8_MEMBER( oso_device::write ) break; case 1: // write 5FFA: write control register - if (TRACE_OSO) logerror("Write control register %02x (WIEN=%d, RIEN=%d, BAVIAEN=%d, BAVAIEN=%d, BAVC=%d, WEN=%d, REN=%d)\n", + LOGMASKED(LOG_OSO, "Write control register %02x (WIEN=%d, RIEN=%d, BAVIAEN=%d, BAVAIEN=%d, BAVC=%d, WEN=%d, REN=%d)\n", data, (data & WIEN)? 1:0, (data & RIEN)? 1:0, (data&BAVIAEN)? 1:0, (data&BAVAIEN)? 1:0, (data & BAVC)? 1:0, (data & WEN)? 1:0, (data & REN)? 1:0); m_control = data; + m_bav = control_bit(BAVC); // Reset some flipflops in the write/read timing section if (!control_bit(WEN)) @@ -2346,10 +2309,11 @@ WRITE8_MEMBER( oso_device::write ) { m_rq1 = m_rq2 = m_rdset = false; } + update_hexbus(); break; default: // write 5FFC, 5FFE: undefined - if (TRACE_OSO) logerror("Invalid write on %04x: %02x\n", (offset<<1) | 0x5ff0, data); + LOGMASKED(LOG_OSO, "Invalid write on %04x: %02x\n", (offset<<1) | 0x5ff0, data); break; } } @@ -2360,35 +2324,28 @@ void oso_device::clear_int_status() m_int(CLEAR_LINE); } -void oso_device::hexbus_value_changed(uint8_t data) -{ - if (TRACE_OSO) logerror("Hexbus value changed to %02x\n", data); - - m_bav = ((data & LINE_BAV)==0) | control_bit(BAVC); - - m_hsk = (data & LINE_HSK)==0; - int nibble = ((data & LINE_BIT32)>>4) | (data & LINE_BIT10); - if (m_msns) - m_data = (m_data & 0x0f) | (nibble<<4); - if (m_lsns) - m_data = (m_data & 0xf0) | nibble; -} - /* Phi3 incoming clock pulse */ WRITE_LINE_MEMBER( oso_device::clock_in ) { + m_phi3 = state; if (state==ASSERT_LINE) { // Control lines SHSK, SBAV // When BAV/HSK is 0/1 for two rising edges of Phi3*, SBAV/SHSK goes to // 0/1 at the following falling edge of Phi3*. // Page 5 - m_sbav = m_bavhold && m_bav; // could mean "stable BAV" - m_bavhold = m_bav; - m_shsk = m_hskhold && m_hsk; - m_hskhold = m_hsk; + + // In reality, the HSK and BAV signals are checked for their minimum + // width (by waiting for two cycles of constant level), but due to + // problems with synchronous execution between different parts in the + // emulation, we accept the level change immediately. + + m_sbav = m_bav; // could mean "stable BAV" + // if (control_bit(WEN)) logerror("hskhold=%d, hsk=%d\n", m_hskhold? 1:0, m_hsk? 1:0); + + m_shsk = m_hsk; set_status(SHSK, m_shsk); set_status(SBAV, m_sbav); @@ -2412,7 +2369,9 @@ WRITE_LINE_MEMBER( oso_device::clock_in ) if (control_bit(WEN)) // Nothing happens without WEN { - if (TRACE_OSO) if (!m_wrset && m_sendbyte) logerror("Starting write process\n"); + if (!m_wrset && m_sendbyte) + LOGMASKED(LOG_OSO, "Starting write process\n"); + // Page 3: Write timing // Note: First pass counts to 30, second to 31 bool cnt30 = ((m_clkcount & 0x1e) == 30); @@ -2420,7 +2379,7 @@ WRITE_LINE_MEMBER( oso_device::clock_in ) || (cnt30 && !m_wq2 && m_wq1) || (m_shsk && m_wq2 && m_wq1); bool jwq1 = cont && m_wq2; - bool kwq1 = !((cont && !m_wq2) || (!cont && m_wq2 && m_wnp)); + bool kwq1 = !(cont && !m_wq2) && !(!cont && m_wq2 && m_wnp); bool jwq2 = cont; bool kwq2 = !(m_wq1 && !cont); @@ -2431,17 +2390,26 @@ WRITE_LINE_MEMBER( oso_device::clock_in ) if (m_wq1 == true) m_sendbyte = false; - // logerror("sendbyte=%d, wq1=%d, wq2=%d, jwq1=%d, kwq1=%d, jwq2=%d, kwq2=%d, shsk=%d\n", m_sendbyte, m_wq1, m_wq2, jwq1, kwq1, jwq2, kwq2, m_shsk); + // logerror("sendbyte=%d, wq1=%d, wq2=%d, jwq1=%d, kwq1=%d, jwq2=%d, kwq2=%d\n", m_sendbyte, m_wq1, m_wq2, jwq1, kwq1, jwq2, kwq2); + // logerror("sendbyte=%d, wq1=%d, wq2=%d, m_shsk=%d\n", m_sendbyte, m_wq1, m_wq2, m_shsk); // WBUSY is asserted on byte load, during phase 1, and phase 2. - bool wbusy = m_sendbyte || m_wq1 || m_wq2; + m_wbusy = m_sendbyte || m_wq1 || m_wq2; // Set status bits and raise interrupt (p. 4) - set_status(WBUSY, wbusy); + set_status(WBUSY, m_wbusy); // Raising edge of wbusy* - if (m_wbusyold == true && wbusy == false) + // This is true when the two nibbles of the byte have been written and acknowledged + // by the receiver which has released HSK* + if (m_wbusyold == true && m_wbusy == false) + { + LOGMASKED(LOG_HEXBUS, "Setting HSKWT to true\n"); set_status(HSKWT, true); - m_wbusyold = wbusy; + // Problem: By turning off the WBUSY signal, the transmit register goes inactive + // so the peripheral setting dominates again. However, the peripheral sender will not + // send its value again. + } + m_wbusyold = m_wbusy; // Operate flipflops // Write phases @@ -2487,27 +2455,26 @@ WRITE_LINE_MEMBER( oso_device::clock_in ) if (control_bit(REN)) { - bool rbusy = m_rq1 || m_rq2; - set_status(RBUSY, rbusy); - - // Flipflop resets - if (!rbusy) m_rnib = false; - if (m_rq2) m_rdset = false; - - bool rdsetin = !control_bit(WBUSY) && m_sbav && m_shsk; + bool rdsetin = !status_bit(WBUSY) && m_sbav && m_shsk; bool next = (m_rdset && !m_rq2) || (m_shsk && m_rq2); bool drq1 = (next && m_rq2) || (m_rq2 && m_rq1 && !m_rnib); bool jrq2 = next && !m_rq1; - bool krq2 = m_rq1 && !m_rnib; - m_msns = m_rnib && !m_rq1 && m_rq2; - m_lsns = !m_rnib && !m_rq1 && m_rq2; + bool krq2 = !m_rq1 || m_rnib; bool rnibc = m_rq1; + //logerror("n=%d,d1=%d,j2=%d,k2=%d,rn=%d\n", next, drq1, jrq2, krq2, m_rnib); // Next state - if (!m_rdsetold && rdsetin) m_rdset = true; // raising edge + if (!m_rdsetold && rdsetin) + { + m_rdset = true; // raising edge + } m_rdsetold = rdsetin; + // logerror("rdset=%d, rdsetin=%d\n", m_rdset, rdsetin); + + // Set the RQ1 flipflop m_rq1 = drq1; + // Set the RQ2 flipflop if (jrq2) { if (!krq2) m_rq2 = !m_rq2; @@ -2516,12 +2483,47 @@ WRITE_LINE_MEMBER( oso_device::clock_in ) else if (!krq2) m_rq2 = false; - if (m_rnibcold == false && rnibc == true) m_rnib = !m_rnib; // raising edge + if (m_rq2) m_rdset = false; + + // Set the rnib flipflop. This is in sequence to the RQ1 flipflop. + rnibc = m_rq1; + if (m_rnibcold == false && rnibc == true) // raising edge + m_rnib = !m_rnib; + m_rnibcold = rnibc; + // Debugging only + // next = (m_rdset && !m_rq2) || (m_shsk && m_rq2); + // drq1 = (next && m_rq2) || (m_rq2 && m_rq1 && !m_rnib); + // jrq2 = next && !m_rq1; + // krq2 = !m_rq1 || m_rnib; + // logerror("r=%d,n=%d,rn=%d,d1=%d,j2=%d,k2=%d,q1=%d,q2=%d\n", m_rdset, next, m_rnib, drq1, jrq2, krq2, m_rq1, m_rq2); + + // Set RBUSY + bool rbusy = m_rq1 || m_rq2; + + if (rbusy != m_rbusy) + LOGMASKED(LOG_HEXBUS, "RBUSY=%d\n",rbusy); + + m_rbusy = rbusy; + set_status(RBUSY, rbusy); + + // Flipflop resets + if (!rbusy) m_rnib = false; + + bool msns = m_rnib && !m_rq1 && m_rq2; + bool lsns = !m_rnib && !m_rq1 && m_rq2; + + // if (msns != m_msns) LOGMASKED(LOG_HEXBUS, "MSNS=%d\n", msns); + // if (lsns != m_lsns) LOGMASKED(LOG_HEXBUS, "LSNS=%d\n", lsns); + + m_lsns = lsns; + m_msns = msns; + // Raising edge of RQ2* if (m_rq2old == true && m_rq2 == false) { + LOGMASKED(LOG_HEXBUS, "Byte available for reading\n"); set_status(HSKRD, true); m_rhsus = true; // byte is available for reading } @@ -2534,11 +2536,14 @@ WRITE_LINE_MEMBER( oso_device::clock_in ) // Handshake control // Set HSK (Page 6, RHSUS*) - bool hskwrite = !m_wq1 && m_wq2; + // This is very likely an error in the schematics. It does not make + // sense, and simulations show that the behaviour would be wrong. + // bool hskwrite = !m_wq1 && m_wq2; + bool hskwrite = (m_wq1 != m_wq2); // We can simplify this to a single flag because the CPU read operation // is atomic here (starts and immediately terminates) - m_hsk = hskwrite || m_rhsus; + m_hsklocal = hskwrite || m_rhsus; update_hexbus(); } // Actions that occur for Phi3=0 @@ -2575,26 +2580,110 @@ WRITE_LINE_MEMBER( oso_device::clock_in ) } } +/* + Change the Hexbus line levels and propagate them towards the peripherals. +*/ void oso_device::update_hexbus() { - uint8_t value = 0x00; - uint8_t nibble = m_xmit; + bool changed = false; + if (m_hsklocal != m_hskold) + { + LOGMASKED(LOG_HEXBUS, "%s HSK*\n", m_hsklocal? "Pulling down" : "Releasing"); + m_hskold = m_hsklocal; + changed = true; + } + + if (m_bav != m_bavold) + { + LOGMASKED(LOG_HEXBUS, "%s BAV*\n", m_bav? "Pulling down" : "Releasing"); + m_bavold = m_bav; + changed = true; + } + + if (!changed) return; + + // If wbusy==false, set the data output to 1111; since the Hexbus is + // a pull-down line bus, this means to inactivate the output + uint8_t nibble = m_wbusy? m_xmit : 0xff; if (m_wnp) nibble >>= 4; - value = ((m_xmit & 0x0c)<<4) | (m_xmit & 0x03); - if (!m_hsk) value |= 0x10; - if (!control_bit(BAVC)) value |= 0x04; - if (value != m_lasthxvalue) + uint8_t value = to_line_state(nibble, control_bit(BAVC), m_hsklocal); + + // if (m_oldvalue != value) + // LOGMASKED(LOG_OSO, "Set hexbus = %02x (BAV*=%d, HSK*=%d, data=%01x)\n", value, (value & 0x04)? 1:0, (value & 0x10)? 1:0, ((value>>4)&0x0c) | (value&0x03)); + + // As for Oso, we can be sure that hexbus_write does not trigger further + // activities from the peripherals that cause a call to hexbus_value_changed. + hexbus_write(value); + + // Check how the bus has changed. This depends on the states of all + // connected peripherals + uint8_t value1 = hexbus_read(); + // if (value1 != value) LOGMASKED(LOG_OSO, "actually: %02x (BAV*=%d, HSK*=%d, data=%01x)\n", value1, (value1 & 0x04)? 1:0, (value1 & 0x10)? 1:0, ((value1>>4)&0x0c) | (value1&0x03)); + + // Update the state of BAV and HSK + m_bav = ((value1 & bus::hexbus::HEXBUS_LINE_BAV)==0); + m_hsk = ((value1 & bus::hexbus::HEXBUS_LINE_HSK)==0); + + // Sometimes, Oso does not have a chance to advance its state after the + // last byte was read. In that case, a change of rdsetin would not be + // sensed. We reset the flag right here and so pretend that the tick + // has happened. + if (m_hsk==false) m_rdsetold = false; + + m_oldvalue = value1; +} + +/* + Called when the value on the Hexbus has changed. +*/ +void oso_device::hexbus_value_changed(uint8_t data) +{ +// LOGMASKED(LOG_OSO, "Hexbus value changed to %02x\n", data); + bool bav = (data & bus::hexbus::HEXBUS_LINE_BAV)==0; + bool hsk = (data & bus::hexbus::HEXBUS_LINE_HSK)==0; + + if ((bav != m_bav) || (hsk != m_hsk)) + { + m_bav = bav | control_bit(BAVC); + m_hsk = hsk; + + LOGMASKED(LOG_HEXBUS, "BAV*=%d, HSK*=%d\n", m_bav? 0:1, m_hsk? 0:1); + int nibble = ((data & bus::hexbus::HEXBUS_LINE_BIT32)>>4) | (data & bus::hexbus::HEXBUS_LINE_BIT10); + + // The real devices are driven at a similar clock rate like the 99/8. + // The designers assumed that there is a clock tick of Oso between + // every clock tick of the peripheral device. This is not true for + // the emulation in MAME, however. For that reason, we trigger "fake" + // clock ticks on every change of the hexbus. + for (int fake=0; fake < 4; fake++) + { + if (m_msns) + { + m_data = (m_data & 0x0f) | (nibble<<4); + LOGMASKED(LOG_HEXBUS, "Data register = %02x\n", m_data); + } + if (m_lsns) + { + m_data = (m_data & 0xf0) | nibble; + LOGMASKED(LOG_HEXBUS, "Data register = %02x\n", m_data); + } + + LOGMASKED(LOG_HEXBUS, "Fake tick %d\n", fake); + bool phi3 = m_phi3; // mind that clock_in swaps the state of m_phi3 + clock_in(!phi3); + clock_in(phi3); + LOGMASKED(LOG_HEXBUS, "Fake tick %d end\n", fake); + } + } + else { - if (TRACE_OSO) logerror("Set hexbus = %02x (BAV*=%d, HSK*=%d, data=%01x)\n", value, (value & 0x04)? 1:0, (value & 0x10)? 1:0, ((value>>4)&0x0c) | (value&0x03)); - hexbus_write(value); + LOGMASKED(LOG_HEXBUS, "No change for BAV* and HSK*\n"); } - m_lasthxvalue = value; } void oso_device::device_start() { - logerror("Starting\n"); m_status = m_xmit = m_control = m_data = 0; m_int.resolve_safe(); diff --git a/src/devices/bus/ti99/internal/998board.h b/src/devices/bus/ti99/internal/998board.h index 526fad8bf44..e8df327cae1 100644 --- a/src/devices/bus/ti99/internal/998board.h +++ b/src/devices/bus/ti99/internal/998board.h @@ -422,6 +422,33 @@ private: /* Custom chip: OSO */ + +/* Status register bits */ +typedef enum +{ + HSKWT = 0x80, + HSKRD = 0x40, + BAVIAS = 0x20, + BAVAIS = 0x10, + SBAV = 0x08, + WBUSY = 0x04, + RBUSY = 0x02, + SHSK = 0x01 +} oso_status; + +/* Control register bits */ +typedef enum +{ + WIEN = 0x80, + RIEN = 0x40, + BAVIAEN = 0x20, + BAVAIEN = 0x10, + BAVC = 0x08, + WEN = 0x04, + REN = 0x02, + CR7 = 0x01 +} oso_control; + class oso_device : public bus::hexbus::hexbus_chained_device { public: @@ -429,9 +456,6 @@ public: DECLARE_READ8_MEMBER( read ); DECLARE_WRITE8_MEMBER( write ); void device_start() override; - // Don't add a hexbus connector; we use the one from the driver instance - virtual void device_add_mconfig(machine_config &config) override { }; - void hexbus_value_changed(uint8_t data) override; WRITE_LINE_MEMBER( clock_in ); @@ -440,8 +464,8 @@ public: devcb_write_line m_int; private: - bool control_bit(int bit) { return (m_control & bit)!=0; } - bool status_bit(int bit) { return (m_status & bit)!=0; } + bool control_bit(oso_control bit) { return (m_control & bit)!=0; } + bool status_bit(oso_status bit) { return (m_status & bit)!=0; } void clear_int_status(); void set_status(int bit, bool set) { m_status = (set)? (m_status | bit) : (m_status & ~bit); } void update_hexbus(); @@ -452,18 +476,15 @@ private: uint8_t m_control; uint8_t m_xmit; - // Last hexbus value; when the new value is different, send it via the hexbus - uint8_t m_lasthxvalue; - bool m_bav; // Bus available; when true, a communication is about to happen bool m_sbav; // Stable BAV; the BAV signal is true for two clock cycles bool m_sbavold; // Old SBAV state - bool m_bavhold; // For computing the SBAV signal + bool m_bavold; bool m_hsk; // Handshake line; when true, a bus member needs more time to process the message + bool m_hsklocal; // Local level of HSK bool m_shsk; // Stable HSK - bool m_shskold; // see above - bool m_hskhold; // see above + bool m_hskold; // Page 3 in OSO schematics: Write timing bool m_wq1; // Flipflop 1 @@ -471,6 +492,7 @@ private: bool m_wq2; // Flipflop 2 bool m_wq2old; // Previous state bool m_wnp; // Write nibble selection; true means upper 4 bits + bool m_wbusy; // When true, direct the transmit register towards the output bool m_wbusyold; // Old state of the WBUSY line bool m_sendbyte; // Byte has been loaded into the XMIT register bool m_wrset; // Start sending @@ -490,6 +512,25 @@ private: // Page 6 (RHSUS*) bool m_rhsus; // Needed to assert the HSK line until the CPU has read the byte + + bool m_rbusy; + + bool m_phi3; + + // Debugging help + uint8_t m_oldvalue; +/* + // This is a buffer to enqueue changes on the Hexbus + // This is not part of the real implementation, but in the emulation + // there is no guarantee that two subsequent bus changes will be sensed + // on the other side + + void enqueue(uint8_t val); + uint8_t dequeue(); + + uint8_t m_queue[8]; + int m_qhead; + int m_qtail; */ }; class mainboard8_device : public device_t diff --git a/src/devices/cpu/tms9900/tms9995.cpp b/src/devices/cpu/tms9900/tms9995.cpp index ce854d82c04..7a9382f571e 100644 --- a/src/devices/cpu/tms9900/tms9995.cpp +++ b/src/devices/cpu/tms9900/tms9995.cpp @@ -121,59 +121,33 @@ enum /***************************************************************** Debugging - Set to 0 (disable) or 1 (enable) + Add the desired LOG aspect to the VERBOSE line ******************************************************************/ -// Log addresses of executed opcodes -#define TRACE_EXEC 0 - -// Log cycles -#define TRACE_CYCLES 0 - -// Log configuration -#define TRACE_CONFIG 1 - -// Log emulation details -#define TRACE_EMU 0 - -// Log wait/hold states -#define TRACE_WAITHOLD 0 - -// Log microinstruction processing -#define TRACE_MICRO 0 - -// Log interrupts -#define TRACE_INT 0 - -// Log interrupts (detailed phases) -#define TRACE_INTD 0 - -// Log clock pulses -#define TRACE_CLOCK 0 - -// Log READY line input -#define TRACE_READY 0 - -// Log memory access -#define TRACE_MEM 0 - -// Log address bus operation -#define TRACE_ADDRESSBUS 0 - -// Log CRU operations -#define TRACE_CRU 0 - -// Log status register -#define TRACE_STATUS 0 - -// Log operation -#define TRACE_OP 0 - -// Log decrementer operation -#define TRACE_DEC 0 - -// Log with max detail -#define TRACE_DETAIL 0 +#define LOG_OP (1U<<1) // Current instruction +#define LOG_EXEC (1U<<2) // Address of current instruction +#define LOG_CONFIG (1U<<3) // Configuration +#define LOG_CYCLES (1U<<4) // Cycles +#define LOG_WARN (1U<<5) // Illegal operation or other condition +#define LOG_MEM (1U<<6) // Memory access +#define LOG_CONTEXT (1U<<7) // Context switch +#define LOG_INT (1U<<8) // Interrupts +#define LOG_READY (1U<<9) // READY line input +#define LOG_CLOCK (1U<<10) // Clock pulses +#define LOG_ADDRESSBUS (1U<<11) // Address bus operation +#define LOG_STATUS (1U<<12) // Status register +#define LOG_CRU (1U<<13) // CRU operations +#define LOG_DEC (1U<<14) // Decrementer +#define LOG_WAITHOLD (1U<<15) // Wait/hold states +#define LOG_EMU (1U<<16) // Emulation details +#define LOG_MICRO (1U<<17) // Microinstruction processing +#define LOG_INTD (1U<<18) // Interrupts (detailed phases) +#define LOG_DETAIL (1U<<19) // Increased detail + +// Minimum log should be config and warnings +#define VERBOSE ( LOG_CONFIG | LOG_WARN ) + +#include "logmacro.h" /**************************************************************************** Constructor @@ -257,7 +231,7 @@ void tms9995_device::device_start() // Set up the lookup table for command decoding build_command_lookup_table(); - if (TRACE_CONFIG) logerror("%s: Variant = %s, Overflow int = %s\n", tag(), m_mp9537? "MP9537 (no on-chip RAM)" : "with on-chip RAM", m_check_overflow? "check" : "no check"); + LOGMASKED(LOG_CONFIG, "Variant = %s, Overflow int = %s\n", m_mp9537? "MP9537 (no on-chip RAM)" : "standard (with on-chip RAM)", m_check_overflow? "check" : "no check"); // Register persistable state variables // save_item(NAME(m_state_any)); // only for debugger output @@ -1172,7 +1146,7 @@ void tms9995_device::build_command_lookup_table() { inst = &s_command[i]; table = m_command_lookup_table.get(); - if (TRACE_EMU) logerror("=== opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]); + LOGMASKED(LOG_EMU, "=== opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]); bitcount = 4; opcode = inst->opcode; cmdindex = (opcode>>12) & 0x000f; @@ -1182,7 +1156,7 @@ void tms9995_device::build_command_lookup_table() // Descend if (table[cmdindex].next_digit == nullptr) { - if (TRACE_EMU) logerror("create new table at bitcount=%d for index=%d\n", bitcount, cmdindex); + LOGMASKED(LOG_EMU, "create new table at bitcount=%d for index=%d\n", bitcount, cmdindex); table[cmdindex].next_digit = std::make_unique<lookup_entry[]>(16); for (int j=0; j < 16; j++) { @@ -1192,7 +1166,7 @@ void tms9995_device::build_command_lookup_table() } else { - if (TRACE_EMU) logerror("found a table at bitcount=%d\n", bitcount); + LOGMASKED(LOG_EMU, "found a table at bitcount=%d\n", bitcount); } table = table[cmdindex].next_digit.get(); @@ -1200,17 +1174,17 @@ void tms9995_device::build_command_lookup_table() bitcount = bitcount+4; opcode <<= 4; cmdindex = (opcode>>12) & 0x000f; - if (TRACE_EMU) logerror("next index=%x\n", cmdindex); + LOGMASKED(LOG_EMU, "next index=%x\n", cmdindex); } - if (TRACE_EMU) logerror("bitcount=%d\n", bitcount); + LOGMASKED(LOG_EMU, "bitcount=%d\n", bitcount); // We are at the target level // Need to fill in the same entry for all values in the bitcount // (if a command needs 10 bits we have to copy it four // times for all combinations with 12 bits) for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++) { - if (TRACE_EMU) logerror("opcode=%04x at position %d\n", inst->opcode, cmdindex+j); + LOGMASKED(LOG_EMU, "opcode=%04x at position %d\n", inst->opcode, cmdindex+j); table[cmdindex+j].index = i; } @@ -1234,14 +1208,14 @@ void tms9995_device::execute_run() { if (m_reset) service_interrupt(); - if (TRACE_EMU) logerror("calling execute_run for %d cycles\n", m_icount); + LOGMASKED(LOG_EMU, "calling execute_run for %d cycles\n", m_icount); do { // Normal operation if (m_check_ready && m_ready == false) { // We are in a wait state - if (TRACE_WAITHOLD) logerror("wait state\n"); + LOGMASKED(LOG_WAITHOLD, "wait state\n"); // The clock output should be used to change the state of an outer // device which operates the READY line pulse_clock(1); @@ -1251,7 +1225,7 @@ void tms9995_device::execute_run() if (m_check_hold && m_hold_requested) { set_hold_state(true); - if (TRACE_WAITHOLD) logerror("HOLD state\n"); + LOGMASKED(LOG_WAITHOLD, "HOLD state\n"); pulse_clock(1); } else @@ -1260,7 +1234,7 @@ void tms9995_device::execute_run() m_check_ready = false; - if (TRACE_MICRO) logerror("main loop, operation %s, MPC = %d\n", opname[m_command], MPC); + LOGMASKED(LOG_MICRO, "main loop, operation %s, MPC = %d\n", opname[m_command], MPC); uint8_t* program = (uint8_t*)s_command[m_index].prog; (this->*s_microoperation[program[MPC]])(); @@ -1276,7 +1250,7 @@ void tms9995_device::execute_run() } } while (m_icount>0 && !m_reset); - if (TRACE_EMU) logerror("cycles expired; will return soon.\n"); + LOGMASKED(LOG_EMU, "cycles expired; will return soon.\n"); } /**************************************************************************/ @@ -1303,28 +1277,28 @@ void tms9995_device::execute_set_input(int irqline, int state) if (irqline == INPUT_LINE_NMI) { m_nmi_active = (state==ASSERT_LINE); - if (TRACE_INT) logerror("NMI interrupt line state=%d\n", state); + LOGMASKED(LOG_INT, "NMI interrupt line state=%d\n", state); } else { if (irqline == INT_9995_INT1) { m_int1_active = m_flag[2] = (state==ASSERT_LINE); - if (TRACE_INT) logerror("Line INT1 state=%d\n", state); + LOGMASKED(LOG_INT, "Line INT1 state=%d\n", state); } else { if (irqline == INT_9995_INT4) { - if (TRACE_INT) logerror("Line INT4/EC state=%d\n", state); + LOGMASKED(LOG_INT, "Line INT4/EC state=%d\n", state); if (m_flag[0]==false) { - if (TRACE_INT) logerror("set as interrupt\n"); + LOGMASKED(LOG_INT, "set as interrupt\n"); m_int4_active = m_flag[4] = (state==ASSERT_LINE); } else { - if (TRACE_INT) logerror("set as event count\n"); + LOGMASKED(LOG_INT, "set as event count\n"); trigger_decrementer(); } } @@ -1363,11 +1337,12 @@ void tms9995_device::pulse_clock(int count) m_ready = m_ready_bufd && !m_request_auto_wait_state; // get the latched READY state if (!m_clock_out_line.isnull()) m_clock_out_line(CLEAR_LINE); m_icount--; // This is the only location where we count down the cycles. - if (TRACE_CLOCK) - { - if (m_check_ready) logerror("pulse_clock, READY=%d, auto_wait=%d\n", m_ready_bufd? 1:0, m_auto_wait? 1:0); - else logerror("pulse_clock\n"); - } + + if (m_check_ready) + LOGMASKED(LOG_CLOCK, "pulse_clock, READY=%d, auto_wait=%d\n", m_ready_bufd? 1:0, m_auto_wait? 1:0); + else + LOGMASKED(LOG_CLOCK, "pulse_clock\n"); + m_request_auto_wait_state = false; if (m_flag[0] == false && m_flag[1] == true) { @@ -1385,7 +1360,7 @@ void tms9995_device::pulse_clock(int count) WRITE_LINE_MEMBER( tms9995_device::hold_line ) { m_hold_requested = (state==ASSERT_LINE); - if (TRACE_WAITHOLD) logerror("set HOLD = %d\n", state); + LOGMASKED(LOG_WAITHOLD, "set HOLD = %d\n", state); if (!m_hold_requested) { if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE); @@ -1398,11 +1373,19 @@ WRITE_LINE_MEMBER( tms9995_device::hold_line ) */ WRITE_LINE_MEMBER( tms9995_device::ready_line ) { - if (m_reset && (m_ready_bufd != state)) logerror("Ignoring READY=%d change due to pending RESET\n", state); - else + bool newready = (state==ASSERT_LINE); + + if (newready != m_ready_bufd) { - m_ready_bufd = (state==ASSERT_LINE); - if (TRACE_READY) logerror("set READY = %d\n", m_ready_bufd? 1 : 0); + if (m_reset) + { + LOGMASKED(LOG_WARN, "Ignoring READY=%d change due to pending RESET\n", state); + } + else + { + m_ready_bufd = newready; + LOGMASKED(LOG_READY, "set READY = %d\n", m_ready_bufd? 1 : 0); + } } } @@ -1444,7 +1427,7 @@ void tms9995_device::decode(uint16_t inst) while (!complete) { ix = (opcode >> 12) & 0x000f; - if (TRACE_EMU) logerror("Check next hex digit of instruction %x\n", ix); + LOGMASKED(LOG_EMU, "Check next hex digit of instruction %x\n", ix); if (table[ix].next_digit != nullptr) { table = table[ix].next_digit.get(); @@ -1457,7 +1440,7 @@ void tms9995_device::decode(uint16_t inst) if (program_index == NOPRG) { // not found - logerror("Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC); + LOGMASKED(LOG_WARN, "Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC); m_pre_IR = 0; m_pre_command = MID; } @@ -1469,7 +1452,7 @@ void tms9995_device::decode(uint16_t inst) m_pre_command = decoded.id; m_pre_index = program_index; m_pre_byteop = ((decoded.format == 1) && ((inst & 0x1000)!=0)); - if (TRACE_EMU) logerror("Command decoded as id %d, %s, base opcode %04x\n", decoded.id, opname[decoded.id], decoded.opcode); + LOGMASKED(LOG_EMU, "Command decoded as id %d, %s, base opcode %04x\n", decoded.id, opname[decoded.id], decoded.opcode); m_pass = 1; } } @@ -1489,7 +1472,7 @@ void tms9995_device::int_prefetch_and_decode() // Check interrupt lines if (m_nmi_active) { - if (TRACE_INT) logerror("Checking interrupts ... NMI active\n"); + LOGMASKED(LOG_INT, "Checking interrupts ... NMI active\n"); m_int_pending |= PENDING_NMI; m_idle_state = false; PC = (PC + 2) & 0xfffe; // we have not prefetched the next instruction @@ -1512,19 +1495,19 @@ void tms9995_device::int_prefetch_and_decode() if (m_idle_state) { m_idle_state = false; - if (TRACE_INT) logerror("Interrupt occurred, terminate IDLE state\n"); + LOGMASKED(LOG_INT, "Interrupt occurred, terminate IDLE state\n"); } PC = PC + 2; // PC must be advanced (see flow chart), but no prefetch - if (TRACE_INT) logerror("Interrupts pending; no prefetch; advance PC to %04x\n", PC); + LOGMASKED(LOG_INT, "Interrupts pending; no prefetch; advance PC to %04x\n", PC); return; } else { - if (TRACE_INT) logerror("Checking interrupts ... none pending\n"); + LOGMASKED(LOG_INT, "Checking interrupts ... none pending\n"); // No pending interrupts if (m_idle_state) { - if (TRACE_WAITHOLD) logerror("IDLE state\n"); + LOGMASKED(LOG_WAITHOLD, "IDLE state\n"); // We are IDLE, stay in the loop and do not advance the PC m_pass = 2; pulse_clock(1); @@ -1554,7 +1537,7 @@ void tms9995_device::prefetch_and_decode() m_value_copy = m_current_value; if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); m_address = PC; - if (TRACE_OP) logerror("**** Prefetching new instruction at %04x ****\n", PC); + LOGMASKED(LOG_DETAIL, "**** Prefetching new instruction at %04x ****\n", PC); } word_read(); // changes m_mem_phase @@ -1567,7 +1550,7 @@ void tms9995_device::prefetch_and_decode() m_current_value = m_value_copy; // restore m_current_value PC = (PC + 2) & 0xfffe; // advance PC if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE); - if (TRACE_OP) logerror("++++ Prefetch done ++++\n"); + LOGMASKED(LOG_DETAIL, "++++ Prefetch done ++++\n"); } } @@ -1598,13 +1581,14 @@ void tms9995_device::next_command() // This is a preset for opcodes which do not need an opcode address derivation m_address = WP + ((IR & 0x000f)<<1); MPC = -1; - if (TRACE_OP) logerror("===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC-2); + LOGMASKED(LOG_OP, "===== %04x: Op=%04x (%s)\n", PC-2, IR, opname[m_command]); + + // Mark logged address as interrupt service + if (m_log_interrupt) + LOGMASKED(LOG_EXEC, "i%04x\n", PC-2); + else + LOGMASKED(LOG_EXEC, "%04x\n", PC-2); - if (TRACE_EXEC) - { - if (m_log_interrupt) logerror("i%04x\n", PC-2); - else logerror("%04x\n", PC-2); - } PC_debug = PC - 2; debugger_instruction_hook(PC_debug); m_first_cycle = m_icount; @@ -1617,7 +1601,7 @@ void tms9995_device::next_command() void tms9995_device::command_completed() { // Pseudo state at the end of the current instruction cycle sequence - if (TRACE_CYCLES) + if (LOG_CYCLES & VERBOSE) { logerror("+++++ Instruction %04x (%s) completed", IR, opname[m_command]); int cycles = m_first_cycle - m_icount; @@ -1679,7 +1663,7 @@ void tms9995_device::service_interrupt() vectorpos = 0x0008; m_intmask = 0x0001; PC = (PC + 2) & 0xfffe; - if (TRACE_INT) logerror("***** MID pending\n"); + LOGMASKED(LOG_INT, "***** MID pending\n"); m_mid_active = false; } else @@ -1689,7 +1673,7 @@ void tms9995_device::service_interrupt() vectorpos = 0xfffc; m_int_pending &= ~PENDING_NMI; m_intmask = 0; - if (TRACE_INT) logerror("***** NMI pending\n"); + LOGMASKED(LOG_INT, "***** NMI pending\n"); } else { @@ -1699,7 +1683,7 @@ void tms9995_device::service_interrupt() m_int_pending &= ~PENDING_LEVEL1; m_flag[2] = false; m_intmask = 0; - if (TRACE_INT) logerror("***** INT1 pending\n"); + LOGMASKED(LOG_INT, "***** INT1 pending\n"); } else { @@ -1708,7 +1692,7 @@ void tms9995_device::service_interrupt() vectorpos = 0x0008; m_int_pending &= ~PENDING_OVERFLOW; m_intmask = 0x0001; - if (TRACE_INT) logerror("***** OVERFL pending\n"); + LOGMASKED(LOG_INT, "***** OVERFL pending\n"); } else { @@ -1719,7 +1703,7 @@ void tms9995_device::service_interrupt() m_int_pending &= ~PENDING_DECR; m_flag[3] = false; m_int_decrementer = false; - if (TRACE_DEC) logerror("***** DECR pending\n"); + LOGMASKED(LOG_DEC, "***** DECR pending\n"); } else { @@ -1727,7 +1711,7 @@ void tms9995_device::service_interrupt() m_intmask = 0x0003; m_int_pending &= ~PENDING_LEVEL4; m_flag[4] = false; - if (TRACE_INT) logerror("***** INT4 pending\n"); + LOGMASKED(LOG_INT, "***** INT4 pending\n"); } } } @@ -1735,7 +1719,7 @@ void tms9995_device::service_interrupt() } } - if (TRACE_INT) logerror("********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2); + LOGMASKED(LOG_INT, "********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2); // just for debugging purposes if (!m_reset) m_log_interrupt = true; @@ -1787,7 +1771,7 @@ void tms9995_device::mem_read() if ((m_address & 0xfffe)==0xfffa && !m_mp9537) { - if (TRACE_DEC) logerror("read decrementer\n"); + LOGMASKED(LOG_DEC, "read decrementer\n"); // Decrementer mapped into the address space m_current_value = m_decrementer_value; if (m_byteop) @@ -1806,7 +1790,7 @@ void tms9995_device::mem_read() // byte operations (e.g. when retrieving the index register) if (m_word_access || !m_byteop) m_address &= 0xfffe; - if (TRACE_MEM) logerror("read onchip memory (single pass, address %04x)\n", m_address); + LOGMASKED(LOG_MEM, "read onchip memory (single pass, address %04x)\n", m_address); // Ignore the READY state m_check_ready = false; @@ -1841,7 +1825,7 @@ void tms9995_device::mem_read() else m_pass = 2; m_check_hold = false; - if (TRACE_ADDRESSBUS) logerror("set address bus %04x\n", m_address & ~1); + LOGMASKED(LOG_ADDRESSBUS, "set address bus %04x\n", m_address & ~1); m_prgspace->set_address(address); m_request_auto_wait_state = m_auto_wait; pulse_clock(1); @@ -1850,12 +1834,12 @@ void tms9995_device::mem_read() // Sample the value on the data bus (high byte) if (m_word_access || !m_byteop) address &= 0xfffe; value = m_prgspace->read_byte(address); - if (TRACE_MEM) logerror("memory read byte %04x -> %02x\n", m_address & ~1, value); + LOGMASKED(LOG_MEM, "memory read byte %04x -> %02x\n", m_address & ~1, value); m_current_value = (value << 8) & 0xff00; break; case 3: // Set address + 1 (unless byte command) - if (TRACE_ADDRESSBUS) logerror("set address bus %04x\n", m_address | 1); + LOGMASKED(LOG_ADDRESSBUS, "set address bus %04x\n", m_address | 1); m_prgspace->set_address(m_address | 1); m_request_auto_wait_state = m_auto_wait; pulse_clock(1); @@ -1864,7 +1848,7 @@ void tms9995_device::mem_read() // Read low byte value = m_prgspace->read_byte(m_address | 1); m_current_value |= value; - if (TRACE_MEM) logerror("memory read byte %04x -> %02x, complete word = %04x\n", m_address | 1, value, m_current_value); + LOGMASKED(LOG_MEM, "memory read byte %04x -> %02x, complete word = %04x\n", m_address | 1, value, m_current_value); m_check_hold = true; break; } @@ -1932,7 +1916,7 @@ void tms9995_device::mem_write() { m_starting_count_storage_register = m_decrementer_value = m_current_value; } - if (TRACE_DEC) logerror("Setting decrementer to %04x, PC=%04x\n", m_current_value, PC); + LOGMASKED(LOG_DEC, "Setting decrementer to %04x, PC=%04x\n", m_current_value, PC); pulse_clock(1); return; } @@ -1944,7 +1928,7 @@ void tms9995_device::mem_write() // byte operations (e.g. when retrieving the index register) if (m_word_access || !m_byteop) m_address &= 0xfffe; - if (TRACE_MEM) logerror("write to onchip memory (single pass, address %04x, value=%04x)\n", m_address, m_current_value); + LOGMASKED(LOG_MEM, "write to onchip memory (single pass, address %04x, value=%04x)\n", m_address, m_current_value); m_check_ready = false; m_onchip_memory[m_address & 0x00ff] = (m_current_value >> 8) & 0xff; if (m_word_access || !m_byteop) @@ -1973,9 +1957,9 @@ void tms9995_device::mem_write() else m_pass = 2; m_check_hold = false; - if (TRACE_ADDRESSBUS) logerror("set address bus %04x\n", address); + LOGMASKED(LOG_ADDRESSBUS, "set address bus %04x\n", address); m_prgspace->set_address(address); - if (TRACE_MEM) logerror("memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff); + LOGMASKED(LOG_MEM, "memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff); m_prgspace->write_byte(address, (m_current_value >> 8)&0xff); m_request_auto_wait_state = m_auto_wait; pulse_clock(1); @@ -1986,9 +1970,9 @@ void tms9995_device::mem_write() break; case 3: // Set address + 1 (unless byte command) - if (TRACE_ADDRESSBUS) logerror("set address bus %04x\n", m_address | 1); + LOGMASKED(LOG_ADDRESSBUS, "set address bus %04x\n", m_address | 1); m_prgspace->set_address(m_address | 1); - if (TRACE_MEM) logerror("memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff); + LOGMASKED(LOG_MEM, "memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff); m_prgspace->write_byte(m_address | 1, m_current_value & 0xff); m_request_auto_wait_state = m_auto_wait; pulse_clock(1); @@ -2029,7 +2013,7 @@ void tms9995_device::return_with_address() m_index = m_caller_index; MPC = m_caller_MPC; // will be increased on return m_address = m_current_value + m_address_add; - if (TRACE_DETAIL) logerror("+++ return from operand address derivation +++\n"); + LOGMASKED(LOG_DETAIL, "+++ return from operand address derivation +++\n"); // no clock pulse } @@ -2043,7 +2027,7 @@ void tms9995_device::return_with_address_copy() m_index = m_caller_index; MPC = m_caller_MPC; // will be increased on return m_address = m_address_saved; - if (TRACE_DETAIL) logerror("+++ return from operand address derivation (auto inc) +++\n"); + LOGMASKED(LOG_DETAIL, "+++ return from operand address derivation (auto inc) +++\n"); // no clock pulse } @@ -2084,7 +2068,7 @@ void tms9995_device::return_with_address_copy() void tms9995_device::cru_output_operation() { - if (TRACE_CRU) logerror("CRU output operation, address %04x, value %d\n", m_cru_address, m_cru_value & 0x01); + LOGMASKED(LOG_CRU, "CRU output operation, address %04x, value %d\n", m_cru_address, m_cru_value & 0x01); if (m_cru_address == 0x1fda) { @@ -2099,7 +2083,7 @@ void tms9995_device::cru_output_operation() { m_check_ready = false; // FLAG2, FLAG3, and FLAG4 are read-only - if (TRACE_CRU) logerror("set CRU address %04x to %d\n", m_cru_address, m_cru_value&1); + LOGMASKED(LOG_CRU, "set CRU address %04x to %d\n", m_cru_address, m_cru_value&1); if ((m_cru_address != 0x1ee4) && (m_cru_address != 0x1ee6) && (m_cru_address != 0x1ee8)) m_flag[(m_cru_address>>1)&0x000f] = (m_cru_value & 0x01); } @@ -2156,7 +2140,7 @@ void tms9995_device::cru_input_operation() // ........ ........ X....... ........ // crubyte = m_cru->read_byte((m_cru_address >> 4)& CRUREADMASK); - if (TRACE_DETAIL) logerror("Need to get next 8 bits (addresses %04x-%04x): %02x\n", (m_cru_address&0xfff0)+14, m_cru_address&0xfff0, crubyte); + LOGMASKED(LOG_DETAIL, "Need to get next 8 bits (addresses %04x-%04x): %02x\n", (m_cru_address&0xfff0)+14, m_cru_address&0xfff0, crubyte); m_cru_read = crubyte << 15; m_cru_bits_left = 8; @@ -2168,7 +2152,7 @@ void tms9995_device::cru_input_operation() m_cru_first_read = false; m_pass = m_count; } - if (TRACE_DETAIL) logerror("adjusted value for shift: %06x\n", m_cru_read); + LOGMASKED(LOG_DETAIL, "adjusted value for shift: %06x\n", m_cru_read); } crubit = (m_cru_read & 0x8000); @@ -2194,7 +2178,7 @@ void tms9995_device::cru_input_operation() } } - if (TRACE_CRU) logerror("CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15); + LOGMASKED(LOG_CRU, "CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15); m_cru_value |= crubit; @@ -2224,11 +2208,11 @@ void tms9995_device::trigger_decrementer() m_decrementer_value--; if (m_decrementer_value==0) { - if (TRACE_DEC) logerror("decrementer reached 0\n"); + LOGMASKED(LOG_DEC, "decrementer reached 0\n"); m_decrementer_value = m_starting_count_storage_register; if (m_flag[1]==true) { - if (TRACE_DEC) logerror("decrementer flags interrupt\n"); + LOGMASKED(LOG_DEC, "decrementer flags interrupt\n"); m_flag[3] = true; m_int_decrementer = true; } @@ -2277,12 +2261,12 @@ void tms9995_device::operand_address_subprogram() { if (m_regnumber != 0) { - if (TRACE_DETAIL) logerror("indexed addressing\n"); + LOGMASKED(LOG_DETAIL, "indexed addressing\n"); MPC = 16; // indexed } else { - if (TRACE_DETAIL) logerror("symbolic addressing\n"); + LOGMASKED(LOG_DETAIL, "symbolic addressing\n"); m_address = PC; PC = (PC + 2) & 0xfffe; } @@ -2292,7 +2276,7 @@ void tms9995_device::operand_address_subprogram() m_mem_phase = 1; m_address_add = 0; MPC--; // will be increased in the mail loop - if (TRACE_DETAIL) logerror("*** Operand address derivation; address=%04x; index=%d\n", m_address, MPC+1); + LOGMASKED(LOG_DETAIL, "*** Operand address derivation; address=%04x; index=%d\n", m_address, MPC+1); } /* @@ -2434,7 +2418,7 @@ void tms9995_device::alu_add_s_sxc() { set_status_parity((uint8_t)(dest_new>>8)); } - if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); // No clock pulse (will be done by prefetch) } @@ -2481,7 +2465,7 @@ void tms9995_device::alu_blwp() case 4: PC = m_current_value & 0xfffe; n = 0; - if (TRACE_OP) logerror("Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); + LOGMASKED(LOG_CONTEXT, "Context switch (blwp): WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); break; } m_inst_state++; @@ -2502,7 +2486,7 @@ void tms9995_device::alu_c() set_status_parity((uint8_t)(m_source_value>>8)); } compare_and_set_lae(m_source_value, m_current_value); - if (TRACE_STATUS) logerror("ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); } /* @@ -2513,12 +2497,12 @@ void tms9995_device::alu_ci() // We have the register value in m_source_value, the register address in m_address_saved // and the immediate value in m_current_value compare_and_set_lae(m_source_value, m_current_value); - if (TRACE_STATUS) logerror("ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); } void tms9995_device::alu_clr_seto() { - if (TRACE_OP) logerror("clr/seto: Setting values for address %04x\n", m_address); + LOGMASKED(LOG_DETAIL, "clr/seto: Setting values for address %04x\n", m_address); switch (m_command) { case CLR: @@ -2727,14 +2711,14 @@ void tms9995_device::alu_external() if (m_command == IDLE) { - if (TRACE_OP) logerror("Entering IDLE state\n"); + LOGMASKED(LOG_OP, "Entering IDLE state\n"); m_idle_state = true; } if (m_command == RSET) { ST &= 0xfff0; - if (TRACE_OP) logerror("RSET, new ST = %04x\n", ST); + LOGMASKED(LOG_OP, "RSET, new ST = %04x\n", ST); } if (!m_external_operation.isnull()) @@ -2776,7 +2760,7 @@ void tms9995_device::alu_f3() compare_and_set_lae(m_current_value, 0); } } - if (TRACE_STATUS) logerror("ST = %04x\n", ST); + LOGMASKED(LOG_STATUS, "ST = %04x\n", ST); break; } m_inst_state++; @@ -2812,7 +2796,7 @@ void tms9995_device::alu_imm_arithm() m_current_value = (uint16_t)(dest_new & 0xffff); compare_and_set_lae(m_current_value, 0); m_address = m_address_saved; - if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); } /* @@ -2868,11 +2852,11 @@ void tms9995_device::alu_jump() if (!cond) { - if (TRACE_OP) logerror("Jump condition false\n"); + LOGMASKED(LOG_DETAIL, "Jump condition false\n"); } else { - if (TRACE_OP) logerror("Jump condition true\n"); + LOGMASKED(LOG_DETAIL, "Jump condition true\n"); PC = (PC + (displacement<<1)) & 0xfffe; } } @@ -2892,7 +2876,7 @@ void tms9995_device::alu_ldcr() case 1: // We have read the byte or word into m_current_value. compare_and_set_lae(m_current_value, 0); - if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); // Parity is computed from the complete byte, even when less than // 8 bits are transferred (see [1]). @@ -2924,7 +2908,7 @@ void tms9995_device::alu_li() // The immediate value is still in m_current_value m_address = m_address_saved; compare_and_set_lae(m_current_value, 0); - if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); } void tms9995_device::alu_limi_lwpi() @@ -2933,13 +2917,13 @@ void tms9995_device::alu_limi_lwpi() if (m_command == LIMI) { ST = (ST & 0xfff0) | (m_current_value & 0x000f); - if (TRACE_OP) logerror("LIMI sets ST = %04x\n", ST); + LOGMASKED(LOG_DETAIL, "LIMI sets ST = %04x\n", ST); pulse_clock(1); // needs one more than LWPI } else { WP = m_current_value & 0xfffe; - if (TRACE_OP) logerror("LWPI sets new WP = %04x\n", WP); + LOGMASKED(LOG_DETAIL, "LWPI sets new WP = %04x\n", WP); } } @@ -2952,13 +2936,13 @@ void tms9995_device::alu_lst_lwp() if (m_command==LST) { ST = m_current_value; - if (TRACE_OP) logerror("new ST = %04x\n", ST); + LOGMASKED(LOG_DETAIL, "new ST = %04x\n", ST); pulse_clock(1); } else { WP = m_current_value & 0xfffe; - if (TRACE_OP) logerror("new WP = %04x\n", WP); + LOGMASKED(LOG_DETAIL, "new WP = %04x\n", WP); } } @@ -2976,7 +2960,7 @@ void tms9995_device::alu_mov() set_status_parity((uint8_t)(m_current_value>>8)); } compare_and_set_lae(m_current_value, 0); - if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); // No clock pulse, as next instruction is prefetch } @@ -3069,7 +3053,7 @@ void tms9995_device::alu_rtwp() // Just for debugging purposes m_log_interrupt = false; - if (TRACE_OP) logerror("RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST); + LOGMASKED(LOG_CONTEXT, "Context switch (rtwp): WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); break; } m_inst_state++; @@ -3122,7 +3106,7 @@ void tms9995_device::alu_shift() } else { - if (TRACE_DETAIL) logerror("Shift operation gets count from R0\n"); + LOGMASKED(LOG_DETAIL, "Shift operation gets count from R0\n"); } pulse_clock(1); pulse_clock(1); @@ -3167,7 +3151,7 @@ void tms9995_device::alu_shift() set_status_bit(ST_OV, overflow); compare_and_set_lae(m_current_value, 0); m_address = m_address_saved; // Register address - if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); break; } m_inst_state++; @@ -3263,7 +3247,7 @@ void tms9995_device::alu_single_arithm() m_current_value = dest_new & 0xffff; compare_and_set_lae(m_current_value, 0); - if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); // No clock pulse, as next instruction is prefetch } @@ -3301,7 +3285,7 @@ void tms9995_device::alu_stcr() m_current_value <<= 8; } else n += 8; - if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); + LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); break; } m_inst_state++; @@ -3341,7 +3325,7 @@ void tms9995_device::alu_tb() break; case 2: set_status_bit(ST_EQ, m_cru_value!=0); - if (TRACE_STATUS) logerror("ST = %04x\n", ST); + LOGMASKED(LOG_STATUS, "ST = %04x\n", ST); break; } m_inst_state++; @@ -3406,6 +3390,7 @@ void tms9995_device::alu_xop() case 6: PC = m_current_value & 0xfffe; set_status_bit(ST_X, true); + LOGMASKED(LOG_CONTEXT, "Context switch (xop): WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); break; } m_inst_state++; @@ -3424,7 +3409,7 @@ void tms9995_device::alu_int() case 0: PC = (PC - 2) & 0xfffe; m_address_saved = m_address; - if (TRACE_INTD) logerror("interrupt service (0): Prepare to read vector\n"); + LOGMASKED(LOG_INTD, "interrupt service (0): Prepare to read vector\n"); break; case 1: pulse = 2; // two cycles (with the one at the end) @@ -3432,30 +3417,30 @@ void tms9995_device::alu_int() WP = m_current_value & 0xfffe; // new WP m_current_value = ST; m_address = (WP + 30)&0xfffe; - if (TRACE_INTD) logerror("interrupt service (1): Read new WP = %04x, save ST to %04x\n", WP, m_address); + LOGMASKED(LOG_INTD, "interrupt service (1): Read new WP = %04x, save ST to %04x\n", WP, m_address); break; case 2: m_address = (WP + 28)&0xfffe; m_current_value = PC; - if (TRACE_INTD) logerror("interrupt service (2): Save PC to %04x\n", m_address); + LOGMASKED(LOG_INTD, "interrupt service (2): Save PC to %04x\n", m_address); break; case 3: m_address = (WP + 26)&0xfffe; m_current_value = m_source_value; // old WP - if (TRACE_INTD) logerror("interrupt service (3): Save WP to %04x\n", m_address); + LOGMASKED(LOG_INTD, "interrupt service (3): Save WP to %04x\n", m_address); break; case 4: m_address = (m_address_saved + 2) & 0xfffe; - if (TRACE_INTD) logerror("interrupt service (4): Read PC from %04x\n", m_address); + LOGMASKED(LOG_INTD, "interrupt service (4): Read PC from %04x\n", m_address); break; case 5: PC = m_current_value & 0xfffe; ST = (ST & 0xfe00) | m_intmask; - if (TRACE_INTD) logerror("interrupt service (5): Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); + LOGMASKED(LOG_CONTEXT, "Context switch (int): WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); if (((m_int_pending & PENDING_MID)!=0) && m_nmi_active) { - if (TRACE_INTD) logerror("interrupt service (6): NMI active after context switch\n"); + LOGMASKED(LOG_INTD, "interrupt service (6): NMI active after context switch\n"); m_int_pending &= ~PENDING_MID; m_address = 0xfffc; m_intmask = 0; @@ -3465,7 +3450,7 @@ void tms9995_device::alu_int() { if (m_from_reset) { - if (TRACE_INTD) logerror("interrupt service (6): RESET completed\n"); + LOGMASKED(LOG_INTD, "interrupt service (6): RESET completed\n"); // We came from the RESET interrupt m_from_reset = false; ST &= 0x01ff; |