diff --git a/hash/ms120101_rom.xml b/hash/ms120101_rom.xml
new file mode 100644
index 0000000000000..1fe1ccb10a6c8
--- /dev/null
+++ b/hash/ms120101_rom.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+ BASIC interpreter (013)
+ 1985
+ Elektronika
+
+
+
+
+
+
+
+ FOCAL interpreter (058)
+ 1985
+ Elektronika
+
+
+
+
+
+
+
diff --git a/src/devices/cpu/t11/t11.cpp b/src/devices/cpu/t11/t11.cpp
index 738707450826c..beb81abadc2c7 100644
--- a/src/devices/cpu/t11/t11.cpp
+++ b/src/devices/cpu/t11/t11.cpp
@@ -33,6 +33,16 @@
#define SPD REGD(6)
#define PCD REGD(7)
#define PSW m_psw.b.l
+#define EPSW m_psw.w.l
+
+/* shadow PC and PSW registers on K1801VM2 */
+#define CPC m_cpc.w.l
+#define CPSW m_cpsw.w.l
+#define COPY_TO_SHADOW ((EPSW & 0600) != 0600)
+#define SET_CPC(x) \
+ do { PC = (x); if (COPY_TO_SHADOW) CPC = PC; } while (0)
+#define SET_CPSW(x) \
+ do { EPSW = (x); if (COPY_TO_SHADOW) CPSW = EPSW; } while (0)
DEFINE_DEVICE_TYPE(T11, t11_device, "t11", "DEC T11")
@@ -73,7 +83,8 @@ k1801vm1_device::k1801vm1_device(const machine_config &mconfig, const char *tag,
* Not implemented:
*
* instruction timing (+ memory timing), bug compatibility (@PC addressing mode),
- * HALT mode, traps: double bus error and bus error on vector fetch.
+ * HALT mode internals (C030 insn, shadow copy special cases, FIS emulation),
+ * traps: double bus error and bus error on vector fetch.
*/
k1801vm2_device::k1801vm2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: t11_device(mconfig, K1801VM2, tag, owner, clock)
@@ -93,6 +104,8 @@ t11_device::t11_device(const machine_config &mconfig, device_type type, const ch
, m_hlt_active(false)
, m_out_reset_func(*this)
, m_in_iack_func(*this, 0) // default vector (T-11 User's Guide, p. A-11)
+ , m_out_bankswitch_func(*this)
+ , m_in_sel1_func(*this, 0)
{
m_program_config.m_is_octal = true;
for (auto ® : m_reg)
@@ -214,6 +227,8 @@ int t11_device::POP()
#define VFLAG 2
#define ZFLAG 4
#define NFLAG 8
+#define TFLAG 16
+#define HFLAG 256
/* extracts flags */
#define GET_C (PSW & CFLAG)
@@ -222,6 +237,7 @@ int t11_device::POP()
#define GET_N (PSW & NFLAG)
#define GET_T (PSW & (1 << 4))
#define GET_I (PSW & (1 << 7))
+#define GET_H (EPSW & (1 << 8))
/* clears flags */
#define CLR_C (PSW &= ~CFLAG)
@@ -553,13 +569,21 @@ void k1801vm2_device::t11_check_irqs()
else if (m_bus_error)
{
m_bus_error = false;
- mcir = MCIR_IRQ;
- vsel = T11_TIMEOUT;
+ if (GET_H)
+ {
+ mcir = MCIR_HALT;
+ vsel = T11_TIMEOUT;
+ }
+ else
+ {
+ mcir = MCIR_IRQ;
+ vsel = T11_TIMEOUT;
+ }
}
// 2. illegal insn; nm
else if (m_mcir == MCIR_ILL)
{
- take_interrupt(vsel);
+ take_interrupt_user(vsel);
}
// 3. trace trap; WCPU
else if (m_trace_trap)
@@ -577,16 +601,15 @@ void k1801vm2_device::t11_check_irqs()
m_trace_trap = true;
}
// 4. power fail; PSW7, PSW8
- else if (m_power_fail)
+ else if (m_power_fail && !GET_I && !GET_H)
{
m_power_fail = false;
mcir = MCIR_IRQ;
vsel = T11_PWRFAIL;
}
// 5. external HALT (nHALT pin); PSW8
- else if (m_hlt_active)
+ else if (m_hlt_active && !GET_H)
{
- m_hlt_active = false;
mcir = MCIR_HALT;
vsel = VM2_HALT;
}
@@ -607,20 +630,72 @@ void k1801vm2_device::t11_check_irqs()
m_vec_active = 0;
return;
}
- mcir = MCIR_IRQ;
+ if (vec == VM2_VECERR)
+ {
+ PUSH(CPSW);
+ PUSH(CPC);
+ m_vec_active = 0;
+ m_icount -= 64;
+ mcir = MCIR_HALT;
+ }
+ else
+ mcir = MCIR_IRQ;
vsel = vec;
}
switch (mcir)
{
case MCIR_IRQ:
- take_interrupt(vsel);
+ take_interrupt_user(vsel);
+ break;
+
+ case MCIR_HALT:
+ if (vsel == VM2_HALT) m_hlt_active = false;
+ take_interrupt_halt(vsel);
break;
}
m_mcir = MCIR_NONE;
}
+void k1801vm2_device::take_interrupt_user(uint16_t vector)
+{
+ assert((vector & 3) == 0);
+
+ // enter USER mode
+ m_out_bankswitch_func(0);
+
+ uint16_t new_pc = RWORD(vector);
+ uint16_t new_psw = RWORD(vector + 2) & ~HFLAG;
+
+ // push the old state, set the new one
+ PUSH(CPSW);
+ PUSH(CPC);
+ SET_CPC(new_pc);
+ SET_CPSW(new_psw);
+
+ // count cycles and clear the WAIT flag
+ m_icount -= 114;
+ m_wait_state = 0;
+}
+
+void k1801vm2_device::take_interrupt_halt(uint16_t vector)
+{
+ assert((vector & 3) == 0);
+
+ // enter HALT mode
+ m_out_bankswitch_func(1);
+
+ // set new state (old state is kept in shadow PC and PSW)
+ PC = RWORD(c_initial_mode + vector);
+ EPSW = RWORD(c_initial_mode + vector + 2);
+ m_out_bankswitch_func(BIT(EPSW, 8));
+
+ // count cycles and clear the WAIT flag
+ m_icount -= 114;
+ m_wait_state = 0;
+}
+
/*************************************
*
@@ -664,6 +739,8 @@ void t11_device::device_start()
save_item(NAME(m_reg[6].w.l));
save_item(NAME(m_reg[7].w.l));
save_item(NAME(m_psw.w.l));
+ save_item(NAME(m_cpc.w.l));
+ save_item(NAME(m_cpsw.w.l));
save_item(NAME(m_initial_pc));
save_item(NAME(m_wait_state));
save_item(NAME(m_cp_state));
@@ -680,7 +757,7 @@ void t11_device::device_start()
// Register debugger state
state_add( T11_PC, "PC", m_reg[7].w.l).formatstr("%06O");
state_add( T11_SP, "SP", m_reg[6].w.l).formatstr("%06O");
- state_add( T11_PSW, "PSW", m_psw.b.l).formatstr("%03O");
+ state_add( T11_PSW, "PSW", m_psw.w.l).formatstr("%06O");
state_add( T11_R0, "R0", m_reg[0].w.l).formatstr("%06O");
state_add( T11_R1, "R1", m_reg[1].w.l).formatstr("%06O");
state_add( T11_R2, "R2", m_reg[2].w.l).formatstr("%06O");
@@ -690,7 +767,7 @@ void t11_device::device_start()
state_add(STATE_GENPC, "GENPC", m_reg[7].w.l).formatstr("%06O").noshow();
state_add(STATE_GENPCBASE, "CURPC", m_ppc.w.l).formatstr("%06O").noshow();
- state_add(STATE_GENFLAGS, "GENFLAGS", m_psw.b.l).formatstr("%8s").noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_psw.w.l).formatstr("%9s").noshow();
set_icountptr(m_icount);
}
@@ -701,7 +778,7 @@ void t11_device::state_string_export(const device_state_entry &entry, std::strin
{
case STATE_GENFLAGS:
str = string_format("%c%c%c%c%c%c%c%c",
- m_psw.b.l & 0x80 ? '?':'.',
+ m_psw.b.l & 0x80 ? 'I':'.',
m_psw.b.l & 0x40 ? 'I':'.',
m_psw.b.l & 0x20 ? 'I':'.',
m_psw.b.l & 0x10 ? 'T':'.',
@@ -739,15 +816,15 @@ void k1801vm2_device::state_string_export(const device_state_entry &entry, std::
{
case STATE_GENFLAGS:
str = string_format("%c%c%c%c%c%c%c%c%c",
- m_psw.b.l & 0x100 ? 'H':'.',
- m_psw.b.l & 0x80 ? 'P':'.',
- m_psw.b.l & 0x40 ? '?':'.',
- m_psw.b.l & 0x20 ? '?':'.',
- m_psw.b.l & 0x10 ? 'T':'.',
- m_psw.b.l & 0x08 ? 'N':'.',
- m_psw.b.l & 0x04 ? 'Z':'.',
- m_psw.b.l & 0x02 ? 'V':'.',
- m_psw.b.l & 0x01 ? 'C':'.'
+ m_psw.w.l & 0x100? 'H':'.',
+ m_psw.w.l & 0x80 ? 'I':'.',
+ m_psw.w.l & 0x40 ? '?':'.',
+ m_psw.w.l & 0x20 ? '?':'.',
+ m_psw.w.l & 0x10 ? 'T':'.',
+ m_psw.w.l & 0x08 ? 'N':'.',
+ m_psw.w.l & 0x04 ? 'Z':'.',
+ m_psw.w.l & 0x02 ? 'V':'.',
+ m_psw.w.l & 0x01 ? 'C':'.'
);
break;
}
@@ -794,11 +871,22 @@ void k1801vm2_device::device_reset()
{
t11_device::device_reset();
- PC = RWORD(c_initial_mode);
- PSW = RWORD(c_initial_mode+2);
+ // start in HALT mode
+ m_out_bankswitch_func(0);
+ m_out_bankswitch_func(1);
- m_mcir = MCIR_NONE;
+ c_initial_mode &= 0xff00;
+
+ CPC = PC = RWORD(c_initial_mode);
+ CPSW = EPSW = RWORD(c_initial_mode + 2);
+
+ m_mcir = suspended(SUSPEND_REASON_DISABLE) ? MCIR_WAIT : MCIR_NONE;
m_vsel = 0;
+
+ logerror("CPU: device_reset(), initial_mode %06o, PC %06o PSW %06o disabled %d\n", c_initial_mode, PC, PSW,
+ suspended(SUSPEND_REASON_DISABLE));
+
+ m_out_bankswitch_func(BIT(EPSW, 8));
}
@@ -860,6 +948,10 @@ void t11_device::execute_set_input(int irqline, int state)
void t11_device::execute_run()
{
+ // power on?
+ if ((c_insn_set & IS_VM2) && (m_mcir == MCIR_WAIT))
+ device_reset();
+
t11_check_irqs();
if (m_wait_state)
@@ -880,6 +972,12 @@ void t11_device::execute_run()
op = ROPCODE();
(this->*s_opcode_table[op >> 3])(op);
+ if ((c_insn_set & IS_VM2) && COPY_TO_SHADOW)
+ {
+ m_cpc = m_reg[7];
+ m_cpsw = m_psw;
+ }
+
if (m_check_irqs || m_trace_trap || GET_T)
{
m_check_irqs = false;
diff --git a/src/devices/cpu/t11/t11.h b/src/devices/cpu/t11/t11.h
index 639e1849f1987..6efb670a9ea58 100644
--- a/src/devices/cpu/t11/t11.h
+++ b/src/devices/cpu/t11/t11.h
@@ -46,6 +46,8 @@ class t11_device : public cpu_device
void set_initial_mode(const uint16_t mode) { c_initial_mode = mode; }
auto out_reset() { return m_out_reset_func.bind(); }
auto in_iack() { return m_in_iack_func.bind(); }
+ auto out_bankswitch() { return m_out_bankswitch_func.bind(); }
+ auto in_sel1() { return m_in_sel1_func.bind(); }
protected:
enum
@@ -62,7 +64,9 @@ class t11_device : public cpu_device
VM1_EVNT = 0100, // EVNT pin vector
VM1_IRQ3 = 0270, // IRQ3 pin vector
VM1_HALT = 0160002, // HALT instruction vector
- VM2_HALT = 0170 // HALT instruction vector
+ VM2_HALT = 0170, // HALT instruction vector
+ VM2_DBLERR = 0174, // Double bus error vector
+ VM2_VECERR = 0274 // Bus error on vector fetch
};
// K1801 microcode constants
enum
@@ -120,6 +124,8 @@ class t11_device : public cpu_device
PAIR m_ppc; /* previous program counter */
PAIR m_reg[8];
PAIR m_psw;
+ PAIR m_cpc; /* shadow copy of program counter */
+ PAIR m_cpsw; /* shadow copy of psw register */
uint16_t m_initial_pc;
uint8_t m_wait_state;
int8_t m_mcir;
@@ -141,6 +147,8 @@ class t11_device : public cpu_device
devcb_write_line m_out_reset_func;
devcb_read8 m_in_iack_func;
+ devcb_write_line m_out_bankswitch_func;
+ devcb_read8 m_in_sel1_func;
inline int ROPCODE();
inline int RBYTE(int addr);
@@ -159,6 +167,9 @@ class t11_device : public cpu_device
void op_0000(uint16_t op);
void op_0001(uint16_t op);
+ void op_0002(uint16_t op);
+ void op_0003(uint16_t op);
+ void op_7a00(uint16_t op);
void halt(uint16_t op);
void illegal(uint16_t op);
void illegal4(uint16_t op);
@@ -1280,6 +1291,8 @@ class k1801vm2_device : public t11_device, public z80_daisy_chain_interface
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
virtual void t11_check_irqs() override;
+ void take_interrupt_user(uint16_t vector);
+ void take_interrupt_halt(uint16_t vector);
};
diff --git a/src/devices/cpu/t11/t11dasm.cpp b/src/devices/cpu/t11/t11dasm.cpp
index fdbe23ab8c36d..0d65642cba37a 100644
--- a/src/devices/cpu/t11/t11dasm.cpp
+++ b/src/devices/cpu/t11/t11dasm.cpp
@@ -124,6 +124,21 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
case 005: util::stream_format(stream, "RESET"); break;
case 006: util::stream_format(stream, "RTT"); flags = STEP_OUT; break;
case 007: util::stream_format(stream, "MFPT"); break;
+ case 010: case 011: case 012:
+ case 013: util::stream_format(stream, "START"); break;
+ case 014: case 015: case 016:
+ case 017: util::stream_format(stream, "STEP"); break;
+ case 020: util::stream_format(stream, "RSEL"); break;
+ case 021: util::stream_format(stream, "MFUS"); break;
+ case 022:
+ case 023: util::stream_format(stream, "RCPC"); break;
+ case 024: case 0025: case 0026:
+ case 027: util::stream_format(stream, "RCPS"); break;
+ case 031: util::stream_format(stream, "MTUS"); break;
+ case 032:
+ case 033: util::stream_format(stream, "WCPC"); break;
+ case 034: case 0035: case 0036:
+ case 037: util::stream_format(stream, "WCPS"); break;
default: util::stream_format(stream, ".WORD %06o", op); break;
}
break;
diff --git a/src/devices/cpu/t11/t11ops.hxx b/src/devices/cpu/t11/t11ops.hxx
index b1244dc455f79..912d7b7437818 100644
--- a/src/devices/cpu/t11/t11ops.hxx
+++ b/src/devices/cpu/t11/t11ops.hxx
@@ -464,6 +464,12 @@ PUT_DW_DREG(result >> 16); REGW(dreg|1) = result
void t11_device::trap_to(uint16_t vector)
{
+ if (c_insn_set & IS_VM2)
+ {
+ EPSW &= ~HFLAG;
+ m_out_bankswitch_func(0);
+ }
+
PUSH(PSW);
PUSH(PC);
PC = RWORD(vector);
@@ -477,11 +483,42 @@ void t11_device::op_0000(uint16_t op)
{
case 0x00: /* HALT */ halt(op); break;
case 0x01: /* WAIT */ m_icount = 0; m_wait_state = 1; break;
- case 0x02: /* RTI */ m_icount -= 24; PC = POP(); PSW = POP(); if (GET_T) m_trace_trap = true; m_check_irqs = true; break;
+ case 0x02: /* RTI */
+ m_icount -= 24;
+ if (c_insn_set & IS_VM2)
+ {
+ SET_CPC(POP());
+ if (PC >= 0160000) SET_CPSW(POP()); else SET_CPSW((EPSW & HFLAG) | (POP() & 255));
+ m_out_bankswitch_func(BIT(EPSW, 8));
+ }
+ else
+ {
+ PC = POP(); PSW = POP();
+ }
+ if (GET_T) m_trace_trap = true;
+ m_check_irqs = true;
+ break;
case 0x03: /* BPT */ m_icount -= 48; trap_to(T11_BPT); break;
case 0x04: /* IOT */ m_icount -= 48; trap_to(T11_IOT); break;
case 0x05: /* RESET */ m_out_reset_func(ASSERT_LINE); m_out_reset_func(CLEAR_LINE); m_icount -= 110; break;
- case 0x06: /* RTT */ if (c_insn_set & IS_LEIS) { m_icount -= 33; PC = POP(); PSW = POP(); m_check_irqs = true; } else illegal(op); break;
+ case 0x06: /* RTT */
+ if (!(c_insn_set & IS_LEIS))
+ {
+ illegal(op); break;
+ }
+ m_icount -= 33;
+ if (c_insn_set & IS_VM2)
+ {
+ SET_CPC(POP());
+ if (PC >= 0160000) SET_CPSW(POP()); else SET_CPSW((EPSW & HFLAG) | (POP() & 255));
+ m_out_bankswitch_func(BIT(EPSW, 8));
+ }
+ else
+ {
+ PC = POP(); PSW = POP();
+ }
+ m_check_irqs = true;
+ break;
case 0x07: /* MFPT */ if (c_insn_set & IS_MFPT) REGB(0) = 4; else illegal(op); break;
default: illegal(op); break;
@@ -490,24 +527,125 @@ void t11_device::op_0000(uint16_t op)
void t11_device::op_0001(uint16_t op)
{
- CHECK_IS(IS_VM1);
+ CHECK_IS(IS_VM1|IS_VM2);
+
+ if (c_insn_set & IS_VM1)
+ {
+ switch (op & 014)
+ {
+ case 010: // START
+ m_icount -= 24;
+ PC = RWORD(VM1_STACK);
+ PSW = RWORD(VM1_STACK + 2);
+ WWORD(VM1_SEL1, RWORD(VM1_SEL1) & ~SEL1_HALT);
+ break;
+ case 014: // STEP
+ m_icount -= 24;
+ PC = RWORD(VM1_STACK);
+ PSW = RWORD(VM1_STACK + 2);
+ WWORD(VM1_SEL1, RWORD(VM1_SEL1) & ~SEL1_HALT);
+ PC += 2;
+ break;
+ default: illegal(op); break;
+ }
+ }
+
+ // commands are valid only in HALT mode
+ else if (c_insn_set & IS_VM2)
+ {
+ if (!BIT(EPSW, 8))
+ {
+ illegal(op);
+ return;
+ }
+ switch (op & 014)
+ {
+ case 010: // START
+ m_icount -= 24;
+ PC = CPC;
+ EPSW = CPSW;
+ m_out_bankswitch_func(BIT(EPSW, 8));
+ m_check_irqs = true;
+ break;
+ case 014: // STEP
+ m_icount -= 24;
+ PC = CPC;
+ EPSW = CPSW;
+ m_out_bankswitch_func(BIT(EPSW, 8));
+ // force execution of next insn
+ m_check_irqs = false;
+ break;
+ default: illegal(op); break;
+ }
+ }
+}
+
+void t11_device::op_0002(uint16_t op)
+{
+ CHECK_IS(IS_VM2);
- switch (op & 014)
+ if (!BIT(EPSW, 8))
{
- case 010: // START
+ illegal(op);
+ return;
+ }
+ switch (op & 0x3f)
+ {
+ case 020: /* RSEL */
+ m_icount -= 24;
+ REGW(0) = c_initial_mode | (m_in_sel1_func(0) & 0xff);
+ break;
+ case 021: /* MFUS */
+ m_icount -= 24;
+ m_out_bankswitch_func(0);
+ REGW(0) = RWORD(REGW(5));
+ REGW(5) += 2;
+ m_out_bankswitch_func(1);
+ m_check_irqs = true;
+ break;
+ case 022: /* RCPC */
+ case 023:
m_icount -= 24;
- PC = RWORD(VM1_STACK);
- PSW = RWORD(VM1_STACK + 2);
- WWORD(VM1_SEL1, RWORD(VM1_SEL1) & ~SEL1_HALT);
+ REGW(0) = CPC;
break;
- case 014: // STEP
+ case 024: /* RCPS */
+ case 025: case 026: case 027:
m_icount -= 24;
- PC = RWORD(VM1_STACK);
- PSW = RWORD(VM1_STACK + 2);
- WWORD(VM1_SEL1, RWORD(VM1_SEL1) & ~SEL1_HALT);
- PC += 2;
+ REGW(0) = CPSW;
break;
+ default: illegal(op); break;
+ }
+}
+void t11_device::op_0003(uint16_t op)
+{
+ CHECK_IS(IS_VM2);
+
+ if (!BIT(EPSW, 8))
+ {
+ illegal(op);
+ return;
+ }
+ switch (op & 0x3f)
+ {
+ case 031: /* MTUS */
+ m_icount -= 24;
+ m_out_bankswitch_func(0);
+ REGW(5) -= 2;
+ WWORD(REGW(5), REGW(0));
+ m_out_bankswitch_func(1);
+ m_check_irqs = true;
+ break;
+ case 032: /* WCPC */
+ case 033:
+ m_icount -= 24;
+ CPC = REGW(0);
+ break;
+ case 034: /* WCPS */
+ case 035: case 036: case 037:
+ m_icount -= 24;
+ CPSW = REGW(0);
+ break;
default: illegal(op); break;
}
}
@@ -522,6 +660,7 @@ void t11_device::halt(uint16_t op)
}
else if (c_insn_set & IS_VM2)
{
+ if (BIT(EPSW, 8)) return;
m_mcir = MCIR_HALT;
m_vsel = VM2_HALT;
m_check_irqs = true;
@@ -536,6 +675,16 @@ void t11_device::halt(uint16_t op)
m_check_irqs = true;
}
+void t11_device::op_7a00(uint16_t op)
+{
+ CHECK_IS(IS_VM2);
+
+ m_icount -= 48;
+ m_mcir = MCIR_HALT;
+ m_vsel = T11_ILLINST;
+ m_check_irqs = true;
+}
+
void t11_device::illegal(uint16_t op)
{
m_icount -= 48;
diff --git a/src/devices/cpu/t11/t11table.hxx b/src/devices/cpu/t11/t11table.hxx
index e5ee1309ffe29..0637a889d3433 100644
--- a/src/devices/cpu/t11/t11table.hxx
+++ b/src/devices/cpu/t11/t11table.hxx
@@ -25,7 +25,7 @@ modes:
const t11_device::opcode_func t11_device::s_opcode_table[65536 >> 3] =
{
/* 0x0000 */
- OP(op_0000), OP(op_0001), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal),
+ OP(op_0000), OP(op_0001), OP(op_0002), OP(op_0003), OP(illegal), OP(illegal), OP(illegal), OP(illegal),
OP(illegal4), OP(jmp_rgd), OP(jmp_in), OP(jmp_ind), OP(jmp_de), OP(jmp_ded), OP(jmp_ix), OP(jmp_ixd),
OP(rts), OP(illegal), OP(illegal), OP(illegal), OP(ccc), OP(ccc), OP(scc), OP(scc),
OP(swab_rg), OP(swab_rgd), OP(swab_in), OP(swab_ind), OP(swab_de), OP(swab_ded), OP(swab_ix), OP(swab_ixd),
@@ -642,7 +642,7 @@ const t11_device::opcode_func t11_device::s_opcode_table[65536 >> 3] =
OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd),
OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd),
/* 0x7a00 */
- OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal),
+ OP(op_7a00), OP(op_7a00), OP(op_7a00), OP(op_7a00), OP(illegal), OP(illegal), OP(illegal), OP(illegal),
OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal),
OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal),
OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal),
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 09d8bafcd97a5..7a1faee2f33c1 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -47953,6 +47953,14 @@ mk98
@source:ussr/ms0515.cpp
ms0515
+@source:ussr/ms1201.cpp
+ms120101
+ms120102
+dvk1
+dvk2
+dvk3
+dvk3m
+
@source:ussr/ms6102.cpp
ms6102
@@ -47973,6 +47981,9 @@ orionzms
@source:ussr/partner.cpp
partner
+@source:ussr/pk11.cpp
+pk11
+
@source:ussr/pk32.cpp
pk32
diff --git a/src/mame/ussr/1801vp033.cpp b/src/mame/ussr/1801vp033.cpp
index 8b7eb3fc68331..e49ecfc85128d 100644
--- a/src/mame/ussr/1801vp033.cpp
+++ b/src/mame/ussr/1801vp033.cpp
@@ -138,11 +138,11 @@ uint16_t k1801vp033_device::bpic_read(offs_t offset)
switch (offset & 3)
{
- case 0:
+ case 2:
data = m_tcsr & BPICCSR_RD;
break;
- case 2:
+ case 3:
data = m_tbuf;
break;
}
@@ -183,7 +183,7 @@ void k1801vp033_device::bpic_write(offs_t offset, uint16_t data, uint16_t mem_ma
switch (offset & 3)
{
- case 0:
+ case 2:
if ((data & CSR_IE) == 0)
{
clear_virq(m_bpic_write_txrdy, 1, 1, m_txrdy);
@@ -196,7 +196,7 @@ void k1801vp033_device::bpic_write(offs_t offset, uint16_t data, uint16_t mem_ma
m_bpic_write_reset(!BIT(m_tcsr, 14));
break;
- case 2:
+ case 3:
m_tbuf = data & 0377;
m_tcsr &= ~BPICCSR_DRQ;
clear_virq(m_bpic_write_txrdy, m_tcsr, CSR_IE, m_txrdy);
diff --git a/src/mame/ussr/ms1201.cpp b/src/mame/ussr/ms1201.cpp
new file mode 100644
index 0000000000000..50b3b21d60333
--- /dev/null
+++ b/src/mame/ussr/ms1201.cpp
@@ -0,0 +1,441 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/***************************************************************************
+
+ Elektronika MS 1201 series of processor boards, used in DVK series
+ desktops. Bus interface is MPI (clone of Q-Bus).
+
+ Firmware's CLI is similar to DEC LSI-11 ODT.
+
+ Available bootstrap routines vary by board and ROM revision:
+
+ MS 1201.01 board:
+
+ ROM 000 - paper tape (bootstrap format only), 'DX' floppy
+ ROM 031, 054 - same, plus 'DY' and 'MX' floppies
+
+ Paper tape: "177550L" (loads absolute loader from tape), followed by
+ "P" (loads the rest of tape).
+ DX floppy: "173000G" or "D0" (drive 0), or "D1" (drive 1)
+ MX floppy: "X0" (drive 0) or "X1" (drive 1)
+
+ MS 1201.02 board:
+
+ ROM 055 - 'LA' paper tape, 'DX' and 'MX' floppies, 'MT' magnetic tape,
+ 'RK' fixed disk, 'RM' ROM disk
+ ROM 279 - same, plus 'MY' floppy and 'DW' fixed disk
+
+ Paper tape: "B LA" (copies absolute loader from ROM), followed by
+ "P" (loads tape).
+ All other devices: "B" followed by device type and optional unit number.
+
+****************************************************************************/
+
+#include "emu.h"
+
+#include "1801vp033.h"
+#include "bus/centronics/ctronics.h"
+#include "bus/generic/carts.h"
+#include "bus/generic/slot.h"
+#include "bus/qbus/qbus.h"
+#include "bus/rs232/rs232.h"
+#include "cpu/t11/t11.h"
+#include "machine/timer.h"
+#include "machine/dl11.h"
+#include "machine/ram.h"
+#include "vm1timer.h"
+
+#include "softlist_dev.h"
+
+
+class ms1201_base_state : public driver_device
+{
+public:
+ ms1201_base_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_bpic(*this, "bpic")
+ , m_dl11(*this, "dl11")
+ , m_rs232(*this, "rs232")
+ , m_qbus(*this, "qbus")
+ , m_sa0(*this, "SA0")
+ , m_sa1(*this, "SA1")
+ , m_view(*this, "view")
+ { }
+
+ void ms1201_base(machine_config &config);
+
+ uint16_t trap_r(offs_t offset);
+ void trap_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+
+private:
+
+protected:
+ required_device m_maincpu;
+ required_device m_bpic;
+ required_device m_dl11;
+ required_device m_rs232;
+ required_device m_qbus;
+ required_ioport m_sa0;
+ required_ioport m_sa1;
+
+ memory_view m_view;
+
+ TIMER_DEVICE_CALLBACK_MEMBER(pclk_timer);
+ int m_odt_map;
+};
+
+
+class ms1201_01_state : public ms1201_base_state
+{
+public:
+ ms1201_01_state(const machine_config &mconfig, device_type type, const char *tag)
+ : ms1201_base_state(mconfig, type, tag)
+ , m_extrom(*this, "extrom")
+ , m_rombank(*this, "rombank")
+ { }
+
+ void ms120101(machine_config &config);
+ void dvk1(machine_config &config);
+ void dvk2(machine_config &config);
+
+ virtual void machine_reset() override ATTR_COLD;
+
+ void ms1201_01_mem(address_map &map) ATTR_COLD;
+
+ uint16_t sel_r(offs_t offset);
+ void sel_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+
+protected:
+ required_device m_extrom;
+
+ memory_view m_rombank;
+
+private:
+ void reset_w(int state);
+ uint16_t m_sel[2];
+};
+
+class ms1201_02_state : public ms1201_base_state
+{
+public:
+ ms1201_02_state(const machine_config &mconfig, device_type type, const char *tag)
+ : ms1201_base_state(mconfig, type, tag)
+ { }
+
+ void ms120102(machine_config &config);
+ void dvk3(machine_config &config);
+ void dvk3m(machine_config &config);
+
+ virtual void machine_start() override ATTR_COLD;
+ virtual void machine_reset() override ATTR_COLD;
+
+ void ms1201_02_mem(address_map &map) ATTR_COLD;
+
+private:
+ void reset_w(int state);
+};
+
+
+static INPUT_PORTS_START(ms1201)
+ PORT_START("SA0")
+ PORT_DIPNAME(0x01, 0x00, "ODT (HALT) mode")
+ PORT_DIPSETTING(0x01, DEF_STR(Yes) )
+ PORT_DIPSETTING(0x00, DEF_STR(No) )
+ PORT_DIPNAME(0x02, 0x00, "Timer interrupt")
+ PORT_DIPSETTING(0x02, DEF_STR(Yes) )
+ PORT_DIPSETTING(0x00, DEF_STR(No) )
+
+ PORT_START("SA1")
+ PORT_DIPNAME(0x0f, 0x01, "Boot mode")
+ PORT_DIPSETTING(0x00, "0 - start at powerfail vector 024" )
+ PORT_DIPSETTING(0x01, "1 - start in ODT" )
+ PORT_DIPSETTING(0x02, "2 - boot from disk" )
+ PORT_DIPSETTING(0x03, "3 - start in user ROM at 0140000" )
+INPUT_PORTS_END
+
+
+void ms1201_01_state::ms1201_01_mem(address_map &map)
+{
+ map(0000000, 0177777).rw(FUNC(ms1201_01_state::trap_r), FUNC(ms1201_01_state::trap_w));
+
+ map(0000000, 0137777).ram();
+ map(0140000, 0157777).view(m_rombank);
+ m_rombank[0](0140000, 0157777).ram();
+ m_rombank[1](0140000, 0157777).r(m_extrom, FUNC(generic_slot_device::read_rom));
+ map(0160000, 0172777).view(m_view);
+ m_view[0](0160000, 0172777).rw(FUNC(ms1201_01_state::trap_r), FUNC(ms1201_01_state::trap_w));
+ m_view[1](0160000, 0163777).rom().region("maincpu", 0);
+ m_view[1](0164000, 0172777).rw(FUNC(ms1201_01_state::trap_r), FUNC(ms1201_01_state::trap_w));
+ m_view[2](0160000, 0172777).rom().region("maincpu", 0);
+ m_view[3](0160000, 0172777).rom().region("maincpu", 0);
+ map(0173000, 0173777).rom().region("maincpu", 013000);
+ map(0177510, 0177517).rw(m_bpic, FUNC(k1801vp033_device::bpic_read), FUNC(k1801vp033_device::bpic_write));
+ map(0177560, 0177567).rw(m_dl11, FUNC(k1801vp065_device::read), FUNC(k1801vp065_device::write));
+ map(0177600, 0177677).ram();
+ map(0177706, 0177713).rw("vm1timer", FUNC(k1801vm1_timer_device::read), FUNC(k1801vm1_timer_device::write));
+ map(0177714, 0177717).rw(FUNC(ms1201_01_state::sel_r), FUNC(ms1201_01_state::sel_w));
+}
+
+void ms1201_02_state::ms1201_02_mem(address_map &map)
+{
+ map(0000000, 0177777).view(m_view);
+
+// USER mode
+ m_view[0](0000000, 0177777).rw(FUNC(ms1201_02_state::trap_r), FUNC(ms1201_02_state::trap_w));
+ m_view[0](0000000, 0157777).ram();
+ m_view[0](0177510, 0177517).rw(m_bpic, FUNC(k1801vp033_device::bpic_read), FUNC(k1801vp033_device::bpic_write));
+ m_view[0](0177560, 0177567).rw(m_dl11, FUNC(k1801vp065_device::read), FUNC(k1801vp065_device::write));
+
+// HALT mode
+ m_view[1](0000000, 0177777).rw(FUNC(ms1201_02_state::trap_r), FUNC(ms1201_02_state::trap_w));
+ m_view[1](0140000, 0157777).rom().region("maincpu", 0);
+ m_view[1](0170000, 0177777).ram();
+}
+
+
+uint16_t ms1201_01_state::sel_r(offs_t offset)
+{
+ if (offset == 0)
+ {
+ return m_sel[1];
+ }
+
+ return 0160000 | (m_sa1->read() & 3) | (m_sel[0] & 0374);
+}
+
+void ms1201_01_state::sel_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ if (offset == 0)
+ {
+ COMBINE_DATA(&m_sel[1]);
+ return;
+ }
+
+ COMBINE_DATA(&m_sel[0]);
+
+ if (m_odt_map != ((m_sel[0] >> 2) & 3))
+ {
+ m_odt_map = (m_sel[0] >> 2) & 3;
+ m_view.select(m_odt_map);
+ }
+}
+
+uint16_t ms1201_base_state::trap_r(offs_t offset)
+{
+ if (!machine().side_effects_disabled())
+ m_maincpu->pulse_input_line(t11_device::BUS_ERROR, attotime::zero);
+
+ return 0xffff;
+}
+
+void ms1201_base_state::trap_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ m_maincpu->pulse_input_line(t11_device::BUS_ERROR, attotime::zero);
+}
+
+
+TIMER_DEVICE_CALLBACK_MEMBER(ms1201_base_state::pclk_timer)
+{
+ m_maincpu->set_input_line(t11_device::HLT_LINE, BIT(m_sa0->read(), 0));
+ if (BIT(m_sa0->read(), 1))
+ m_maincpu->pulse_input_line(t11_device::CP2_LINE, m_maincpu->minimum_quantum_time());
+}
+
+
+static const z80_daisy_config daisy_chain[] =
+{
+ { "dl11" },
+// { "fdic" },
+ { "bpic" },
+ { "qbus" },
+ { nullptr }
+};
+
+
+void ms1201_01_state::machine_reset()
+{
+ // move to machine_start? see https://github.com/1801BM1/k1801/tree/master/030
+ m_odt_map = 2;
+ m_view.select(m_odt_map);
+ m_rombank.select(m_extrom->get_rom_size() == 0 ? 0 : 1);
+ m_sel[0] = m_sel[1] = 0;
+}
+
+void ms1201_01_state::reset_w(int state)
+{
+ if (state == ASSERT_LINE)
+ {
+ m_dl11->reset();
+ // FDIC
+ m_bpic->reset();
+ m_qbus->init_w();
+ }
+}
+
+void ms1201_02_state::machine_start()
+{
+ m_qbus->set_view(m_view[0]);
+}
+
+void ms1201_02_state::machine_reset()
+{
+ m_odt_map = 1;
+ m_view.select(m_odt_map);
+}
+
+void ms1201_02_state::reset_w(int state)
+{
+ if (state == ASSERT_LINE)
+ {
+ m_dl11->reset();
+ // FDIC
+ m_bpic->reset();
+ m_qbus->init_w();
+ }
+}
+
+void ms1201_base_state::ms1201_base(machine_config &config)
+{
+ TIMER(config, "pclk").configure_periodic(FUNC(ms1201_base_state::pclk_timer), attotime::from_hz(50));
+
+ QBUS(config, m_qbus, 0);
+ m_qbus->set_space(m_maincpu, AS_PROGRAM);
+ m_qbus->birq4().set_inputline(m_maincpu, t11_device::VEC_LINE);
+ QBUS_SLOT(config, "qbus" ":1", qbus_cards, "pc11"); // actually BPIC in bidirectional mode
+ QBUS_SLOT(config, "qbus" ":2", qbus_cards, nullptr); // actually FDIC
+ QBUS_SLOT(config, "qbus" ":3", qbus_cards, nullptr);
+ QBUS_SLOT(config, "qbus" ":4", qbus_cards, nullptr);
+
+ K1801VP065(config, m_dl11, XTAL(4'608'000));
+ m_dl11->set_rxc(9600);
+ m_dl11->set_txc(9600);
+ m_dl11->set_rxvec(060);
+ m_dl11->set_txvec(064);
+ m_dl11->txd_wr_callback().set(m_rs232, FUNC(rs232_port_device::write_txd));
+ m_dl11->txrdy_wr_callback().set_inputline(m_maincpu, t11_device::VEC_LINE);
+ m_dl11->rxrdy_wr_callback().set_inputline(m_maincpu, t11_device::VEC_LINE);
+
+ RS232_PORT(config, m_rs232, default_rs232_devices, "terminal");
+ m_rs232->rxd_handler().set(m_dl11, FUNC(k1801vp065_device::rx_w));
+
+ K1801VP033(config, m_bpic, 0);
+ m_bpic->set_txvec(0200);
+ m_bpic->bpic_txrdy_wr_callback().set_inputline(m_maincpu, t11_device::VEC_LINE);
+ m_bpic->bpic_reset_wr_callback().set("centronics", FUNC(centronics_device::write_init));
+ m_bpic->bpic_strobe_wr_callback().set("centronics", FUNC(centronics_device::write_strobe));
+ m_bpic->bpic_pd_wr_callback().set("printdata", FUNC(output_latch_device::write));
+
+ centronics_device ¢ronics(CENTRONICS(config, "centronics", centronics_devices, "printer"));
+ centronics.set_output_latch(OUTPUT_LATCH(config, "printdata"));
+ centronics.busy_handler().set(m_bpic, FUNC(k1801vp033_device::bpic_write_drq)).invert();
+ centronics.perror_handler().set(m_bpic, FUNC(k1801vp033_device::bpic_write_err));
+}
+
+void ms1201_01_state::ms120101(machine_config &config)
+{
+ ms1201_base(config);
+
+ K1801VM1(config, m_maincpu, XTAL(8'000'000) / 2);
+ m_maincpu->set_addrmap(AS_PROGRAM, &ms1201_01_state::ms1201_01_mem);
+ downcast(m_maincpu.target())->set_daisy_config(daisy_chain);
+ m_maincpu->out_reset().set(FUNC(ms1201_01_state::reset_w));
+
+ K1801VM1_TIMER(config, "vm1timer", XTAL(8'000'000) / 2);
+
+ GENERIC_CARTSLOT(config, m_extrom, generic_plain_slot, "ms120101_rom");
+ SOFTWARE_LIST(config, "cart_list").set_original("ms120101_rom");
+}
+
+void ms1201_01_state::dvk1(machine_config &config)
+{
+ ms120101(config);
+
+ // FIXME add basic
+ subdevice("qbus:2")->set_default_option(nullptr);
+ subdevice("rs232")->set_default_option("ie15");
+}
+
+void ms1201_01_state::dvk2(machine_config &config)
+{
+ ms120101(config);
+
+ subdevice("rs232")->set_default_option("ie15");
+}
+
+void ms1201_02_state::ms120102(machine_config &config)
+{
+ ms1201_base(config);
+
+ K1801VM2(config, m_maincpu, XTAL(8'000'000) / 2);
+ m_maincpu->set_addrmap(AS_PROGRAM, &ms1201_02_state::ms1201_02_mem);
+ m_maincpu->set_initial_mode(0140000);
+ downcast(m_maincpu.target())->set_daisy_config(daisy_chain);
+ m_maincpu->out_reset().set(FUNC(ms1201_02_state::reset_w));
+ m_maincpu->out_bankswitch().set([this] (int state) {
+ if (m_odt_map != state) { m_view.select(state); m_odt_map = state; }
+ });
+ m_maincpu->in_sel1().set_ioport("SA1");
+}
+
+void ms1201_02_state::dvk3(machine_config &config)
+{
+ ms120102(config);
+
+ // FIXME replace with ksm
+ subdevice("rs232")->set_default_option("ie15");
+ subdevice("qbus:1")->set_default_option("kgd");
+ subdevice("qbus:2")->set_default_option("mx");
+}
+
+void ms1201_02_state::dvk3m(machine_config &config)
+{
+ ms120102(config);
+
+ // FIXME replace with kcgd
+ subdevice("rs232")->set_default_option("ie15");
+ subdevice("qbus:1")->set_default_option("dw");
+ subdevice("qbus:2")->set_default_option("my");
+}
+
+
+ROM_START(ms120101)
+ ROM_REGION16_LE(020000, "maincpu", ROMREGION_ERASE00)
+ ROM_DEFAULT_BIOS("054")
+ ROM_SYSTEM_BIOS(0, "000", "mask 000 (1981)")
+ ROMX_LOAD("000.dat", 0, 020000, CRC(7c8d149b) SHA1(8603c99d99237d3dec4a022118f4ad0af358e899), ROM_BIOS(0))
+ ROM_SYSTEM_BIOS(1, "031", "mask 031 (198x)")
+ ROMX_LOAD("031.dat", 0, 020000, CRC(4631ffe6) SHA1(1584c674ca9728be51040fd04b0a22c938fe57b1), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(2, "054", "mask 054 (198x)")
+ ROMX_LOAD("054.bin", 0, 020000, CRC(89254082) SHA1(9aa3ad780d881915d27fea7621d474c4dda2a6d2), ROM_BIOS(2))
+ROM_END
+
+ROM_START(ms120102)
+ ROM_REGION16_LE(020000, "maincpu", ROMREGION_ERASE00)
+ ROM_DEFAULT_BIOS("279")
+ ROM_SYSTEM_BIOS(0, "055", "mask 055 (1985)")
+ ROMX_LOAD("055.dat", 0, 020000, CRC(11c28e48) SHA1(a328ca6de54630cd81659977fd2a0e7f0ad168fd), ROM_BIOS(0))
+ ROM_SYSTEM_BIOS(1, "279", "mask 279 (1991)")
+ ROMX_LOAD("279.dat", 0, 020000, CRC(26932af0) SHA1(e2d863085fc818ebcb08dcccbc5470106dd8eb33), ROM_BIOS(1))
+ROM_END
+
+#define rom_dvk1 rom_ms120101
+#define rom_dvk2 rom_ms120101
+#define rom_dvk3 rom_ms120102
+#define rom_dvk3m rom_ms120102
+
+/* Driver */
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */
+COMP( 1983, ms120101, 0, 0, ms120101, ms1201, ms1201_01_state, empty_init, "USSR", "MS 1201.01", MACHINE_NOT_WORKING)
+COMP( 1985, ms120102, 0, 0, ms120102, ms1201, ms1201_02_state, empty_init, "USSR", "MS 1201.02", MACHINE_NOT_WORKING)
+// ie15, rom 013 (basic), no storage
+COMP( 1983, dvk1, ms120101, 0, dvk1, ms1201, ms1201_01_state, empty_init, "USSR", "DVK-1", MACHINE_NOT_WORKING)
+// ie15, kgd, rom 093? (focal), no storage, lan
+//MP( 1983, dvk1msh, ms120101, 0, ms120101, ms1201, ms1201_01_state, empty_init, "USSR", "DVK-1MSH", MACHINE_NOT_WORKING)
+// ie15, dx floppy
+COMP( 1983, dvk2, ms120101, 0, dvk2, ms1201, ms1201_01_state, empty_init, "USSR", "DVK-2", MACHINE_NOT_WORKING)
+// ksm, kgd, mx floppy
+COMP( 1983, dvk3, ms120102, 0, dvk3, ms1201, ms1201_02_state, empty_init, "USSR", "DVK-3", MACHINE_NOT_WORKING)
+// kcgd, my floppy, dw disk
+COMP( 1983, dvk3m, ms120102, 0, dvk3m, ms1201, ms1201_02_state, empty_init, "USSR", "DVK-3M", MACHINE_NOT_WORKING)
diff --git a/src/mame/ussr/pk11.cpp b/src/mame/ussr/pk11.cpp
new file mode 100644
index 0000000000000..22e25910f0389
--- /dev/null
+++ b/src/mame/ussr/pk11.cpp
@@ -0,0 +1,1142 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/***************************************************************************
+
+ Soyuz-Neon PK-11/16K (experimental desktop)
+
+ References:
+ - https://github.com/troosh/pk11-16/wiki
+ - https://github.com/nzeemin/neonbtl
+
+ todo
+ - init and save_item
+ - video mode quirks (vn 0, vn 0/1 + vd 0, 1bpp/2bpp palette layout), borders
+ - console window palette
+ - odd address vs. io_rw
+ - bit 21 in 22-bit address fix
+
+ debug
+ - kbd (stop button)
+ - hdd
+
+ add
+ - mouse
+ - printer
+ - ata
+ - slot (uses UR7 and HR7?)
+
+ hw revisions
+ - A: IRQ 5 rate = 64 Hz, driven by RTC (SQW output)
+ two expansion slots, use IRQs 6,7 and registers UR7 and HR7
+ schematic: pk11-16-sch-20180617.pdf
+ - B: IRQ 5 rate = 50 Hz, driven by vblank
+ one expansion slot, uses IRQ 7
+ IRQ 6 -- printer port
+ schematic: tbd
+
+ irqs
+
+ 0 RESET insn
+ 1 fdc, hdc
+ 2 rxrdy
+ 3 txrdy
+ 4 kbdc
+ 5 vblank || rtc
+ 6 printer
+ 7 slot
+
+****************************************************************************/
+
+#include "emu.h"
+
+#include "bus/centronics/ctronics.h"
+#include "bus/rs232/rs232.h"
+#include "cpu/t11/t11.h"
+#include "formats/bk0010_dsk.h"
+#include "imagedev/floppy.h"
+#include "imagedev/harddriv.h"
+#include "machine/i8251.h"
+#include "machine/i8255.h"
+#include "machine/i8279.h"
+#include "machine/input_merger.h"
+#include "machine/mc146818.h"
+#include "machine/pic8259.h"
+#include "machine/pit8253.h"
+#include "machine/ram.h"
+#include "machine/timer.h"
+#include "machine/upd765.h"
+#include "machine/wd1010.h"
+#include "emupal.h"
+#include "screen.h"
+
+
+#define LOG_MMU (1U << 1)
+#define LOG_DEBUG (1U << 2)
+#define LOG_VIDEO (1U << 3)
+#define LOG_DISK (1U << 4)
+
+// #define VERBOSE (LOG_DEBUG | LOG_DISK)
+#include "logmacro.h"
+
+#define LOGMMU(...) LOGMASKED(LOG_MMU, __VA_ARGS__)
+#define LOGDBG(...) LOGMASKED(LOG_DEBUG, __VA_ARGS__)
+#define LOGVIDEO(...) LOGMASKED(LOG_VIDEO, __VA_ARGS__)
+#define LOGDISK(...) LOGMASKED(LOG_DISK, __VA_ARGS__)
+
+#define BUS_ERROR do { m_maincpu->pulse_input_line(t11_device::BUS_ERROR, attotime::zero); } while (0)
+
+
+namespace {
+
+// these are unverified
+static constexpr int PK11_TOTAL_HORZ = 1024;
+static constexpr int PK11_DISP_HORZ = 832;
+static constexpr int PK11_HORZ_START = 0;
+
+static constexpr int PK11_TOTAL_VERT = 312;
+static constexpr int PK11_DISP_VERT = 300;
+static constexpr int PK11_VERT_START = 0;
+
+
+typedef struct
+{
+ uint32_t addr[26];
+ uint16_t mode[26];
+ int border[26];
+} pk11_scanline;
+
+
+class pk11_state : public driver_device
+{
+public:
+ pk11_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_pic8259(*this, "pic8259")
+ , m_upd8251(*this, "upd8251")
+ , m_pit8253_1(*this, "pit8253_1")
+ , m_pit8253_2(*this, "pit8253_2")
+ , m_ppi8255(*this, "ppi8255")
+ , m_kdc(*this, "kdc")
+ , m_fdc(*this, "fdc")
+ , m_hdc(*this, "hdc")
+ , m_hdd(*this, "hdc:1")
+ , m_rtc(*this, "rtc")
+ , m_halt_merger(*this, "merge_halt")
+ , m_irq1_merger(*this, "merge_irq1")
+ , m_screen(*this, "screen")
+ , m_io_keyboard(*this, "X%u", 0U)
+ , m_buttons(*this, "mouse_buttons")
+ , m_ram(*this, "ram")
+ , m_view_main(*this, "view_main")
+ { }
+
+ void pk11(machine_config &config);
+
+ DECLARE_INPUT_CHANGED_MEMBER(mouse_x_changed);
+ DECLARE_INPUT_CHANGED_MEMBER(mouse_y_changed);
+ DECLARE_INPUT_CHANGED_MEMBER(buttons_changed);
+
+private:
+ virtual void machine_reset() override ATTR_COLD;
+ virtual void machine_start() override ATTR_COLD;
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ uint32_t vdpword(uint32_t offset);
+ void update_displaylist();
+
+ uint16_t mmu_user_r(offs_t offset);
+ uint16_t mmu_halt_r(offs_t offset);
+ void mmu_user_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+ void mmu_halt_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+ uint16_t mmap_r(uint16_t reg, uint32_t addr);
+ void mmap_w(uint16_t reg, uint32_t addr, uint16_t data, uint16_t mem_mask);
+
+ uint16_t mmap_user_r(offs_t offset);
+ uint16_t mmap_halt_r(offs_t offset);
+ void mmap_user_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+ void mmap_halt_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+ uint16_t io_r(offs_t offset, uint16_t mem_mask);
+ void io_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+ uint16_t fdc_r(offs_t offset);
+ void fdc_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+ uint16_t hdc_r(offs_t offset);
+ void hdc_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+ uint16_t buf_r();
+ void buf_w(uint16_t data);
+
+ uint16_t fdc_buf_r();
+ void fdc_buf_w(uint16_t data);
+
+ void fdc_drq_w(int state);
+
+ void pk11_mem(address_map &map) ATTR_COLD;
+
+ int m_odt_map, m_halt, m_ioint, m_ef[2];
+ uint16_t m_ur[8], m_hr[8], *m_p_ram;
+ uint32_t m_vdpmask;
+
+ std::unique_ptr m_scanlines;
+ uint32_t m_palette[1024]{};
+
+ static void floppy_formats(format_registration &fr);
+ floppy_image_device *floppy[2];
+
+ int8_t m_x, m_y, m_sr;
+ uint8_t kbd_r(), m_digit;
+
+ std::map syscall_map;
+
+ bool m_buf_dir, drq;
+ uint16_t m_buf_ptr;
+ std::unique_ptr m_buf;
+
+ TIMER_CALLBACK_MEMBER(timer_tick);
+ emu_timer *m_timer;
+
+protected:
+ required_device m_maincpu;
+ required_device m_pic8259;
+ required_device m_upd8251;
+ required_device m_pit8253_1;
+ required_device m_pit8253_2;
+ required_device m_ppi8255;
+ required_device m_kdc;
+ required_device m_fdc;
+ required_device m_hdc;
+ optional_device m_hdd;
+ required_device m_rtc;
+ required_device m_halt_merger;
+ required_device m_irq1_merger;
+ required_device m_screen;
+ required_ioport_array<8> m_io_keyboard;
+ required_ioport m_buttons;
+
+ required_device m_ram;
+ memory_view m_view_main;
+};
+
+//
+
+INPUT_CHANGED_MEMBER(pk11_state::mouse_x_changed)
+{
+ m_x += newval - oldval;
+ LOGVIDEO("X %3d->%3d d %3d m_x %3d\n", oldval, newval, newval-oldval, m_x);
+}
+
+INPUT_CHANGED_MEMBER(pk11_state::mouse_y_changed)
+{
+ m_y += newval - oldval;
+ LOGVIDEO("Y %3d->%3d d %3d m_y %3d\n", oldval, newval, newval-oldval, m_y);
+}
+
+INPUT_CHANGED_MEMBER(pk11_state::buttons_changed)
+{
+ m_sr = m_buttons->read();
+}
+
+/*
+ * row 8 (signal KX9 in XS1 connector) is dedicated to STOP key; wired together with row 2 (KX3)
+ * columns 0..11 (signals KY1..KY12 in XS2 connector) are mapped to RL bits:
+ *
+ * 0 RL001 KY3 KY6 KY9
+ * 1 RL002 KY4 KY6 KY11
+ * 2 RL004 KY5 KY9 KY11
+ * 3 RL010 KY7
+ * 4 RL020 KY8
+ * 5 RL040 KY10
+ * 6 RL100 KY1 KY12
+ * 7 RL200 KY2
+ */
+uint8_t pk11_state::kbd_r()
+{
+ if (m_digit > 7) return 0xff;
+
+ uint16_t raw = bitswap<16>(m_io_keyboard[m_digit]->read(),
+ 0, 0, 0, 0, 4, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5);
+
+ uint8_t data = bitswap<8>(raw, 1, 0, 9, 7, 6, 4, 3, 2) &
+ bitswap<8>(raw, 15, 11, 15, 15, 15, 8, 5, 5) &
+ bitswap<8>(raw, 15, 15, 15, 15, 15, 10, 10, 8);
+
+ return data;
+}
+
+// keyboard is ms7007
+
+INPUT_PORTS_START(pk11)
+
+ // bit 15 = col 11, bit 5 = col 1, bit 4 = col 12
+ PORT_START("X0")
+ PORT_BIT( 0x001F, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad ,") PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK))
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("AR2 (Esc)") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("K1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("K2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("K3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("K4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("K5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+
+ PORT_START("X1")
+ PORT_BIT( 0x001F, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') PORT_CHAR(0x0a) PORT_CHAR(0x0a)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0x05) PORT_CHAR(0x05)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+
+ PORT_START("X2")
+ PORT_BIT( 0x002F, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR(0x06) PORT_CHAR(0x06)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') PORT_CHAR(0x03) PORT_CHAR(0x03)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR(0x15) PORT_CHAR(0x15)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') PORT_CHAR(0x0b) PORT_CHAR(0x0b)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(0x10) PORT_CHAR(0x10)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') PORT_CHAR(0x0e) PORT_CHAR(0x0e)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR(0x07) PORT_CHAR(0x07)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c) PORT_CHAR(0x0c)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR(0x04) PORT_CHAR(0x04)
+
+ PORT_START("X3")
+ PORT_BIT( 0x003F, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Graf") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT))
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR(0x11) PORT_CHAR(0x11)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR(0x19) PORT_CHAR(0x19)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(0x17) PORT_CHAR(0x17)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR(0x01) PORT_CHAR(0x01)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') PORT_CHAR(0x09) PORT_CHAR(0x09)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR(0x12) PORT_CHAR(0x12)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0f) PORT_CHAR(0x0f)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') PORT_CHAR(0x02) PORT_CHAR(0x02)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(": @") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('@') PORT_CHAR('`')
+
+ PORT_START("X4")
+ PORT_BIT( 0x001F, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Alf") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT))
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Ch")
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR(0x13) PORT_CHAR(0x13)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') PORT_CHAR(0x0d) PORT_CHAR(0x0d)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR(0x14) PORT_CHAR(0x14)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR(0x18) PORT_CHAR(0x18)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Cursor left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+
+ PORT_START("X5")
+ PORT_BIT( 0x001F, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad +") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD))
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("UTF8_LEFT") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Cursor right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Cursor down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(0x16) PORT_CHAR(0x16)
+
+ PORT_START("X6")
+ PORT_BIT( 0x001F, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(" (Go)") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(" (Setup)") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r')
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Cursor up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(": hardsign") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') PORT_CHAR(0x08) PORT_CHAR(0x08)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR(0x1a) PORT_CHAR(0x1a)
+
+ PORT_START("X7")
+ PORT_BIT( 0x001F, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad Enter") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(" (Reset)") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(" (Help)") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*') // FIXME
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') // FIXME
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // FIXME
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+
+ PORT_START("mouse_x")
+ PORT_BIT( 0xff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(10) PORT_KEYDELTA(1) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(pk11_state::mouse_x_changed), 0)
+
+ PORT_START("mouse_y")
+ PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(10) PORT_KEYDELTA(1) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(pk11_state::mouse_y_changed), 0)
+
+ PORT_START("mouse_buttons")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Left Mouse Button") PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(pk11_state::buttons_changed), 0)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Right Mouse Button") PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(pk11_state::buttons_changed), 0)
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+INPUT_PORTS_END
+
+void pk11_state::pk11_mem(address_map &map)
+{
+ map(0000000, 0177777).view(m_view_main);
+ map(0160000, 0167777).lrw16(
+ NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) BUS_ERROR; return 0; }),
+ NAME([this](offs_t offset, uint16_t data) { BUS_ERROR; }));
+
+ // USER mode
+ m_view_main[0](0000000, 0157777).rw(FUNC(pk11_state::mmap_user_r), FUNC(pk11_state::mmap_user_w));
+ m_view_main[0](0170000, 0177677).rw(FUNC(pk11_state::io_r), FUNC(pk11_state::io_w)); // 174000 and up trigger HALT irq
+ m_view_main[0](0177700, 0177777).lrw16(
+ NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) BUS_ERROR; return 0; }),
+ NAME([this](offs_t offset, uint16_t data) { BUS_ERROR; }));
+
+ // HALT mode
+ m_view_main[1](0000000, 0037777).rom().region("maincpu", 0);
+ m_view_main[1](0040000, 0157777).rw(FUNC(pk11_state::mmap_halt_r), FUNC(pk11_state::mmap_halt_w));
+ m_view_main[1](0170000, 0177677).lrw16(
+ NAME([this](offs_t offset) { return m_p_ram[offset]; }),
+ NAME([this](offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_p_ram[offset]); }));
+
+ map(0161000, 0161003).rw(m_pic8259, FUNC(pic8259_device::read), FUNC(pic8259_device::write)).umask16(0xff);
+ map(0161010, 0161017).rw(m_pit8253_1, FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask16(0xff);
+ map(0161020, 0161027).rw(m_pit8253_2, FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask16(0xff);
+ map(0161030, 0161037).rw(m_ppi8255, FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0xff);
+ map(0161040, 0161057).rw(FUNC(pk11_state::hdc_r), FUNC(pk11_state::hdc_w));
+ map(0161060, 0161063).rw(m_upd8251, FUNC(i8251_device::read), FUNC(i8251_device::write)).umask16(0xff);
+ map(0161064, 0161067).rw(m_kdc, FUNC(i8279_device::read), FUNC(i8279_device::write)).umask16(0xff);
+ map(0161070, 0161073).m(m_fdc, FUNC(upd765a_device::map)).umask16(0xff);
+ map(0161076, 0161077).rw(FUNC(pk11_state::fdc_r), FUNC(pk11_state::fdc_w));
+ map(0161200, 0161217).rw(FUNC(pk11_state::mmu_halt_r), FUNC(pk11_state::mmu_halt_w));
+ map(0161220, 0161237).rw(FUNC(pk11_state::mmu_user_r), FUNC(pk11_state::mmu_user_w));
+ map(0161400, 0161477).rw(m_rtc, FUNC(mc146818_device::read_direct), FUNC(mc146818_device::write_direct)).flags(t11_device::UNALIGNED_BYTE);
+}
+
+static DEVICE_INPUT_DEFAULTS_START( host_rs232_defaults )
+ DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_9600 )
+ DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_9600 )
+ DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 )
+ DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE )
+ DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_2 )
+DEVICE_INPUT_DEFAULTS_END
+
+
+void pk11_state::machine_reset()
+{
+ m_odt_map = 1; m_view_main.select(1);
+ m_halt = m_ioint = 0;
+ m_ef[0] = m_ef[1] = 0;
+
+ memset(m_palette, 0, sizeof(m_palette));
+
+ m_x = m_y = m_digit = 0;
+
+ m_buf_ptr = 0;
+ m_buf_dir = false; // READ
+ drq = false;
+}
+
+void pk11_state::machine_start()
+{
+ m_p_ram = (uint16_t *) m_ram->pointer();
+ m_vdpmask = (m_ram->size() >> 1) - 1;
+
+ m_scanlines = make_unique_clear(PK11_DISP_VERT);
+ m_buf = make_unique_clear(2048);
+ m_hdc->drdy_w(m_hdd->exists());
+ m_hdc->head_w(0);
+
+ for (int i = 0; i < 2; i++)
+ {
+ char name[2] = { static_cast('0' + i), 0 };
+ floppy_connector *conn = m_fdc->subdevice(name);
+ floppy[i] = conn ? conn->get_device() : nullptr;
+ }
+
+ m_timer = timer_alloc(FUNC(pk11_state::timer_tick), this);
+ m_timer->adjust(attotime::never, 0, attotime::never);
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_ur[i] = m_hr[i] = 0;
+ }
+
+ // FIXME
+ save_item(NAME(m_buf_ptr));
+ save_pointer(NAME(m_buf), 2048);
+
+ syscall_map = {
+ // syscalls
+ {0174176, "GET4K"},
+ {0174200, "GET8K"},
+ {0174202, "FREMEM"},
+ {0174174, "FRE4K"},
+ {0174204, "PUTMAP"},
+ {0174206, "GETBMAP"},
+ {0174210, "GETSMAP"},
+ {0174166, "NEWROMP"},
+ {0174214, "NEWPROC"},
+ {0174222, "KILPROC"},
+ {0174152, "SETPRI"},
+ {0174212, "HIMPRI"},
+ {0174154, "PROVEC"},
+ {0174156, "UNPVEC"},
+ {0174160, "PROREG"},
+ {0174162, "UNPREG"},
+ {0174164, "WAITINT"},
+ {0174170, "SETINT"},
+ {0174172, "RESINT"},
+ {0174216, "MTHLT"},
+ {0174220, "MFHLT"},
+ {0174142, "INITSEM"},
+ {0174144, "RELSEM"},
+ {0174146, "WAITSEM"},
+ {0174150, "SIGSEM"},
+ {0174224, "GETPDS"},
+ {0174226, "PUTPDS"},
+ {0174230, "GETRDS"},
+ {0174232, "PUTRDS"},
+ {0174234, "GETPAR"},
+ {0174236, "PUTPAR"},
+ {0174000, "reboot"},
+ // devices
+ {0177130, "HFBUF"}, // floppy and hard disk, vectors 230 (hdvec), 234 (fdvec)
+ {0177144, "MDCSR"}, // ram disk
+ {0177146, "MDBUF"},
+ {0177150, "MDSIZ"},
+ {0176500, "RCSR"}, // serial port, vector 300
+ {0176502, "RBUF"},
+ {0176504, "TCSR"},
+ {0176506, "TBUF"},
+ {0177530, "WCSR"}, // window system and manager
+ {0177524, "WMCSR"},
+ {0177564, "DCSR"}, // console, vector 64
+ {0177566, "DBUF"},
+ {0177174, "HOLER"}, // calculator
+ {0174060, "FILCSR"}, // filer
+ {0174062, "FMCSR"},
+ {0174064, "FCCSR"},
+ {0177600, "GCSR"}, // graphics display
+ {0176200, "MXX"}, // mouse
+ {0176202, "MYY"},
+ {0176204, "MCSR"},
+ {0176206, "MCALL"},
+ {0176240, "SNCSR"}, // sound
+ {0176242, "SNBUF"},
+ {0177110, "CLKREG"}, // aux display
+ {0174100, "DCHAR"},
+ {0174102, "DSTRING"},
+ {0174104, "DVAL"},
+ {0174106, "KSTRING"},
+ {0174110, "RESPON"},
+ {0177560, "KBCSR"}, // keyboard, vector 60
+ {0177562, "KBBUF"},
+ {0174052, "CNSBUF"}, // debugger
+ {0174054, "CNSKIL"},
+ // undocumented
+ {0177546, "CLKCSR"},
+ {0176220, "COCO"},
+ {0176216, "COCS"},
+ };
+}
+
+void pk11_state::mmu_user_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMMU("UR%d W <- %06o (A21:12 = %4o, access %d)\n", offset, data, BIT(data, 4, 10), BIT(data, 3));
+ COMBINE_DATA(&m_ur[offset]);
+}
+
+uint16_t pk11_state::mmu_user_r(offs_t offset)
+{
+ uint16_t data = m_ur[offset];
+ LOGMMU("UR%d R == %06o\n", offset, data);
+ return data;
+}
+
+void pk11_state::mmu_halt_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ if (!m_odt_map)
+ {
+ BUS_ERROR;
+ return;
+ }
+ LOGMMU("HR%d W <- %06o (A21:12 = %4o, access %d)\n", offset, data, BIT(data, 4, 10), BIT(data, 3));
+ COMBINE_DATA(&m_hr[offset]);
+ if (offset == 0 || offset == 1)
+ {
+ m_ef[0] = m_ef[1] = 0;
+ m_halt_merger->in_w<0>(CLEAR_LINE);
+ }
+}
+
+uint16_t pk11_state::mmu_halt_r(offs_t offset)
+{
+ uint16_t data = m_hr[offset];
+ LOGMMU("HR%d R == %06o\n", offset, data);
+ return data;
+}
+
+
+void pk11_state::fdc_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGDISK("disk fdc_w <- %04x (buf %d)\n", data, data & 3);
+ m_buf_ptr = (data & 3) << 9;
+ if (data & 020) m_fdc->reset();
+}
+
+uint16_t pk11_state::fdc_r(offs_t offset)
+{
+ return 0;
+}
+
+void pk11_state::fdc_drq_w(int state)
+{
+ if (drq == state) return;
+ drq = state;
+ if (!drq)
+ {
+ m_timer->adjust(attotime::never, 0, attotime::never);
+ return;
+ }
+
+ LOGDISK("disk drq (%d, %d)\n", m_buf_dir, m_buf_ptr);
+ m_timer->adjust(attotime::from_usec(16)); // FIXME timing
+}
+
+TIMER_CALLBACK_MEMBER(pk11_state::timer_tick)
+{
+ int tc = m_buf_ptr == 2047;
+ m_fdc->tc_w(tc);
+ if (m_buf_dir)
+ fdc_buf_w(m_fdc->dma_r());
+ else
+ {
+ m_fdc->dma_w(fdc_buf_r());
+ if (!tc && drq) m_timer->adjust(attotime::from_usec(16)); // FIXME timing
+ }
+}
+
+void pk11_state::hdc_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ switch (offset)
+ {
+ case 0:
+ if (!m_buf_dir) return;
+ LOGDISK("disk hdc_w[%4d] <- %02x\n", m_buf_ptr, data);
+ m_buf[m_buf_ptr++] = data;
+ m_buf_ptr &= 2047;
+ return;
+
+ case 6 >> 1: // SNUM
+ // workaround for non-standard sector numbering
+ if (data == 255) data = 0;
+ data &= 31;
+ break;
+
+ case 014 >> 1: // SDH
+ m_buf_dir = true;
+ if (!BIT(data, 3))
+ {
+ LOGDISK("disk dor %02x (side %d dens %d drive %d motor %d)\n", data, BIT(data, 0), BIT(data, 1), BIT(data, 2), BIT(data, 4));
+ // 0 side select
+ // 1 density
+ // 2 drive
+ // 3 0=floppy 1=hdd
+ // 4 motor
+ for (int i=0; i<2; i++)
+ if (floppy[i])
+ floppy[i]->mon_w(!BIT(data, 4));
+ m_fdc->set_floppy(floppy[BIT(data, 2)]);
+
+ return;
+ }
+ else
+ {
+ data &= ~0x10; // FIXME
+ m_hdc->head_w(data & 7);
+ }
+ break;
+
+ case 016 >> 1:
+ m_buf_dir = false;
+ break;
+ }
+
+ m_hdc->write(offset, data);
+}
+
+uint16_t pk11_state::hdc_r(offs_t offset)
+{
+ uint16_t data;
+
+ switch (offset)
+ {
+ case 0:
+ if (m_buf_dir) return 0;
+ data = m_buf[m_buf_ptr];
+ LOGDISK("disk hdc_r[%4d] == %02x\n", m_buf_ptr, data);
+ if (!machine().side_effects_disabled())
+ m_buf_ptr = (m_buf_ptr + 1) & 2047;
+ return data;
+
+ case 014 >> 1:
+ if (!machine().side_effects_disabled())
+ m_buf_dir = true;
+ break;
+
+ case 016 >> 1:
+ if (!machine().side_effects_disabled())
+ m_buf_dir = false;
+ break;
+ }
+
+ return m_hdc->read(offset);
+}
+
+void pk11_state::fdc_buf_w(uint16_t data)
+{
+ LOGDISK("disk fdc_buf_w[%4d] <- %02x\n", m_buf_ptr, data);
+ m_buf[m_buf_ptr++] = data;
+ m_buf_ptr &= 2047;
+}
+
+uint16_t pk11_state::fdc_buf_r()
+{
+ uint16_t data = m_buf[m_buf_ptr];
+ LOGDISK("disk fdc_buf_r[%4d] == %02x\n", m_buf_ptr, data);
+ if (!machine().side_effects_disabled())
+ m_buf_ptr = (m_buf_ptr + 1) & 2047;
+ return data;
+}
+
+void pk11_state::buf_w(uint16_t data)
+{
+ LOGDISK("disk buf_w[%4d] <- %02x\n", m_buf_ptr, data);
+ m_buf[m_buf_ptr] = data;
+ m_buf_ptr = ((m_buf_ptr + 1) & 511) | (m_buf_ptr & (3 << 9));
+}
+
+uint16_t pk11_state::buf_r()
+{
+ uint16_t data = m_buf[m_buf_ptr];
+ LOGDISK("disk buf_r[%4d] == %02x\n", m_buf_ptr, data);
+ if (!machine().side_effects_disabled())
+ m_buf_ptr = ((m_buf_ptr + 1) & 511) | (m_buf_ptr & (3 << 9));
+ return data;
+}
+
+
+void pk11_state::io_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ uint16_t a = 0170000 + (offset << 1); // + (mem_mask == 0xff00);
+ LOGDBG("%s IO W %06o <- %06o ; %s\n", machine().describe_context(), a, data, syscall_map[a].c_str());
+ COMBINE_DATA(&m_p_ram[(offset & 03777)]);
+ if (offset >= 02000)
+ {
+ if (!m_ef[0] || m_hr[0] == a) // XXX rmw
+ m_hr[0] = a;
+ else
+ m_hr[1] = a;
+ m_ef[0] = m_ef[1] = 1;
+ m_halt_merger->in_w<0>(ASSERT_LINE);
+ }
+}
+
+uint16_t pk11_state::io_r(offs_t offset, uint16_t mem_mask)
+{
+ uint16_t a = 0170000 + (offset << 1); // + (mem_mask == 0xff00);
+ uint16_t data = m_p_ram[(offset & 03777)];
+ LOGDBG("%s IO R %06o == %06o ; %s\n", machine().describe_context(), a, data, syscall_map[a].c_str());
+ if (offset >= 02000 && !machine().side_effects_disabled())
+ {
+ if (!m_ef[0])
+ m_hr[0] = a;
+ else
+ m_hr[1] = a;
+ m_ef[0] = 1;
+ m_halt_merger->in_w<0>(ASSERT_LINE);
+ }
+ return data;
+}
+
+/*
+ * write modes
+ *
+ * 0 -- mask unchanged
+ * 1 -- mask for 2bpp modes
+ * 2 -- mask for 4bpp modes
+ */
+void pk11_state::mmap_w(uint16_t reg, uint32_t addr, uint16_t data, uint16_t mem_mask)
+{
+ if ((addr << 1) >= m_ram->size() || BIT(reg, 3))
+ {
+ BUS_ERROR;
+ return;
+ }
+
+ uint16_t mask = 0;
+ data &= mem_mask;
+
+ if (BIT(reg, 0))
+ {
+ for (int i = 0; i < 16; i+=2)
+ {
+ if (BIT(data, i, 2)) mask |= (3 << i);
+ }
+ mem_mask &= mask;
+ }
+ else if (BIT(reg, 1))
+ {
+ for (int i = 0; i < 16; i+=4)
+ {
+ if (BIT(data, i, 4)) mask |= (15 << i);
+ }
+ mem_mask &= mask;
+ }
+
+ COMBINE_DATA(&m_p_ram[addr]);
+}
+
+uint16_t pk11_state::mmap_r(uint16_t reg, uint32_t addr)
+{
+ uint16_t data = 0;
+ if ((addr << 1) >= m_ram->size() || BIT(reg, 3))
+ BUS_ERROR;
+ else
+ data = m_p_ram[addr];
+ return data;
+}
+
+void pk11_state::mmap_user_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ uint16_t ur = BIT(offset, 12, 3);
+ uint32_t addr = (offset & 07777) + (BIT(m_ur[ur], 4, 10) << 11);
+ mmap_w(m_ur[ur], addr, data, mem_mask);
+}
+
+uint16_t pk11_state::mmap_user_r(offs_t offset)
+{
+ uint16_t ur = BIT(offset, 12, 3);
+ uint32_t addr = (offset & 07777) + (BIT(m_ur[ur], 4, 10) << 11);
+ return mmap_r(m_ur[ur], addr);
+}
+
+void pk11_state::mmap_halt_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ offset += 020000;
+ uint16_t hr = BIT(offset, 12, 3);
+ uint32_t addr = (offset & 07777) + (BIT(m_hr[hr], 4, 10) << 11);
+ mmap_w(m_hr[hr], addr, data, mem_mask);
+}
+
+uint16_t pk11_state::mmap_halt_r(offs_t offset)
+{
+ offset += 020000;
+ uint16_t hr = BIT(offset, 12, 3);
+ uint32_t addr = (offset & 07777) + (BIT(m_hr[hr], 4, 10) << 11);
+ return mmap_r(m_hr[hr], addr);
+}
+
+void pk11_state::floppy_formats(format_registration &fr)
+{
+ fr.add_mfm_containers();
+ fr.add(FLOPPY_BK0010_FORMAT);
+}
+
+static void pk11_floppies(device_slot_interface &device)
+{
+ device.option_add("525qd", FLOPPY_525_QD);
+}
+
+uint32_t pk11_state::vdpword(uint32_t offset)
+{
+ return ((m_p_ram[offset] + (m_p_ram[offset + 1] << 16)) << 1) & m_vdpmask; // offset into m_p_ram
+}
+
+/*
+ * VDPTAP points to palette list
+ * palette entries use RGB565 format
+ * 512 entries -- 1,2,4bpp palettes (two sets, 4 palettes per mode): vm1, vm2, vm40, vm41 modes in each set (vm41 unused in set 1)
+ * 512 entries -- 8bpp palettes (two palettes)
+ *
+ * VDPTAS points to 2-level display list (300 dwords)
+ * list entry format: 19:0 = top 20 bits of physical address, 25:20 and 31 = mode bits, 30:26 = slice length
+ * 1st level entries use only address field
+ * max 26 slices per scanline (32 pixel clocks each)
+ */
+void pk11_state::update_displaylist()
+{
+ uint32_t paladdr = vdpword(004 >> 1);
+ uint32_t tasaddr = vdpword(010 >> 1) + 4; // skip first 2 invisible entries
+ uint32_t lineaddr, otraddr;
+ uint16_t slicebits;
+ int slice;
+
+ /*
+ * 4 sets of 256 entries, layout is: 256 bytes of msb, then 256 bytes of lsb
+ */
+ LOGVIDEO("paladdr %09o\n", paladdr);
+ for (int c = 0; c < 1024; c++)
+ {
+ uint16_t hi = m_p_ram[paladdr + ((c >> 1) & 127) + (c & ~255)];
+ uint16_t lo = m_p_ram[paladdr + ((c >> 1) & 127) + (c & ~255) + 128];
+ uint16_t rgb;
+ if (c & 1)
+ rgb = (hi & 0xff00) | (lo >> 8);
+ else
+ rgb = (hi << 8) | (lo & 0xff);
+
+ if (c < 4) LOGVIDEO("pal %d %04x\n", c, rgb);
+ m_palette[c] = rgbexpand<5,6,5>(bitswap<16>(rgb, 12, 11, 10, 4, 3, 15, 14, 13, 7, 6, 5, 9, 8, 2, 1, 0), 11, 5, 0);
+ }
+
+ for (int i = 0; i < PK11_DISP_VERT; i++)
+ {
+ lineaddr = vdpword(tasaddr);
+ tasaddr += 2;
+ pk11_scanline *scanline = &m_scanlines[i];
+
+ if (!i) LOGVIDEO("u_d\n");
+ if (i<20) LOGVIDEO("%3d (%09o)=%09o\n", i, (tasaddr - 2) << 1, lineaddr << 1);
+ for (int j = 0, bar = 26; bar > 0;)
+ {
+ otraddr = vdpword(lineaddr);
+ slicebits = m_p_ram[lineaddr+1];
+ lineaddr += 2;
+
+ slice = 32 - BIT(slicebits, 10, 5);
+ if (!slice) slice = 32;
+ if (i < 20 && slice) LOGVIDEO("otr (%09o)=%09o %06o %2d mode pn %d vn %d vd %d\n",
+ (lineaddr - 2) << 1, otraddr << 1, slicebits, slice,
+ BIT(slicebits, 4, 2), BIT(slicebits, 6, 2) + (BIT(slicebits, 15) << 2), BIT(slicebits, 8, 2));
+
+ for (int first = 0 /* FIXME */; slice > 0 && bar > 0; slice--, bar--, j++)
+ {
+ const int vd = BIT(slicebits, 8, 2);
+ scanline->addr[j] = otraddr;
+ scanline->mode[j] = slicebits;
+ scanline->border[j] = first;
+ first = 0;
+ otraddr += 1 << (vd ? vd - 1 : 0);
+ }
+ }
+ }
+}
+
+uint32_t pk11_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ update_displaylist();
+
+ for (int row = 0; row < PK11_DISP_VERT; row++)
+ {
+ uint32_t *p = &bitmap.pix(row);
+ pk11_scanline *scanline = &m_scanlines[row];
+ for (int g = 0; g < 26; g++)
+ {
+ // 0: 1bpp, 1: 2bpp, 2: 4bpp, 3: 4/8bpp
+ int vn = BIT(scanline->mode[g], 6, 2);
+ // vd 0,1: fetch 52 bytes per scanline, 2: 104, 3: 208 bytes XXX vd 0
+ int vd = BIT(scanline->mode[g], 8, 2);
+ int pb = (BIT(scanline->mode[g], 15) << 4) | (vn << 2) | BIT(scanline->mode[g], 4, 2);
+ int wide = vd ? (1 << (vd - 1)) : 1;
+ int zoom = vd ? (1 << (3 - vd)) : 4;
+
+ if (scanline->border[g])
+ {
+ // prev
+ for (int b1 = 0; b1 < 9; b1++) *p++ = m_palette[pb << 4];
+ // border
+ for (int b2 = 0; b2 < 2; b2++) *p++ = m_palette[0];
+ // this
+ for (int b3 = 0; b3 < 5; b3++) *p++ = m_palette[pb << 4];
+ }
+// else
+ for (int w = 0; w < wide; w++)
+ {
+ uint16_t gfx = m_p_ram[scanline->addr[g] + w];
+ uint32_t color;
+
+ switch (vn)
+ {
+ case 0:
+ for (int px = 0; px < 16; px++)
+ {
+ color = m_palette[BIT(gfx, px) + 14 + (pb << 4)];
+ *p++ = color;
+ if (vd < 2) { *p++ = color; }
+ }
+ break;
+
+ case 1:
+ for (int px = 0; px < 16; px+=2)
+ {
+ color = m_palette[BIT(gfx, px, 2) + 12 + (pb << 4)];
+ for (int j = 0; j < zoom; j++) *p++ = color;
+ }
+ break;
+
+ case 2:
+ case 3:
+ for (int px = 0; px < 16; px+=4)
+ {
+ if (vn == 3 && BIT(scanline->mode[g], 15))
+ {
+ color = m_palette[BIT(gfx, px, 8) + (512 << BIT(scanline->mode[g], 4))];
+ for (int j = 0; j < (zoom * 4); j++) *p++ = color;
+ px += 4;
+ }
+ else
+ {
+ color = m_palette[BIT(gfx, px, 4) + (pb << 4)];
+ for (int j = 0; j < (zoom * 2); j++) *p++ = color;
+ }
+ }
+ break;
+
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+void pk11_state::pk11(machine_config &config)
+{
+ K1801VM2(config, m_maincpu, XTAL(30'800'000) / 4);
+ m_maincpu->set_addrmap(AS_PROGRAM, &pk11_state::pk11_mem);
+ m_maincpu->set_initial_mode(0);
+ m_maincpu->in_iack().set([] () { return 0274; }); // vector timeout handler, adds 64T
+ m_maincpu->out_reset().set(m_pic8259, FUNC(pic8259_device::ir0_w));
+ m_maincpu->out_bankswitch().set([this] (int state) {
+ if (m_odt_map != state) {
+ m_view_main.select(state); m_odt_map = state;
+ // m_halt_merger->in_w<0>(CLEAR_LINE);
+ LOGDBG("%s HALT mode changed: %d (ef %d,%d io %d halt %d)\n", machine().describe_context(), state, m_ef[0], m_ef[1], m_ioint, m_halt);
+ }
+ });
+
+ RAM(config, m_ram).set_default_size("512K").set_extra_options("1M,2M,4M");
+
+ INPUT_MERGER_ANY_HIGH(config, m_halt_merger).output_handler().set_inputline(m_maincpu, t11_device::HLT_LINE);
+ INPUT_MERGER_ANY_HIGH(config, m_irq1_merger).output_handler().set(m_pic8259, FUNC(pic8259_device::ir1_w));
+
+ PIC8259(config, m_pic8259);
+ m_pic8259->out_int_callback().set(m_halt_merger, FUNC(input_merger_any_high_device::in_w<1>));
+ m_pic8259->out_int_callback().append([this] (int state) {
+ if (m_ioint != state) LOGDBG("ioint <- %d\n", state);
+ m_ioint = state;
+ });
+
+ I8251(config, m_upd8251, 0);
+ m_upd8251->txd_handler().set("rs232", FUNC(rs232_port_device::write_txd));
+ m_upd8251->dtr_handler().set("rs232", FUNC(rs232_port_device::write_dtr));
+ m_upd8251->rts_handler().set("rs232", FUNC(rs232_port_device::write_rts));
+ m_upd8251->rxrdy_handler().set(m_pic8259, FUNC(pic8259_device::ir2_w));
+ m_upd8251->txrdy_handler().set(m_pic8259, FUNC(pic8259_device::ir3_w));
+
+ // debug console, active when power-on memory test fails
+ rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, nullptr));
+ rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(host_rs232_defaults));
+ rs232.rxd_handler().set(m_upd8251, FUNC(i8251_device::write_rxd));
+ rs232.dsr_handler().set(m_upd8251, FUNC(i8251_device::write_dsr));
+ rs232.cts_handler().set(m_upd8251, FUNC(i8251_device::write_cts));
+
+ PIT8253(config, m_pit8253_1);
+ m_pit8253_1->set_clk<0>(2'000'000);
+ m_pit8253_1->set_clk<1>(1'996'800); /* serial port */
+ m_pit8253_1->out_handler<1>().set([this] (int state) { m_upd8251->write_txc(state); m_upd8251->write_rxc(state); });
+ m_pit8253_1->set_clk<2>(2'000'000);
+
+ PIT8253(config, m_pit8253_2);
+ m_pit8253_2->set_clk<0>(2'000'000);
+ m_pit8253_2->set_clk<1>(2'000'000);
+ m_pit8253_2->set_clk<2>(2'000'000);
+
+ I8255(config, m_ppi8255);
+ // PA -- printer, mouse
+ // PB -- printer, io, irqs
+ m_ppi8255->in_pb_callback().set([this] () -> uint8_t {
+ uint8_t data = (!m_ef[0]) | (!m_ef[1] << 1) | (m_ioint << 2) | (m_halt << 3);
+ LOGDBG("%s %d in_pb 0x%x (ef %d,%d io %d halt %d)\n", machine().describe_context(), machine().side_effects_disabled(),
+ data, m_ef[0], m_ef[1], m_ioint, m_halt);
+ return data;
+ });
+ // PC -- rtc, irqs, mouse
+ m_ppi8255->out_pc_callback().set([this] (uint8_t data) {
+ m_halt = !BIT(data, 2);
+ m_halt_merger->in_w<2>(m_halt);
+ m_maincpu->set_input_line(t11_device::VEC_LINE, !BIT(data, 3));
+ LOGDBG("%s out_pc halt %d vec %d\n", machine().describe_context(), m_halt, !BIT(data, 3));
+ });
+
+ I8279(config, m_kdc, 2'000'000);
+ m_kdc->out_irq_callback().set(m_pic8259, FUNC(pic8259_device::ir4_w));
+ m_kdc->out_sl_callback().set([this](uint8_t data) { m_digit = data; });
+ m_kdc->in_rl_callback().set(FUNC(pk11_state::kbd_r)); // kbd RL lines
+ m_kdc->in_shift_callback().set_constant(0); // Shift key
+ m_kdc->in_ctrl_callback().set_constant(0);
+
+ UPD765A(config, m_fdc, 8'000'000, false, false);
+ m_fdc->intrq_wr_callback().set(m_irq1_merger, FUNC(input_merger_any_high_device::in_w<0>));
+ m_fdc->drq_wr_callback().set(*this, FUNC(pk11_state::fdc_drq_w));
+ FLOPPY_CONNECTOR(config, "fdc:0", pk11_floppies, "525qd", pk11_state::floppy_formats);
+ FLOPPY_CONNECTOR(config, "fdc:1", pk11_floppies, "525qd", pk11_state::floppy_formats);
+
+ WD1010(config, m_hdc, 20_MHz_XTAL / 4);
+ m_hdc->out_intrq_callback().set(m_irq1_merger, FUNC(input_merger_any_high_device::in_w<1>));
+ m_hdc->out_bdrq_callback().set(m_hdc, FUNC(wd1010_device::brdy_w));
+ m_hdc->out_bdrq_callback().append([this](int state) {
+ if (state) { m_buf_ptr = ((BIT(m_buf_ptr, 9, 2) + 1) & 3) << 9; }
+ });
+ m_hdc->in_data_callback().set(FUNC(pk11_state::buf_r));
+ m_hdc->out_data_callback().set(FUNC(pk11_state::buf_w));
+ m_hdc->out_bcs_callback().set([this](int state) { if (state) m_buf_dir = false; });
+
+ // Seagate ST-225 formatted with 18 sectors per track
+ HARDDISK(config, m_hdd, 0);
+
+ MC146818(config, m_rtc, 32.768_kHz_XTAL);
+ m_rtc->set_24hrs(true);
+ m_rtc->set_binary(true);
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_screen_update(FUNC(pk11_state::screen_update));
+ m_screen->set_raw(XTAL(16'000'000), PK11_TOTAL_HORZ, PK11_HORZ_START,
+ PK11_HORZ_START+PK11_DISP_HORZ, PK11_TOTAL_VERT, PK11_VERT_START,
+ PK11_VERT_START+PK11_DISP_VERT);
+ m_screen->screen_vblank().set(m_pic8259, FUNC(pic8259_device::ir5_w));
+}
+
+ROM_START(pk11)
+ ROM_REGION16_BE(040000, "maincpu", ROMREGION_ERASE00)
+ ROM_DEFAULT_BIOS("mfm")
+ ROM_SYSTEM_BIOS(0, "mfm", "mfm hdd")
+ ROMX_LOAD("pk11.rom", 0, 040000, CRC(9c877036) SHA1(aba3afcb9a3ffd4093ef5e937b57db0b2686bb31), ROM_BIOS(0))
+ROM_END
+
+} // anonymous namespace
+
+
+/* Driver */
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
+COMP( 1991, pk11, 0, 0, pk11, pk11, pk11_state, empty_init, "USSR", "PK-11/16", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )