rtpc: wip, now able to boot from vrm floppy

* rtpc: improve keyboard/locator/speaker adapter emulation
* romp: fully decode memory and i/o access from processor channel
* iocc: use emumem flags for isa bus i/o width detection
* iocc: correct isa bus access endianness
* iocc: internalize tcw and csr
This commit is contained in:
Patrick Mackinlay 2023-01-06 13:30:23 +07:00
parent e28f20b2d5
commit 07c20e3faf
8 changed files with 478 additions and 323 deletions

View File

@ -15,7 +15,7 @@
* set and scan codes are very similar to a PC keyboard (scan code "set 3").
*
* Sources:
* - http://bitsavers.org/pdf/ibm/pc/rt/6489893_RT_PC_Technical_Reference_Volume_1_Nov85.pdf
* - IBM RT PC Hardware Technical Reference Volume I, 75X0232, March 1987
*
* Key switches are addressed using an 8 bit code as follows:
*
@ -55,7 +55,7 @@
//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(RTPC_KBD, rtpc_kbd_device, "rtpc_kbd", "IBM PC RT Keyboard")
DEFINE_DEVICE_TYPE(RTPC_KBD, rtpc_kbd_device, "rtpc_kbd", "IBM RT PC Keyboard")
rtpc_kbd_device::rtpc_kbd_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, RTPC_KBD, tag, owner, clock)

View File

@ -5,7 +5,7 @@
* IBM Research and Office Products Division Microprocessor (ROMP).
*
* Sources:
* - http://bitsavers.org/pdf/ibm/pc/rt/75X0232_RT_PC_Technical_Reference_Volume_1_Jun87.pdf
* - IBM RT PC Hardware Technical Reference Volume I, 75X0232, March 1987
*
* TODO:
* - configurable storage channel
@ -322,7 +322,7 @@ void romp_device::execute_run()
m_icount -= 4;
break;
case 0xcb: // ior: input/output read
if (((r3 + i) & 0xff00'0000U) || !m_mmu->ior(r3 + i, m_gpr[R2]))
if (((r3 + i) & 0xff00'0000U) || !m_mmu->pio_load(r3 + i, m_gpr[R2]))
program_check(PCS_PCK | PCS_DAE);
break;
case 0xcc: // ti: trap on condition immediate
@ -433,7 +433,7 @@ void romp_device::execute_run()
m_icount -= 4;
break;
case 0xdb: // iow: input/output write
if (((r3 + i) & 0xff00'0000U) || !m_mmu->iow(r3 + i, m_gpr[R2]))
if (((r3 + i) & 0xff00'0000U) || !m_mmu->pio_store(r3 + i, m_gpr[R2]))
program_check(PCS_PCK | PCS_DAE);
m_icount--;
break;

View File

@ -166,7 +166,7 @@ private:
switch (address >> 28)
{
default:
if (m_mmu->load(address, data, mode))
if (m_mmu->mem_load(address, data, mode))
f(data);
else
program_check(PCS_PCK | PCS_DAE);
@ -176,8 +176,13 @@ private:
switch (address >> 24)
{
case 0xf0:
if (m_iou->pio_load(address, data, mode))
f(data);
else
program_check(PCS_PCK | PCS_DAE);
break;
case 0xf4:
if (m_iou->load(address, data, mode))
if (m_iou->mem_load(address, data, mode))
f(data);
else
program_check(PCS_PCK | PCS_DAE);
@ -202,7 +207,7 @@ private:
switch (address >> 28)
{
default:
if (!m_mmu->store(address, data, mode))
if (!m_mmu->mem_store(address, data, mode))
program_check(PCS_PCK | PCS_DAE);
break;
@ -210,8 +215,11 @@ private:
switch (address >> 24)
{
case 0xf0:
if (!m_iou->pio_store(address, data, mode))
program_check(PCS_PCK | PCS_DAE);
break;
case 0xf4:
if (!m_iou->store(address, data, mode))
if (!m_iou->mem_store(address, data, mode))
program_check(PCS_PCK | PCS_DAE);
break;
@ -234,7 +242,7 @@ private:
switch (address >> 28)
{
default:
if (!m_mmu->modify(address, f, mode))
if (!m_mmu->mem_modify(address, f, mode))
program_check(PCS_PCK | PCS_DAE);
break;
@ -242,8 +250,11 @@ private:
switch (address >> 24)
{
case 0xf0:
if (!m_iou->pio_modify(address, f, mode))
program_check(PCS_PCK | PCS_DAE);
break;
case 0xf4:
if (!m_iou->modify(address, f, mode))
if (!m_iou->mem_modify(address, f, mode))
program_check(PCS_PCK | PCS_DAE);
break;

View File

@ -37,17 +37,29 @@ public:
RSC_PUT = 7,
};
virtual bool load(u32 address, u8 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool load(u32 address, u16 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool load(u32 address, u32 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool mem_load(u32 address, u8 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool mem_load(u32 address, u16 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool mem_load(u32 address, u32 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool store(u32 address, u8 data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool store(u32 address, u16 data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool store(u32 address, u32 data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool mem_store(u32 address, u8 data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool mem_store(u32 address, u16 data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool mem_store(u32 address, u32 data, rsc_mode const mode = RSC_N, bool sp = false) = 0;
virtual bool modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode = RSC_N) = 0;
virtual bool modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode = RSC_N) = 0;
virtual bool modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode = RSC_N) = 0;
virtual bool mem_modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode = RSC_N) = 0;
virtual bool mem_modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode = RSC_N) = 0;
virtual bool mem_modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_load(u32 address, u8 &data, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_load(u32 address, u16 &data, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_load(u32 address, u32 &data, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_store(u32 address, u8 data, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_store(u32 address, u16 data, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_store(u32 address, u32 data, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode = RSC_N) = 0;
virtual bool pio_modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode = RSC_N) = 0;
protected:
rsc_bus_interface(machine_config const &mconfig, device_t &device, char const *type)
@ -69,17 +81,14 @@ public:
// cpu interface
virtual bool fetch(u32 address, u16 &data, rsc_mode const mode = RSC_N) = 0;
virtual bool ior(u32 address, u32 &data) = 0;
virtual bool iow(u32 address, u32 data) = 0;
// rsc_bus_interface overrides
virtual bool load(u32 address, u8 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool load(u32 address, u16 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool load(u32 address, u32 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool mem_load(u32 address, u8 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool mem_load(u32 address, u16 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool mem_load(u32 address, u32 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool store(u32 address, u8 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool store(u32 address, u16 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool store(u32 address, u32 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool mem_store(u32 address, u8 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool mem_store(u32 address, u16 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
virtual bool mem_store(u32 address, u32 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0;
};
#endif // MAME_CPU_ROMP_RSC_H

View File

@ -36,19 +36,27 @@ public:
// rsc_cpu_interface overrides
virtual bool fetch(u32 address, u16 &data, rsc_mode const mode) override;
virtual bool ior(u32 address, u32 &data) override;
virtual bool iow(u32 address, u32 data) override;
// rsc_bus_interface overrides
virtual bool load(u32 address, u8 &data, rsc_mode const mode, bool sp) override { return load<u8>(address, data, mode, sp); }
virtual bool load(u32 address, u16 &data, rsc_mode const mode, bool sp) override { return load<u16>(address, data, mode, sp); }
virtual bool load(u32 address, u32 &data, rsc_mode const mode, bool sp) override { return load<u32>(address, data, mode, sp); }
virtual bool store(u32 address, u8 data, rsc_mode const mode, bool sp) override { return store<u8>(address, data, mode, sp); }
virtual bool store(u32 address, u16 data, rsc_mode const mode, bool sp) override { return store<u16>(address, data, mode, sp); }
virtual bool store(u32 address, u32 data, rsc_mode const mode, bool sp) override { return store<u32>(address, data, mode, sp); }
virtual bool modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode) override { return modify<u8>(address, f, mode); }
virtual bool modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode) override { return modify<u16>(address, f, mode); }
virtual bool modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode) override { return modify<u32>(address, f, mode); }
virtual bool mem_load(u32 address, u8 &data, rsc_mode const mode, bool sp) override { return load<u8>(address, data, mode, sp); }
virtual bool mem_load(u32 address, u16 &data, rsc_mode const mode, bool sp) override { return load<u16>(address, data, mode, sp); }
virtual bool mem_load(u32 address, u32 &data, rsc_mode const mode, bool sp) override { return load<u32>(address, data, mode, sp); }
virtual bool mem_store(u32 address, u8 data, rsc_mode const mode, bool sp) override { return store<u8>(address, data, mode, sp); }
virtual bool mem_store(u32 address, u16 data, rsc_mode const mode, bool sp) override { return store<u16>(address, data, mode, sp); }
virtual bool mem_store(u32 address, u32 data, rsc_mode const mode, bool sp) override { return store<u32>(address, data, mode, sp); }
virtual bool mem_modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode) override { return modify<u8>(address, f, mode); }
virtual bool mem_modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode) override { return modify<u16>(address, f, mode); }
virtual bool mem_modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode) override { return modify<u32>(address, f, mode); }
virtual bool pio_load(u32 address, u8 &data, rsc_mode const mode) override { return false; }
virtual bool pio_load(u32 address, u16 &data, rsc_mode const mode) override { return false; }
virtual bool pio_load(u32 address, u32 &data, rsc_mode const mode) override { return ior(address, data); }
virtual bool pio_store(u32 address, u8 data, rsc_mode const mode) override { return false; }
virtual bool pio_store(u32 address, u16 data, rsc_mode const mode) override { return false; }
virtual bool pio_store(u32 address, u32 data, rsc_mode const mode) override { return iow(address, data); }
virtual bool pio_modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode) override { return false; }
virtual bool pio_modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode) override { return false; }
virtual bool pio_modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode) override { return false; }
protected:
// device_t overrides
@ -64,6 +72,8 @@ protected:
template <typename T> bool load(u32 address, T &data, rsc_mode const mode, bool sp);
template <typename T> bool store(u32 address, T data, rsc_mode const mode, bool sp);
template <typename T> bool modify(u32 address, std::function<T(T)> f, rsc_mode const mode);
bool ior(u32 address, u32 &data);
bool iow(u32 address, u32 data);
// register read handlers
u32 segment_r(offs_t offset);

View File

@ -5,7 +5,7 @@
* IBM RT PC.
*
* Sources:
* - http://bitsavers.org/pdf/ibm/pc/rt/75X0232_RT_PC_Technical_Reference_Volume_1_Jun87.pdf
* - IBM RT PC Hardware Technical Reference Volume I, 75X0232, March 1987
* - http://www.cs.cmu.edu/afs/andrew.cmu.edu/usr/shadow/www/ibmrt.html
* - http://ps-2.kev009.com/ohlandl/6152/rt_index.html
*
@ -68,9 +68,8 @@
* https://ardent-tool.com/615x/rt_loadable_post.html
*
* WIP
* - diagnostic disk 1 fails with alternating code a6/13
* exception at 0x16824: lcs r2,0x4(r9) # r9=40435c9c
* - aix vrm disk 1 fails with alternating code a6/13
* - boots to vrm install disk menu
* - requires improved hard disk controller emulation
*/
#include "emu.h"
@ -94,7 +93,6 @@
#include "bus/isa/isa_cards.h"
#include "bus/isa/mda.h"
#include "bus/isa/fdc.h"
#include "bus/isa/ide.h"
// busses and connectors
#include "bus/rs232/rs232.h"
@ -110,7 +108,7 @@
#define LOG_GENERAL (1U << 0)
#define LOG_KLS (1U << 1)
//#define VERBOSE (LOG_GENERAL)
//#define VERBOSE (LOG_GENERAL|LOG_KLS)
#include "logmacro.h"
#include "debugger.h"
@ -152,23 +150,24 @@ protected:
void iocc_mem_map(address_map &map) { map.unmap_value_high(); }
template <bool SCC> void iocc_pio_map(address_map &map);
void mcu_pgm_map(address_map &map);
void common(machine_config &config);
void kls_cmd_w(u16 data);
void mcu_port1_w(u8 data);
void mcu_port2_w(u8 data);
void mcu_port3_w(u8 data);
void ppi_portc_w(u8 data);
void kls_cmd_w(offs_t offset, u16 data, u16 mem_mask);
void crra_w(u8 data);
void crrb_w(u8 data);
void dia_w(u8 data);
void mcu_timer(timer_device &timer, s32 param)
{
m_mcu_p3 ^= 0x10;
m_mcu->set_input_line(MCS51_T0_LINE, BIT(m_mcu_p3, 4));
m_mcu->set_input_line(MCS51_T0_LINE, 1);
m_mcu->set_input_line(MCS51_T0_LINE, 0);
}
void speaker()
@ -195,13 +194,17 @@ protected:
required_region_ptr<u32> m_ipl;
u8 m_mcu_p0 = 0;
u8 m_mcu_p1 = 0;
u8 m_mcu_p2 = 0;
u8 m_mcu_p3 = 0;
u8 m_kls_cmd;
u8 m_ppi_pb = 0;
u8 m_mcu_uart = 0;
u8 m_mcu_p0;
u8 m_mcu_p1;
u8 m_mcu_p2;
u8 m_mcu_p3;
u8 m_mcu_uart;
u8 m_ppi_pa;
u8 m_ppi_pb;
u8 m_ppi_pc;
u8 m_ch8er = 0; // dma channel 8 enable register
u8 m_crra = 0; // component reset register a
@ -214,12 +217,17 @@ static double const speaker_levels[4] = { 0.0, 1.0 / 3.0, 2.0 / 3.0, 1.0 };
void rtpc_state::machine_start()
{
m_kls_cmd = 0;
m_mcu_p0 = 0;
m_mcu_p1 = 0;
m_mcu_p2 = 0;
m_mcu_p3 = 0;
m_mcu_uart = 0;
m_ppi_pa = 0;
m_ppi_pb = 0;
m_ppi_pc = 0;
m_crra = 0xff;
m_crrb = 0xff;
@ -250,12 +258,12 @@ template <bool SCC> void rtpc_state::iocc_pio_map(address_map &map)
// delay 1µs per byte written
map(0x00'80e0, 0x00'80e3).lw8([this](u8 data) { m_cpu->eat_cycles(m_cpu->clock() / 1000000 + 1); }, "io_delay");
map(0x00'8400, 0x00'8403).mirror(0x7c).rw(m_ppi, FUNC(i8255_device::read), FUNC(i8255_device::write));
map(0x00'8400, 0x00'8401).mirror(0x78).w(FUNC(rtpc_state::kls_cmd_w));
map(0x00'8400, 0x00'8401).w(FUNC(rtpc_state::kls_cmd_w)).flags(rtpc_iocc_device::PIO_W);
map(0x00'8404, 0x00'8407).rw(m_ppi, FUNC(i8255_device::read), FUNC(i8255_device::write));
map(0x00'8800, 0x00'883f).rw(m_rtc, FUNC(mc146818_device::read_direct), FUNC(mc146818_device::write_direct));
map(0x00'8840, 0x00'884f).mirror(0x10).rw(m_dma[0], FUNC(am9517a_device::read), FUNC(am9517a_device::write));
map(0x00'8860, 0x00'887f).umask16(0xff00).rw(m_dma[1], FUNC(am9517a_device::read), FUNC(am9517a_device::write));
map(0x00'8860, 0x00'887f).umask16(0x00ff).rw(m_dma[1], FUNC(am9517a_device::read), FUNC(am9517a_device::write));
map(0x00'8880, 0x00'8881).mirror(0x1e).rw(m_pic[0], FUNC(pic8259_device::read), FUNC(pic8259_device::write));
map(0x00'88a0, 0x00'88a1).mirror(0x1e).rw(m_pic[1], FUNC(pic8259_device::read), FUNC(pic8259_device::write));
map(0x00'88c0, 0x00'88c0).mirror(0x1f).rw(m_iocc, FUNC(rtpc_iocc_device::dbr_r), FUNC(rtpc_iocc_device::dbr_w));
@ -275,10 +283,12 @@ template <bool SCC> void rtpc_state::iocc_pio_map(address_map &map)
// 8c82 diag dma mode?
// 8c84 diag dma exit?
map(0x00'8ce0, 0x00'8ce1).nopw(); // FIXME: hex display register?
}
map(0x01'0000, 0x01'07ff).rw(m_iocc, FUNC(rtpc_iocc_device::tcw_r), FUNC(rtpc_iocc_device::tcw_w));
map(0x01'0800, 0x01'0801).mirror(0x7fc).rw(m_iocc, FUNC(rtpc_iocc_device::csr_r<1>), FUNC(rtpc_iocc_device::csr_w));
map(0x01'0802, 0x01'0803).mirror(0x7fc).rw(m_iocc, FUNC(rtpc_iocc_device::csr_r<0>), FUNC(rtpc_iocc_device::csr_w));
void rtpc_state::mcu_pgm_map(address_map &map)
{
map(0x0000, 0x0fff).rom().region("mcu", 0);
map(0xf800, 0xffff).lr8([this]() { m_cpu->pulse_input_line(INPUT_LINE_IRQ0, attotime::from_msec(1)); return 0; }, "sys_atn");
}
void rtpc_state::mcu_port1_w(u8 data)
@ -286,7 +296,7 @@ void rtpc_state::mcu_port1_w(u8 data)
// bit function
// 6 speaker volume 0
// 7 speaker volume 1
LOGMASKED(LOG_KLS, "mcu_port1_w volume %d\n", data >> 6);
LOGMASKED(LOG_KLS, "kls volume %d\n", data >> 6);
m_mcu_p1 = (m_mcu_p1 & 0x3f) | (data & 0xc0);
// speaker volume wraps to ppi port b.6 and b.5
@ -298,41 +308,57 @@ void rtpc_state::mcu_port1_w(u8 data)
void rtpc_state::mcu_port2_w(u8 data)
{
// bit dst
// 0 ppi port c.0 (iid0)
// 1 ppi port c.1 (iid1)
// 2 ppi port c.2 (iid2)
// 3 i/o channel system reset (active low)
// 4 ppi port c.4
// 5 (input)
// 6 ppi port c.6 (-ack)
// 7 speaker frequency
// interrupts
// 0 informational
// 1 received byte from keyboard
// 2 received byte from uart
// 3 returning byte requested by system
// 4 block transfer ready
// 5 unassigned
// 6 self-test performed
// 7 error condition
// bit i/o function
// 0 o ppi port c.0 (iid0)
// 1 o ppi port c.1 (iid1)
// 2 o ppi port c.2 (iid2)
// 3 o i/o channel system reset (active low)
// 4 o ppi port c.4 (-stb)
// 5 i ppi port c.5 (ibf)
// 6 o ppi port c.6 (-ack)
// 7 o speaker frequency
if ((data ^ m_mcu_p2) & 7)
LOGMASKED(LOG_KLS, "mcu_port2_w interrupt %d\n", data & 7);
{
static const char *const mcu_code[] =
{
"informational", "received byte from keyboard", "received byte from uart", "returning byte requested by system",
"block transfer ready", "unassigned", "self-test performed", "error condition"
};
LOGMASKED(LOG_KLS, "kls mcu iid %d: %s\n", data & 7, mcu_code[data & 7]);
}
if ((data ^ m_mcu_p2) & 8)
LOGMASKED(LOG_KLS, "mcu_port2_w system reset %d\n", data & 8);
LOGMASKED(LOG_KLS, "kls mcu system reset %d\n", BIT(data, 3));
m_ppi->pc4_w(BIT(data, 4));
m_ppi->pc6_w(BIT(data, 6));
if ((data ^ m_mcu_p2) & 0x10)
{
if (!BIT(data, 4))
{
LOGMASKED(LOG_KLS, "kls mcu data out 0x%02x\n", m_mcu_p0);
m_ppi_pa = m_mcu_p0;
}
m_ppi->pc4_w(BIT(data, 4));
}
m_mcu_p2 &= ~0xdf;
m_mcu_p2 |= data & 0xdf;
if ((data ^ m_mcu_p2) & 0x40)
{
m_ppi->pc6_w(BIT(data, 6));
if (!BIT(data, 6))
{
LOGMASKED(LOG_KLS, "kls mcu data in 0x%02x\n", m_ppi_pa);
m_mcu_p0 = m_ppi_pa;
}
}
m_mcu_p2 = (m_mcu_p2 & ~0xdf) | (data & 0xdf);
// speaker frequency wraps to ppi port b.7
m_ppi_pb &= ~0x80;
m_ppi_pb |= ~data & 0x80;
m_ppi_pb = (m_ppi_pb & ~0x80) | (~data & 0x80);
// iid, ack, stb map to ppi port c
m_ppi_pc = (m_ppi_pc & ~0x57) | (data & 0x57);
speaker();
}
@ -342,60 +368,98 @@ void rtpc_state::mcu_port3_w(u8 data)
// bit i/o function
// 0 i uart rx
// 1 o uart tx
// 2 i kbd clock in
// 3 i obf/int1
// 4 i 32 kHz
// 2 i kbd clock in (-int0)
// 3 i ppi -obf (-int1)
// 4 i 32 kHz (t0)
// 5 i kbd data in
// 6 o kbd data out
// 7 o kbd clock out
LOGMASKED(LOG_KLS, "mcu_port3_w 0x%02x\n", data);
m_kbd_con->data_write_from_mb(BIT(data, 6));
m_kbd_con->clock_write_from_mb(BIT(data, 7));
m_mcu_p3 = (m_mcu_p3 & ~0xc2) | (data & 0xc2);
}
/*
* bit i/o function
* 0 i iid0
* 1 i iid1
* 2 i iid2
* 3 o +irq
* 4 i -stb
* 5 o ibf
* 6 i -ack
* 7 o -obf
*/
void rtpc_state::ppi_portc_w(u8 data)
{
LOGMASKED(LOG_KLS, "ppi_portc_w 0x%02x\n", data);
// bit 3 -> i/o channel (irq)
m_pic[0]->ir5_w(BIT(data, 3));
// bit 3 (+irq) -> i/o channel
if (BIT(m_ppi_pc ^ data, 3))
{
LOGMASKED(LOG_KLS, "kls host irq %d\n", BIT(data, 3));
m_pic[0]->ir5_w(BIT(data, 3));
}
// bit 5 -> mcu p2.5 (ibf)
if (BIT(data, 5))
m_mcu_p2 |= 0x20;
else
m_mcu_p2 &= ~0x20;
// bit 5 (+ibf) -> mcu p2.5
if (BIT(m_ppi_pc ^ data, 5))
{
if (BIT(data, 5))
m_mcu_p2 |= 0x20;
else
m_mcu_p2 &= ~0x20;
}
// bit 7 -> mcu p3.3(-int1) (-obf)
if (BIT(data, 7))
m_mcu_p3 |= 0x08;
else
m_mcu_p3 &= ~0x08;
m_mcu->set_input_line(MCS51_INT1_LINE, !BIT(data, 7));
// bit 7 (-obf) -> mcu p3.3 (-int1)
if (BIT(m_ppi_pc ^ data, 7))
m_mcu->set_input_line(MCS51_INT1_LINE, !BIT(data, 7));
m_ppi_pc = (m_ppi_pc & ~0xa8) | (data & 0xa8);
}
void rtpc_state::kls_cmd_w(offs_t offset, u16 data, u16 mem_mask)
void rtpc_state::kls_cmd_w(u16 data)
{
LOGMASKED(LOG_KLS, "kls_cmd_w command 0x%02x data 0x%02x mask 0x%04x\n", u8(data), data >> 8, mem_mask);
LOGMASKED(LOG_KLS, "kls command 0x%02x data 0x%02x (%s)\n", data >> 8, u8(data), machine().describe_context());
// 00cc cccc dddd dddd
switch (mem_mask)
m_kls_cmd = BIT(data, 8, 6);
switch (m_kls_cmd & 0x1f)
{
case 0xff00:
m_ppi->write(0, data);
case 0x0: // extended command
switch (u8(data))
{
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
LOGMASKED(LOG_KLS, "clr mode bit %d\n", data & 0xf); break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
LOGMASKED(LOG_KLS, "set mode bit %d\n", data & 0xf); break;
default: LOGMASKED(LOG_KLS, "extended command 0x%02x\n", data); break;
}
break;
case 0x00ff:
m_ppi->write(1, data);
case 0x1: LOGMASKED(LOG_KLS, "write keyboard 0x%02x\n", data); break;
case 0x2: LOGMASKED(LOG_KLS, "write speaker 0x%02x\n", data); break;
case 0x3: LOGMASKED(LOG_KLS, "write uart control 0x%02x\n", data); break;
case 0x4: LOGMASKED(LOG_KLS, "write uart query 0x%02x\n", data); break;
case 0x5: LOGMASKED(LOG_KLS, "set uart rate 0x%02x\n", data); break;
case 0x6: LOGMASKED(LOG_KLS, "init uart 0x%02x\n", data); break;
case 0x7: LOGMASKED(LOG_KLS, "set speaker duration 0x%02x\n", data); break;
case 0x8: LOGMASKED(LOG_KLS, "set speaker freq-hi 0x%02x\n", data); break;
case 0x9: LOGMASKED(LOG_KLS, "set speaker freq-lo 0x%02x\n", data); break;
case 0xc: LOGMASKED(LOG_KLS, "diagnostic write 0x%02x\n", data); break;
case 0xa: case 0xb: case 0xd: case 0xe: case 0xf:
LOGMASKED(LOG_KLS, "unassigned\n");
break;
case 0xffff:
m_mcu_p1 = (m_mcu_p1 & ~0x3f) | (data & 0x3f);
m_ppi->write(0, data >> 8);
default:
LOGMASKED(LOG_KLS, "write shared ram addr 0x%x data 0x%02x\n", m_kls_cmd & 0xf, data);
break;
}
m_mcu_p1 = (m_mcu_p1 & 0xe0) | (m_kls_cmd & 0x1f);
m_ppi->write(0, data);
}
void rtpc_state::crra_w(u8 data)
@ -417,7 +481,7 @@ void rtpc_state::crra_w(u8 data)
void rtpc_state::crrb_w(u8 data)
{
LOG("crrb_w 0x%02x\n", data);
LOG("crrb_w 0x%02x (%s)\n", data, machine().describe_context());
// bit function
// 0 8530
@ -431,8 +495,11 @@ void rtpc_state::crrb_w(u8 data)
if (m_scc && BIT(data, 0))
m_scc->reset();
// TODO: rs232 if
m_mcu->set_input_line(INPUT_LINE_RESET, !BIT(data, 2));
// TODO: dmac !ready
// TODO: arbitor
@ -466,6 +533,17 @@ void rtpc_state::dia_w(u8 data)
void rtpc_state::common(machine_config &config)
{
/*
* irq source
* 0 mcu system attention
* 1 rtc interrupt
* 2 mmu program check, iocc error
* 3 pic 0 interrupt
* 4 pic 1 interrupt
* 5 (not connected, software interrupt?)
* 6 (not connected, software interrupt?)
* nmi mmu machine check, early power off
*/
ROMP(config, m_cpu, 23'529'400 / 4);
m_cpu->set_mmu(m_mmu);
m_cpu->set_iou(m_iocc);
@ -491,27 +569,27 @@ void rtpc_state::common(machine_config &config)
// (c)IBM 1986
// (c)INTEL '80
I8051(config, m_mcu, 9.216_MHz_XTAL);
m_mcu->port_in_cb<0>().set([this]() { return m_ppi->pa_r(); });
m_mcu->set_addrmap(AS_PROGRAM, &rtpc_state::mcu_pgm_map);
m_mcu->port_in_cb<0>().set([this]() { return m_mcu_p0; });
m_mcu->port_out_cb<0>().set([this](u8 data) { m_mcu_p0 = data; });
m_mcu->port_in_cb<1>().set([this]() { return m_mcu_p1 & 0x1f; });
m_mcu->port_in_cb<1>().set([this]() { return m_mcu_p1 | 0xc0; });
m_mcu->port_out_cb<1>().set(FUNC(rtpc_state::mcu_port1_w));
m_mcu->port_in_cb<2>().set([this]() { return m_mcu_p2; });
m_mcu->port_in_cb<2>().set([this]() { return m_mcu_p2 | 0xdf; });
m_mcu->port_out_cb<2>().set(FUNC(rtpc_state::mcu_port2_w));
m_mcu->port_in_cb<3>().set([this]() { return m_mcu_p3 | 0xce; });
m_mcu->port_out_cb<3>().set(FUNC(rtpc_state::mcu_port3_w));
m_mcu->port_in_cb<3>().set([this]() { return m_mcu_p3 & 0x3d; });
m_mcu->serial_tx_cb().set(
[this](u8 data)
{
if (BIT(m_mcu_p1, 5))
if (BIT(m_kls_cmd, 5))
{
m_mcu_uart = data;
m_mcu->set_input_line(MCS51_RX_LINE, 1);
}
else
logerror("uart tx 0x%02x\n", data);
LOGMASKED(LOG_KLS, "kls uart tx 0x%02x\n", data);
});
m_mcu->serial_rx_cb().set([this]() { return m_mcu_uart; });
//m_mcu->out_?().set_inputline(m_cpu, INPUT_LINE_IRQ0);
TIMER(config, "mcu_timer").configure_periodic(FUNC(rtpc_state::mcu_timer), attotime::from_hz(32768));
@ -637,28 +715,21 @@ void rtpc_state::common(machine_config &config)
// port C lower: input
// port C upper: 8051 handshake
// port C & 0x20 -> irq
m_ppi->in_pa_callback().set([this]() { return m_mcu_p0; });
m_ppi->out_pa_callback().set([this](u8 data) { m_ppi_pa = data; });
m_ppi->in_pa_callback().set([this]() { return m_ppi_pa; });
// TODO: bits 4-1 "non-adapter system board signals"
// TODO: bit 0 "uart rxd signal"
m_ppi->in_pb_callback().set([this]() { return m_ppi_pb; });
m_ppi->out_pc_callback().set(FUNC(rtpc_state::ppi_portc_w));
m_ppi->in_pc_callback().set([this]() { return m_mcu_p2 & 0x57; });
m_ppi->in_pc_callback().set([this]() { return m_ppi_pc; });
RTPC_KBD_CON(config, m_kbd_con);
m_kbd_con->option_add("kbd", RTPC_KBD);
m_kbd_con->set_default_option("kbd");
m_kbd_con->out_data_cb().set([this](int state) { if (state) m_mcu_p3 |= 0x20; else m_mcu_p3 &= ~0x20; });
m_kbd_con->out_clock_cb().set(
[this](int state)
{
if (state)
m_mcu_p3 |= 0x04;
else
m_mcu_p3 &= ~0x04;
m_mcu->set_input_line(MCS51_INT0_LINE, !state);
});
m_kbd_con->out_clock_cb().set_inputline(m_mcu, MCS51_INT0_LINE).invert();
// MC146818AP
// IL 0A46D8729
@ -693,7 +764,6 @@ void rtpc_isa8_cards(device_slot_interface &device)
void rtpc_isa16_cards(device_slot_interface &device)
{
// FIXME: need 16-bit combined hdc/fdc card
device.option_add("hdc", ISA16_IDE);
device.option_add("fdc", ISA8_FDC_AT);
}

View File

@ -5,14 +5,11 @@
* IBM RT PC I/O Channel Converter/Controller
*
* Sources:
* - http://bitsavers.org/pdf/ibm/pc/rt/75X0232_RT_PC_Technical_Reference_Volume_1_Jun87.pdf
* - IBM RT PC Hardware Technical Reference Volume I, 75X0232, March 1987
*
* TODO:
* - bus spaces should be little endian
* - isa bus i/o space should be halfword addressed
* - alternate controllers, region mode dma
* - improve rsc interface
* - state saving
* - refactoring and cleanup
*/
#include "emu.h"
@ -25,14 +22,14 @@
//#define VERBOSE (LOG_GENERAL|LOG_DMA)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(RTPC_IOCC, rtpc_iocc_device, "rtpc_iocc", "RT PC I/O Channel Converter/Controller")
DEFINE_DEVICE_TYPE(RTPC_IOCC, rtpc_iocc_device, "rtpc_iocc", "IBM RT PC I/O Channel Converter/Controller")
rtpc_iocc_device::rtpc_iocc_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, RTPC_IOCC, tag, owner, clock)
, device_memory_interface(mconfig, *this)
, rsc_bus_interface(mconfig, *this)
, m_mem_config("mem", ENDIANNESS_BIG, 16, 24, 0)
, m_pio_config("pio", ENDIANNESS_BIG, 16, 24, 0)
, m_mem_config("mem", ENDIANNESS_LITTLE, 16, 24, 0)
, m_pio_config("pio", ENDIANNESS_LITTLE, 16, 24, 0)
, m_out_int(*this)
, m_out_rst(*this)
, m_rsc(*this, "^mmu")
@ -66,6 +63,9 @@ void rtpc_iocc_device::device_start()
save_item(NAME(m_tcw));
save_item(NAME(m_adc));
save_item(NAME(m_out_int_state));
space(AS_PROGRAM).specific(m_mem);
space(AS_IO).specific(m_pio);
}
void rtpc_iocc_device::device_reset()
@ -86,10 +86,10 @@ u8 rtpc_iocc_device::dma_b_r(offs_t offset)
LOGMASKED(LOG_DMA, "dma0 tcw 0x%04x real 0x%08x\n", tcw, real);
if (tcw & TCW_IOC)
data = space(AS_PROGRAM).read_byte(real);
data = m_mem.read_byte(real);
else
{
if (!m_rsc->load(real, data, RSC_N))
if (!m_rsc->mem_load(real, data, RSC_N))
{
// on dma exception
// - assert interrupt (level 2)
@ -120,9 +120,9 @@ void rtpc_iocc_device::dma_b_w(offs_t offset, u8 data)
LOGMASKED(LOG_DMA, "dma0 tcw 0x%04x real 0x%08x\n", tcw, real);
if (tcw & TCW_IOC)
space(AS_PROGRAM).write_byte(real, data);
m_mem.write_byte(real, data);
else
m_rsc->store(real, data, RSC_N);
m_rsc->mem_store(real, data, RSC_N);
}
else
fatalerror("rtpc_iocc_device::dma_b_w() invalid dma operation\n");
@ -139,9 +139,9 @@ u8 rtpc_iocc_device::dma_w_r(offs_t offset)
LOGMASKED(LOG_DMA, "dma1 tcw 0x%04x real 0x%08x\n", tcw, real);
if (tcw & TCW_IOC)
data = space(AS_PROGRAM).read_word(real);
data = swapendian_int16(m_mem.read_word(real));
else
m_rsc->load(real, data, RSC_N);
m_rsc->mem_load(real, data, RSC_N);
}
else
fatalerror("rtpc_iocc_device::dma_w_r() invalid dma operation\n");
@ -161,84 +161,45 @@ void rtpc_iocc_device::dma_w_w(offs_t offset, u8 data)
LOGMASKED(LOG_DMA, "dma1 tcw 0x%04x real 0x%08x\n", tcw, real);
// FIXME: upper data bits
if (tcw & TCW_IOC)
space(AS_PROGRAM).write_word(real, data);
m_mem.write_word(real, swapendian_int16(data));
else
m_rsc->store(real, u16(data), RSC_N);
m_rsc->mem_store(real, u16(data), RSC_N);
}
else
fatalerror("rtpc_iocc_device::dma_w_w() invalid dma operation\n");
}
template <typename T> bool rtpc_iocc_device::load(u32 address, T &data, rsc_mode const mode)
{
unsigned const s = (address >> 24) & 15 ? AS_PROGRAM : AS_IO;
if (s == AS_PROGRAM && (mode & RSC_U) && !(m_ccr & CCR_MMP))
{
LOG("load mem protection violation (%s)\n", machine().describe_context());
m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_PVIO;
return false;
}
if (s == AS_IO)
{
if ((mode & RSC_U) && (address == 0xf001'0800U || !(m_ccr & CCR_IMP)))
{
LOG("load pio protection violation (%s)\n", machine().describe_context());
m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_PVIO;
return false;
}
}
switch (sizeof(T))
{
case 1: data = space(s).read_byte(address); break;
case 2:
if (s == 2 && target_size(address) < sizeof(T))
{
LOGMASKED(LOG_WIDEPIO, "load pio w<-b 0x%08x (%s)\n", address, machine().describe_context());
data = u16(space(s).read_byte(address)) << 8;
data |= space(s).read_byte(address);
}
else
data = space(s).read_word(address);
break;
case 4:
if (s == 2 && target_size(address) < sizeof(T))
{
if (target_size(address) == 1)
{
LOGMASKED(LOG_WIDEPIO, "load pio d<-b 0x%08x (%s)\n", address, machine().describe_context());
data = u32(space(s).read_byte(address)) << 24;
data |= u32(space(s).read_byte(address)) << 16;
data |= u32(space(s).read_byte(address)) << 8;
data |= space(s).read_byte(address);
}
else
{
LOGMASKED(LOG_WIDEPIO, "load pio d<-w 0x%08x (%s)\n", address, machine().describe_context());
data = u32(space(s).read_word(address)) << 16;
data |= space(s).read_word(address);
}
}
else
data = space(s).read_dword(address);
break;
}
return true;
}
#ifdef _MSC_VER
// avoid incorrect MSVC warnings about excessive shift sizes below
#pragma warning(disable:4333)
#endif
template <typename T> bool rtpc_iocc_device::store(u32 address, T data, rsc_mode const mode)
template <typename T> bool rtpc_iocc_device::mem_load(u32 address, T &data, rsc_mode const mode)
{
unsigned const spacenum = (address >> 24) & 15 ? AS_PROGRAM : AS_IO;
if ((mode & RSC_U) && !(m_ccr & CCR_MMP))
{
LOG("load mem protection violation (%s)\n", machine().describe_context());
m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_PVIO;
return false;
}
switch (sizeof(T))
{
case 1: data = m_mem.read_byte(address); break;
case 2: data = swapendian_int16(m_mem.read_word(address)); break;
case 4:
data = swapendian_int32(m_mem.read_word(address + 0));
data |= swapendian_int16(m_mem.read_word(address + 2));
break;
}
return true;
}
template <typename T> bool rtpc_iocc_device::mem_store(u32 address, T data, rsc_mode const mode)
{
int const spacenum = (address >> 24) & 15 ? AS_PROGRAM : AS_IO;
if (spacenum == AS_PROGRAM && (mode & RSC_U) && !(m_ccr & CCR_MMP))
{
@ -255,68 +216,22 @@ template <typename T> bool rtpc_iocc_device::store(u32 address, T data, rsc_mode
return true;
}
if (spacenum == AS_IO && (mode & RSC_U))
{
if (address == 0xf001'0800U || !(m_ccr & CCR_IMP))
{
LOG("store pio protection violation (%s)\n", machine().describe_context());
m_csr |= CSR_PER | CSR_PD | CSR_PVIO;
if (mode & RSC_T)
{
m_csr |= CSR_EXR;
return false;
}
else
set_int(true);
return true;
}
}
switch (sizeof(T))
{
case 1: space(spacenum).write_byte(address, data); break;
case 2:
if (spacenum == AS_IO && target_size(address) < sizeof(T))
{
LOGMASKED(LOG_WIDEPIO, "store pio w->b 0x%08x data 0x%04x (%s)\n", address, data, machine().describe_context());
space(spacenum).write_byte(address, u8(data >> 8));
space(spacenum).write_byte(address, u8(data >> 0));
}
else
space(spacenum).write_word(address, data);
break;
case 1: m_mem.write_byte(address, data); break;
case 2: m_mem.write_word(address, swapendian_int16(data)); break;
case 4:
if (spacenum == AS_IO && target_size(address) < sizeof(T))
{
if (target_size(address) == 1)
{
LOGMASKED(LOG_WIDEPIO, "store pio d->b 0x%08x data 0x%08x (%s)\n", address, data, machine().describe_context());
space(spacenum).write_byte(address, u8(data >> 24));
space(spacenum).write_byte(address, u8(data >> 16));
space(spacenum).write_byte(address, u8(data >> 8));
space(spacenum).write_byte(address, u8(data >> 0));
}
else
{
LOGMASKED(LOG_WIDEPIO, "store pio d->w 0x%08x data 0x%08x (%s)\n", address, data, machine().describe_context());
space(spacenum).write_word(address, u16(data >> 16));
space(spacenum).write_word(address, u16(data >> 0));
}
}
else
space(spacenum).write_dword(address, data);
m_mem.write_word(address + 0, swapendian_int16(data >> 16));
m_mem.write_word(address + 2, swapendian_int16(data >> 0));
break;
}
return true;
}
template <typename T> bool rtpc_iocc_device::modify(u32 address, std::function<T(T)> f, rsc_mode const mode)
template <typename T> bool rtpc_iocc_device::mem_modify(u32 address, std::function<T(T)> f, rsc_mode const mode)
{
unsigned const spacenum = (address >> 24) & 15 ? AS_PROGRAM : AS_IO;
if (spacenum == AS_PROGRAM && (mode & RSC_U) && !(m_ccr & CCR_MMP))
if ((mode & RSC_U) && !(m_ccr & CCR_MMP))
{
LOG("modify mem protection violation (%s)\n", machine().describe_context());
m_csr |= CSR_PER | CSR_PD | CSR_PVIO;
@ -331,20 +246,161 @@ template <typename T> bool rtpc_iocc_device::modify(u32 address, std::function<T
return true;
}
if (spacenum == AS_IO)
{
LOG("modify pio space invalid operation (%s)\n", machine().describe_context());
m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_INVOP;
return false;
}
switch (sizeof(T))
{
case 1: space(spacenum).write_byte(address, f(space(spacenum).read_byte(address))); break;
case 2: space(spacenum).write_word(address, f(space(spacenum).read_word(address))); break;
case 4: space(spacenum).write_dword(address, f(space(spacenum).read_dword(address))); break;
case 1: m_mem.write_byte(address, f(m_mem.read_byte(address))); break;
case 2: m_mem.write_word(address, swapendian_int16(f(swapendian_int16(m_mem.read_word(address))))); break;
case 4:
{
T data = swapendian_int32(m_mem.read_word(address + 0));
data |= swapendian_int16(m_mem.read_word(address + 2));
data = f(data);
m_mem.write_word(address + 0, swapendian_int16(data >> 16));
m_mem.write_word(address + 2, swapendian_int16(data >> 0));
}
break;
}
return true;
}
template <typename T> bool rtpc_iocc_device::pio_load(u32 address, T &data, rsc_mode const mode)
{
if ((mode & RSC_U) && (address == CSR_ADDR || !(m_ccr & CCR_IMP)))
{
LOG("load pio protection violation (%s)\n", machine().describe_context());
m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_PVIO;
return false;
}
else if ((address & REG_MASK) == CSR_ADDR)
{
data = m_csr | CSR_RSV;
return true;
}
else if ((address & REG_MASK) == TCW_BASE)
{
// the multiply creates a halfword smear needed to pass POST
data = m_tcw[(address & ~REG_MASK) >> 1] * 0x0001'0001U;
return true;
}
switch (sizeof(T))
{
case 1: data = m_pio.read_byte(address); break;
case 2:
switch (m_pio.lookup_read_word_flags(address) & PIO_SIZE)
{
case PIO_B:
data = swapendian_int16(m_pio.read_byte(address));
data |= m_pio.read_byte(address);
LOGMASKED(LOG_WIDEPIO, "load pio w<-b 0x%08x data 0x%04x (%s)\n", address, data, machine().describe_context());
break;
case PIO_W:
data = swapendian_int16(m_pio.read_word(address));
break;
}
break;
case 4:
switch (m_pio.lookup_read_dword_flags(address) & PIO_SIZE)
{
case PIO_B:
data = u32(m_pio.read_byte(address)) << 24;
data |= u32(m_pio.read_byte(address)) << 16;
data |= u32(m_pio.read_byte(address)) << 8;
data |= u32(m_pio.read_byte(address)) << 0;
LOGMASKED(LOG_WIDEPIO, "load pio d<-b 0x%08x data 0x%08x (%s)\n", address, data, machine().describe_context());
break;
case PIO_W:
data = swapendian_int32(m_pio.read_word(address));
data |= swapendian_int16(m_pio.read_word(address));
LOGMASKED(LOG_WIDEPIO, "load pio d<-w 0x%08x data 0x%08x(%s)\n", address, data, machine().describe_context());
break;
}
break;
}
return true;
}
template <typename T> bool rtpc_iocc_device::pio_store(u32 address, T data, rsc_mode const mode)
{
if ((mode & RSC_U) && (address == CSR_ADDR || !(m_ccr & CCR_IMP)))
{
LOG("store pio protection violation (%s)\n", machine().describe_context());
m_csr |= CSR_PER | CSR_PD | CSR_PVIO;
if (mode & RSC_T)
{
m_csr |= CSR_EXR;
return false;
}
else
set_int(true);
return true;
}
else if ((address & REG_MASK) == CSR_ADDR)
{
m_csr = 0;
set_int(false);
return true;
}
else if ((address & REG_MASK) == TCW_BASE)
{
m_tcw[(address & ~REG_MASK) >> 1] = data;
return true;
}
switch (sizeof(T))
{
case 1: m_pio.write_byte(address, data); break;
case 2:
switch (m_pio.lookup_write_word_flags(address) & PIO_SIZE)
{
case PIO_B:
LOGMASKED(LOG_WIDEPIO, "store pio w->b 0x%08x data 0x%04x (%s)\n", address, data, machine().describe_context());
m_pio.write_byte(address, data >> 8);
m_pio.write_byte(address, data >> 0);
break;
case PIO_W:
m_pio.write_word(address, swapendian_int16(data));
break;
}
break;
case 4:
switch (m_pio.lookup_write_dword_flags(address) & PIO_SIZE)
{
case PIO_B:
// HACK: suppress excessive logging from frequent delay register word writes
if (address != 0xf000'80e0U)
LOGMASKED(LOG_WIDEPIO, "store pio d->b 0x%08x data 0x%08x (%s)\n", address, data, machine().describe_context());
m_pio.write_byte(address, data >> 24);
m_pio.write_byte(address, data >> 16);
m_pio.write_byte(address, data >> 8);
m_pio.write_byte(address, data >> 0);
break;
case PIO_W:
LOGMASKED(LOG_WIDEPIO, "store pio d->w 0x%08x data 0x%08x (%s)\n", address, data, machine().describe_context());
m_pio.write_word(address, swapendian_int16(data >> 16));
m_pio.write_word(address, swapendian_int16(data >> 0));
break;
}
break;
}
return true;
}
template <typename T> bool rtpc_iocc_device::pio_modify(u32 address, std::function<T(T)> f, rsc_mode const mode)
{
LOG("modify pio space invalid operation (%s)\n", machine().describe_context());
m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_INVOP;
return false;
}

View File

@ -19,6 +19,14 @@ public:
auto out_int() { return m_out_int.bind(); }
auto out_rst() { return m_out_rst.bind(); }
enum pio_flags : u16
{
PIO_B = 0x0000,
PIO_W = 0x0001,
PIO_SIZE = 0x0001,
};
enum ccr_mask : u8
{
CCR_RFE = 0x02, // refresh enable
@ -67,23 +75,30 @@ public:
using rsc_mode = rsc_bus_interface::rsc_mode;
// rsc_pio_interface overrides
virtual bool load(u32 address, u8 &data, rsc_mode const mode, bool sp) override { return load<u8>(address, data, mode); }
virtual bool load(u32 address, u16 &data, rsc_mode const mode, bool sp) override { return load<u16>(address, data, mode); }
virtual bool load(u32 address, u32 &data, rsc_mode const mode, bool sp) override { return load<u32>(address, data, mode); }
virtual bool store(u32 address, u8 data, rsc_mode const mode, bool sp) override { return store<u8>(address, data, mode); }
virtual bool store(u32 address, u16 data, rsc_mode const mode, bool sp) override { return store<u16>(address, data, mode); }
virtual bool store(u32 address, u32 data, rsc_mode const mode, bool sp) override { return store<u32>(address, data, mode); }
virtual bool modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode) override { return modify<u8>(address, f, mode); }
virtual bool modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode) override { return modify<u16>(address, f, mode); }
virtual bool modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode) override { return modify<u32>(address, f, mode); }
// rsc_bus_interface overrides
virtual bool mem_load(u32 address, u8 &data, rsc_mode const mode, bool sp) override { return mem_load<u8>(address, data, mode); }
virtual bool mem_load(u32 address, u16 &data, rsc_mode const mode, bool sp) override { return mem_load<u16>(address, data, mode); }
virtual bool mem_load(u32 address, u32 &data, rsc_mode const mode, bool sp) override { return mem_load<u32>(address, data, mode); }
virtual bool mem_store(u32 address, u8 data, rsc_mode const mode, bool sp) override { return mem_store<u8>(address, data, mode); }
virtual bool mem_store(u32 address, u16 data, rsc_mode const mode, bool sp) override { return mem_store<u16>(address, data, mode); }
virtual bool mem_store(u32 address, u32 data, rsc_mode const mode, bool sp) override { return mem_store<u32>(address, data, mode); }
virtual bool mem_modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode) override { return mem_modify<u8>(address, f, mode); }
virtual bool mem_modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode) override { return mem_modify<u16>(address, f, mode); }
virtual bool mem_modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode) override { return mem_modify<u32>(address, f, mode); }
virtual bool pio_load(u32 address, u8 &data, rsc_mode const mode) override { return pio_load<u8>(address, data, mode); }
virtual bool pio_load(u32 address, u16 &data, rsc_mode const mode) override { return pio_load<u16>(address, data, mode); }
virtual bool pio_load(u32 address, u32 &data, rsc_mode const mode) override { return pio_load<u32>(address, data, mode); }
virtual bool pio_store(u32 address, u8 data, rsc_mode const mode) override { return pio_store<u8>(address, data, mode); }
virtual bool pio_store(u32 address, u16 data, rsc_mode const mode) override { return pio_store<u16>(address, data, mode); }
virtual bool pio_store(u32 address, u32 data, rsc_mode const mode) override { return pio_store<u32>(address, data, mode); }
virtual bool pio_modify(u32 address, std::function<u8(u8)> f, rsc_mode const mode) override { return pio_modify<u8>(address, f, mode); }
virtual bool pio_modify(u32 address, std::function<u16(u16)> f, rsc_mode const mode) override { return pio_modify<u16>(address, f, mode); }
virtual bool pio_modify(u32 address, std::function<u32(u32)> f, rsc_mode const mode) override { return pio_modify<u32>(address, f, mode); }
u8 ccr_r() { return m_ccr; }
void ccr_w(u8 data) { m_ccr = data; }
template <unsigned Word> u16 csr_r() { return u16((m_csr | CSR_RSV) >> (16 * Word)); }
void csr_w(u16 data) { set_int(false); m_csr = 0; }
u8 dma_b_r(offs_t offset);
u8 dma_w_r(offs_t offset);
void dma_b_w(offs_t offset, u8 data);
@ -94,9 +109,6 @@ public:
void dmr_w(u8 data) { m_dmr = data; }
void dbr_w(u8 data) { m_dbr = data; }
u16 tcw_r(offs_t offset) { return m_tcw[offset]; }
void tcw_w(offs_t offset, u16 data, u16 mem_mask) { COMBINE_DATA(&m_tcw[offset]); }
template <unsigned Channel> void dack_w(int state) { if (!state) m_adc = Channel; }
// HACK: temporary workaround for eop handling
@ -111,9 +123,12 @@ protected:
virtual space_config_vector memory_space_config() const override;
//virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
template <typename T> bool load(u32 address, T &data, rsc_mode const mode);
template <typename T> bool store(u32 address, T data, rsc_mode const mode);
template <typename T> bool modify(u32 address, std::function<T(T)> f, rsc_mode const mode);
template <typename T> bool mem_load(u32 address, T &data, rsc_mode const mode);
template <typename T> bool mem_store(u32 address, T data, rsc_mode const mode);
template <typename T> bool mem_modify(u32 address, std::function<T(T)> f, rsc_mode const mode);
template <typename T> bool pio_load(u32 address, T &data, rsc_mode const mode);
template <typename T> bool pio_store(u32 address, T data, rsc_mode const mode);
template <typename T> bool pio_modify(u32 address, std::function<T(T)> f, rsc_mode const mode);
void set_int(bool state)
{
@ -121,39 +136,23 @@ protected:
{
if (state)
m_csr |= CSR_INTP;
m_out_int_state = state;
m_out_int(!m_out_int_state);
}
}
unsigned target_size(u32 const address) const
{
if (address < 0xf000'8000U)
{
if (address == 0xf000'0110U || address == 0xf000'0112U)
return 2;
else
// FIXME: get size from isa bus
return 1;
}
else if (address == 0xf000'80e0U)
// exception for i/o delay register
return 4;
else if (address == 0xf000'8400U)
// exception for kls
return 2;
else if (address < 0xf001'0000U)
return 1;
else if (address < 0xf001'0800U)
return 2;
else
return 4;
}
private:
static constexpr u32 REG_MASK = 0xffff'f800U; // on-chip register mask
static constexpr u32 TCW_BASE = 0xf001'0000U; // translation control registers base address
static constexpr u32 CSR_ADDR = 0xf001'0800U; // channel status register address
address_space_config m_mem_config;
address_space_config m_pio_config;
memory_access<24, 1, 0, ENDIANNESS_LITTLE>::specific m_mem;
memory_access<24, 1, 0, ENDIANNESS_LITTLE>::specific m_pio;
devcb_write_line m_out_int;
devcb_write_line m_out_rst;