Checkpoint

This commit is contained in:
therealmogminer@gmail.com 2016-06-19 17:49:28 +02:00
parent 1905f52ac8
commit ad030cc4f4
6 changed files with 559 additions and 222 deletions

View File

@ -165,6 +165,12 @@ void mb86901_device::device_stop()
void mb86901_device::device_reset()
{
m_queued_tt = 0;
m_queued_priority = 0;
m_asi = 0;
MAE = false;
HOLD_BUS = false;
PC = 0;
nPC = 4;
memset(m_r, 0, sizeof(UINT32) * 120);
@ -699,7 +705,7 @@ bool mb86901_device::execute_group2(UINT32 op)
bool v = ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0);
if (v)
{
queue_trap(sparc_tag_overflow);
trap(SPARC_TAG_OVERFLOW);
}
else
{
@ -716,7 +722,7 @@ bool mb86901_device::execute_group2(UINT32 op)
bool v = ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0);
if (v)
{
queue_trap(sparc_tag_overflow);
trap(SPARC_TAG_OVERFLOW);
}
else
{
@ -795,7 +801,7 @@ bool mb86901_device::execute_group2(UINT32 op)
case 41: // rd psr
if (IS_USER)
{
queue_trap(sparc_privileged_instruction);
trap(SPARC_PRIVILEGED_INSTRUCTION);
}
else
{
@ -805,7 +811,7 @@ bool mb86901_device::execute_group2(UINT32 op)
case 42: // rd wim
if (IS_USER)
{
queue_trap(sparc_privileged_instruction);
trap(SPARC_PRIVILEGED_INSTRUCTION);
}
else
{
@ -815,7 +821,7 @@ bool mb86901_device::execute_group2(UINT32 op)
case 43: // rd tbr
if (IS_USER)
{
queue_trap(sparc_privileged_instruction);
trap(SPARC_PRIVILEGED_INSTRUCTION);
}
else
{
@ -837,14 +843,14 @@ bool mb86901_device::execute_group2(UINT32 op)
case 49: // wr psr
if (IS_USER)
{
queue_trap(sparc_privileged_instruction);
trap(SPARC_PRIVILEGED_INSTRUCTION);
}
else
{
UINT32 new_psr = (arg1 ^ arg2) & ~PSR_ZERO_MASK;
if ((new_psr & PSR_CWP_MASK) >= WINDOW_COUNT)
{
queue_trap(sparc_illegal_instruction);
trap(SPARC_ILLEGAL_INSTRUCTION);
}
else
{
@ -856,7 +862,7 @@ bool mb86901_device::execute_group2(UINT32 op)
case 50: // wr wim
if (IS_USER)
{
queue_trap(sparc_privileged_instruction);
trap(SPARC_PRIVILEGED_INSTRUCTION);
}
else
{
@ -866,7 +872,7 @@ bool mb86901_device::execute_group2(UINT32 op)
case 51: // wr tbr
if (IS_USER)
{
queue_trap(sparc_privileged_instruction);
trap(SPARC_PRIVILEGED_INSTRUCTION);
}
else
{
@ -876,13 +882,13 @@ bool mb86901_device::execute_group2(UINT32 op)
case 52: // FPop1
if (FPU_DISABLED)
{
queue_trap(sparc_floating_point_disabled);
trap(SPARC_FLOATING_POINT_DISABLED);
}
break;
case 53: // FPop2
if (FPU_DISABLED)
{
queue_trap(sparc_floating_point_disabled);
trap(SPARC_FLOATING_POINT_DISABLED);
}
break;
case 56: // jmpl
@ -891,7 +897,7 @@ bool mb86901_device::execute_group2(UINT32 op)
m_icount--;
if (addr & 3)
{
queue_trap(sparc_mem_address_not_aligned);
trap(SPARC_MEM_ADDRESS_NOT_ALIGNED);
}
else
{
@ -909,11 +915,11 @@ bool mb86901_device::execute_group2(UINT32 op)
{
if (IS_USER)
{
queue_trap(sparc_privileged_instruction);
trap(SPARC_PRIVILEGED_INSTRUCTION);
}
else
{
queue_trap(sparc_illegal_instruction);
trap(SPARC_ILLEGAL_INSTRUCTION);
}
break;
}
@ -921,17 +927,17 @@ bool mb86901_device::execute_group2(UINT32 op)
{
if (IS_USER)
{
queue_trap(sparc_reset, sparc_privileged_instruction);
trap(SPARC_RESET, SPARC_PRIVILEGED_INSTRUCTION);
break;
}
else if (m_wim & (1 << new_cwp))
{
queue_trap(sparc_reset, sparc_window_underflow);
trap(SPARC_RESET, SPARC_WINDOW_UNDERFLOW);
break;
}
else if (ADDRESS & 3)
{
queue_trap(sparc_reset, sparc_mem_address_not_aligned);
trap(SPARC_RESET, SPARC_MEM_ADDRESS_NOT_ALIGNED);
break;
}
}
@ -963,7 +969,7 @@ bool mb86901_device::execute_group2(UINT32 op)
UINT8 new_cwp = ((m_cwp + WINDOW_COUNT) - 1) % WINDOW_COUNT;
if (m_wim & (1 << new_cwp))
{
queue_trap(sparc_window_overflow);
trap(SPARC_WINDOW_OVERFLOW);
}
else
{
@ -976,7 +982,7 @@ bool mb86901_device::execute_group2(UINT32 op)
UINT8 new_cwp = (m_cwp + 1) % WINDOW_COUNT;
if (m_wim & (1 << new_cwp))
{
queue_trap(sparc_window_overflow);
trap(SPARC_WINDOW_UNDERFLOW);
}
else
{
@ -985,7 +991,7 @@ bool mb86901_device::execute_group2(UINT32 op)
break;
}
default:
queue_trap(sparc_illegal_instruction);
trap(SPARC_ILLEGAL_INSTRUCTION);
break;
}
@ -1014,17 +1020,17 @@ bool mb86901_device::check_main_traps(UINT32 op, bool privileged, UINT32 alignme
bool trap_queued = false;
if (privileged && !m_s)
{
queue_trap(sparc_privileged_instruction);
trap(SPARC_PRIVILEGED_INSTRUCTION);
trap_queued = true;
}
if (alignment & ADDRESS)
{
queue_trap(sparc_mem_address_not_aligned);
trap(SPARC_MEM_ADDRESS_NOT_ALIGNED);
trap_queued = true;
}
if ((registeralign & RD) || (noimmediate && USEIMM))
{
queue_trap(sparc_illegal_instruction);
trap(SPARC_ILLEGAL_INSTRUCTION);
trap_queued = true;
}
return trap_queued;
@ -1051,21 +1057,44 @@ void mb86901_device::execute_group3(UINT32 op)
switch (OP3)
{
case 0: // ld
{
check_main_traps(op, false, 3, 0, false);
SET_RDREG(read_word(m_data_asi, ADDRESS));
UINT32 result = read_word(m_data_asi, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 1: // ldub
SET_RDREG(read_byte(m_data_asi, ADDRESS));
{
UINT32 result = read_byte(m_data_asi, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 2: // lduh
{
check_main_traps(op, false, 1, 0, false);
SET_RDREG(read_half(m_data_asi, ADDRESS));
UINT32 result = read_half(m_data_asi, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 3: // ldd
{
check_main_traps(op, false, 7, 1, false);
SET_RDREG(read_word(m_data_asi, ADDRESS));
REG(RD+1) = read_word(m_data_asi, ADDRESS+4);
UINT32 result = read_word(m_data_asi, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
result = read_word(m_data_asi, ADDRESS+4);
if (MAE || HOLD_BUS)
break;
REG(RD+1) = result;
break;
}
case 4: // st
check_main_traps(op, false, 3, 0, false);
write_word(m_data_asi, ADDRESS, RDREG);
@ -1080,38 +1109,78 @@ void mb86901_device::execute_group3(UINT32 op)
case 7: // std
check_main_traps(op, false, 7, 1, false);
write_word(m_data_asi, ADDRESS, RDREG);
if (MAE || HOLD_BUS)
break;
write_word(m_data_asi, ADDRESS, REG(RD+1));
break;
case 9: // ldsb
SET_RDREG(read_signed_byte(m_data_asi, ADDRESS));
{
UINT32 result = read_signed_byte(m_data_asi, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 10: // lsdh
{
check_main_traps(op, false, 1, 0, false);
SET_RDREG(read_signed_half(m_data_asi, ADDRESS));
UINT32 result = read_signed_half(m_data_asi, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 13: // ldstub
SET_RDREG(read_byte(m_data_asi, ADDRESS));
{
UINT32 result = read_byte(m_data_asi, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
write_byte(m_data_asi, ADDRESS, 0xff);
break;
}
case 15: // swap, SPARCv8
break;
case 16: // lda
{
check_main_traps(op, true, 3, 0, true);
SET_RDREG(read_word(ASI, ADDRESS));
UINT32 result = read_word(ASI, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 17: // lduba
{
check_main_traps(op, true, 0, 0, true);
SET_RDREG(read_byte(ASI, ADDRESS));
UINT32 result = read_byte(ASI, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 18: // lduha
{
check_main_traps(op, true, 1, 0, true);
SET_RDREG(read_half(ASI, ADDRESS));
UINT32 result = read_half(ASI, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 19: // ldda
{
check_main_traps(op, true, 7, 1, true);
SET_RDREG(read_word(ASI, ADDRESS));
REG(RD+1) = read_word(ASI, ADDRESS+4);
UINT32 result = read_word(ASI, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
result = read_word(ASI, ADDRESS+4);
if (MAE || HOLD_BUS)
break;
REG(RD+1) = result;
break;
}
case 20: // sta
check_main_traps(op, true, 3, 0, true);
write_word(ASI, ADDRESS, RDREG);
@ -1127,36 +1196,67 @@ void mb86901_device::execute_group3(UINT32 op)
case 23: // stda
check_main_traps(op, true, 7, 1, true);
write_word(ASI, ADDRESS, RDREG);
if (MAE || HOLD_BUS)
break;
write_word(ASI, ADDRESS+4, REG(RD+1));
break;
case 25: // ldsba
{
check_main_traps(op, true, 0, 0, true);
SET_RDREG(read_signed_byte(ASI, ADDRESS));
UINT32 result = read_signed_byte(ASI, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 26: // ldsha
{
check_main_traps(op, true, 1, 0, true);
SET_RDREG(read_signed_half(ASI, ADDRESS));
UINT32 result = read_signed_half(ASI, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
break;
}
case 29: // ldstuba
{
check_main_traps(op, true, 0, 0, true);
SET_RDREG(read_byte(ASI, ADDRESS));
UINT32 result = read_byte(ASI, ADDRESS);
if (MAE || HOLD_BUS)
break;
SET_RDREG(result);
write_byte(ASI, ADDRESS, 0xff);
break;
}
case 31: // swapa, SPARCv8
break;
case 32: // ld fpr
if (FPU_DISABLED)
trap(SPARC_FLOATING_POINT_DISABLED);
break;
case 33: // ld fsr
if (FPU_DISABLED)
trap(SPARC_FLOATING_POINT_DISABLED);
break;
case 35: // ldd fpr
if (FPU_DISABLED)
trap(SPARC_FLOATING_POINT_DISABLED);
break;
case 36: // st fpr
if (FPU_DISABLED)
trap(SPARC_FLOATING_POINT_DISABLED);
break;
case 37: // st fsr
if (FPU_DISABLED)
trap(SPARC_FLOATING_POINT_DISABLED);
break;
case 38: // std fq, SPARCv8
if (FPU_DISABLED)
trap(SPARC_FLOATING_POINT_DISABLED);
break;
case 39: // std fpr
if (FPU_DISABLED)
trap(SPARC_FLOATING_POINT_DISABLED);
break;
case 40: // ld cpr, SPARCv8
break;
@ -1174,7 +1274,10 @@ void mb86901_device::execute_group3(UINT32 op)
break;
}
m_icount -= ldst_cycles[OP3];
if (MAE || HOLD_BUS)
m_icount--;
else
m_icount -= ldst_cycles[OP3];
}
@ -1253,7 +1356,7 @@ bool mb86901_device::execute_ticc(UINT32 op)
{
UINT32 arg2 = USEIMM ? SIMM7 : RS2REG;
UINT8 tt = 128 + ((RS1REG + arg2) & 0x7f);
queue_trap(sparc_trap_instruction, tt);
trap(SPARC_TRAP_INSTRUCTION, tt);
m_icount -= 3;
return false;
}
@ -1263,24 +1366,32 @@ bool mb86901_device::execute_ticc(UINT32 op)
//-------------------------------------------------
// queue_trap - flag an incoming trap of a given
// trap - flag an incoming trap of a given
// type
//-------------------------------------------------
void mb86901_device::queue_trap(UINT8 type, UINT8 tt_override)
void mb86901_device::trap(UINT8 type, UINT8 tt_override)
{
if (type == sparc_reset)
if (type == SPARC_RESET)
{
m_queued_priority = m_trap_priorities[0];
m_queued_tt = tt_override;
}
else
{
if (type == sparc_trap_instruction)
if (type == SPARC_TRAP_INSTRUCTION)
{
type = tt_override;
}
if (type >= SPARC_INT1 && type <= SPARC_INT14)
{
if (!ET)
return;
int irl = (type - SPARC_INT1) + 1;
if (irl <= PIL)
return;
}
if (m_trap_priorities[type] < m_queued_priority)
{
m_queued_priority = m_trap_priorities[type];
@ -1302,6 +1413,7 @@ bool mb86901_device::invoke_queued_traps()
if (m_queued_priority > 0)
{
m_queued_priority = 0;
m_queued_tt = 0;
m_et = false;
m_ps = m_s;
@ -1336,8 +1448,20 @@ void mb86901_device::execute_run()
while (m_icount > 0)
{
bool trap_was_queued = invoke_queued_traps();
if (trap_was_queued)
{
m_icount -= 4;
continue;
}
debugger_instruction_hook(this, m_pc);
if (HOLD_BUS)
{
m_icount--;
continue;
}
UINT32 op = GET_OPCODE;
bool update_npc = true;
@ -1390,7 +1514,7 @@ void mb86901_device::execute_run()
REG(0) = 0;
bool trap_taken = invoke_queued_traps();
if (!trap_taken && update_npc)
if (!trap_taken && update_npc && !HOLD_BUS)
{
PC = nPC;
nPC = PC + 4;

View File

@ -9,6 +9,34 @@
#ifndef __SPARC_H__
#define __SPARC_H__
#define SPARC_RESET 0
#define SPARC_INSTRUCTION_ACCESS_EXCEPTION 1
#define SPARC_ILLEGAL_INSTRUCTION 2
#define SPARC_PRIVILEGED_INSTRUCTION 3
#define SPARC_FLOATING_POINT_DISABLED 4
#define SPARC_WINDOW_OVERFLOW 5
#define SPARC_WINDOW_UNDERFLOW 6
#define SPARC_MEM_ADDRESS_NOT_ALIGNED 7
#define SPARC_FLOATING_POINT_EXCEPTION 8
#define SPARC_DATA_ACCESS_EXCEPTION 9
#define SPARC_TAG_OVERFLOW 10
#define SPARC_INT1 17
#define SPARC_INT2 18
#define SPARC_INT3 19
#define SPARC_INT4 20
#define SPARC_INT5 21
#define SPARC_INT6 22
#define SPARC_INT7 23
#define SPARC_INT8 24
#define SPARC_INT9 25
#define SPARC_INT10 26
#define SPARC_INT11 27
#define SPARC_INT12 28
#define SPARC_INT13 29
#define SPARC_INT14 30
#define SPARC_INT15 31
#define SPARC_TRAP_INSTRUCTION 128
class mb86901_device : public cpu_device
{
public:
@ -40,8 +68,12 @@ public:
UINT8 get_asi() { return m_asi; }
UINT32 pc() { return m_pc; }
void trap(UINT8 type, UINT8 tt_override = 0);
void set_mae() { m_mae = true; }
void hold_bus() { m_hold_bus = true; }
void release_bus() { m_hold_bus = false; }
protected:
void queue_trap(UINT8 type, UINT8 tt_override = 0);
bool invoke_queued_traps();
bool check_main_traps(UINT32 op, bool privileged, UINT32 alignment, UINT8 registeralign, bool noimmediate);
@ -103,6 +135,8 @@ protected:
UINT8 m_trap_priorities[256];
UINT8 m_queued_tt;
UINT8 m_queued_priority;
bool m_mae;
bool m_hold_bus;
int m_icount;
// debugger helpers

View File

@ -114,35 +114,9 @@
#define Y m_y
enum sparc_trap_type
{
sparc_reset = 0,
sparc_instruction_access_exception = 1,
sparc_illegal_instruction = 2,
sparc_privileged_instruction = 3,
sparc_floating_point_disabled = 4,
sparc_window_overflow = 5,
sparc_window_underflow = 6,
sparc_mem_address_not_aligned = 7,
sparc_floating_point_exception = 8,
sparc_data_access_exception = 9,
sparc_tag_overflow = 10,
sparc_int1 = 17,
sparc_int2 = 18,
sparc_int3 = 19,
sparc_int4 = 20,
sparc_int5 = 21,
sparc_int6 = 22,
sparc_int7 = 23,
sparc_int8 = 24,
sparc_int9 = 25,
sparc_int10 = 26,
sparc_int11 = 27,
sparc_int12 = 28,
sparc_int13 = 29,
sparc_int14 = 30,
sparc_int15 = 31,
sparc_trap_instruction = 128
};
#define ET m_et
#define PIL m_pil
#define MAE m_mae
#define HOLD_BUS m_hold_bus
#endif // __MB86901_DEFS_H__

View File

@ -447,7 +447,7 @@ void scc8530_t::set_reg_a(int reg, UINT8 data)
/*-------------------------------------------------
scc8530_set_reg_a
scc8530_set_reg_b
-------------------------------------------------*/
void scc8530_t::set_reg_b(int reg, UINT8 data)
@ -457,46 +457,41 @@ void scc8530_t::set_reg_b(int reg, UINT8 data)
/*-------------------------------------------------
scc8530_r
-------------------------------------------------*/
//-------------------------------------------------
// reg_r - read handler, trampolines into normal
// getter
//-------------------------------------------------
READ8_MEMBER( scc8530_t::reg_r)
READ8_MEMBER(scc8530_t::reg_r)
{
UINT8 result = 0;
return read_reg(offset & 3);
}
offset %= 4;
//-------------------------------------------------
// read_reg - reads either the control or data
// port for either SCC channel.
//-------------------------------------------------
UINT8 scc8530_t::read_reg(int offset)
{
switch(offset)
{
case 0:
/* Channel B (Printer Port) Control */
case 0: /* Channel B (Printer Port) Control */
case 1: /* Channel A (Modem Port) Control */
if (mode == 1)
mode = 0;
else
reg = 0;
result = getbreg();
result = (offset == 0) ? getbreg(); : getareg()
break;
case 1:
/* Channel A (Modem Port) Control */
if (mode == 1)
mode = 0;
else
reg = 0;
result = getareg();
break;
case 2:
/* Channel B (Printer Port) Data */
result = channel[1].rxData;
break;
case 3:
/* Channel A (Modem Port) Data */
result = channel[0].rxData;
case 2: /* Channel B (Printer Port) Data */
case 3:/* Channel A (Modem Port) Data */
result = channel[offset == 2 ? 1 : 0].rxData;
break;
}
return result;
@ -504,116 +499,85 @@ READ8_MEMBER( scc8530_t::reg_r)
/*-------------------------------------------------
scc8530_w
-------------------------------------------------*/
//-------------------------------------------------
// reg_w - write handler, trampolines into normal
// setter
//-------------------------------------------------
WRITE8_MEMBER( scc8530_t::reg_w )
{
Chan *pChan;
write_reg(offset & 3, data);
}
offset &= 3;
//-------------------------------------------------
// write_reg - writes either the control or data
// port for either SCC channel.
//-------------------------------------------------
void scc8530_t::write_reg(int offset, UINT8 data)
{
offset & 3;
// printf(" mode %d data %x offset %d \n", mode, data, offset);
Chan *pChan;
switch(offset)
{
case 0:
/* Channel B (Printer Port) Control */
case 0: /* Channel B (Printer Port) Control */
case 1: /* Channel A (Modem Port) Control */
{
int chan = ((offset == 2) ? 1 : 0);
if (mode == 0)
{
if((data & 0xf0) == 0) // not a reset command
{
mode = 1;
reg = data & 0x0f;
// putbreg(data & 0xf0);
// putbreg(data & 0xf0);
}
else if (data == 0x10)
{
pChan = &channel[1];
// clear ext. interrupts
pChan->extIRQPending = 0;
pChan->baudIRQPending = 0;
channel[chan].extIRQPending = 0;
channel[chan].baudIRQPending = 0;
updateirqs();
}
}
else
{
mode = 0;
putreg(1, data);
putreg(chan, data);
}
break;
}
case 1:
/* Channel A (Modem Port) Control */
if (mode == 0)
case 2: /* Channel B (Printer Port) Data */
case 3: /* Channel A (Modem Port) Data */
{
int chan = ((offset == 2) ? 1 : 0);
if (channel[chan].txEnable)
{
if((data & 0xf0) == 0) // not a reset command
{
mode = 1;
reg = data & 0x0f;
// putareg(data & 0xf0);
}
else if (data == 0x10)
{
pChan = &channel[0];
// clear ext. interrupts
pChan->extIRQPending = 0;
pChan->baudIRQPending = 0;
updateirqs();
}
}
else
{
mode = 0;
putreg(0, data);
}
break;
case 2:
/* Channel B (Printer Port) Data */
pChan = &channel[1];
if (pChan->txEnable)
{
pChan->txData = data;
channel[chan].txData = data;
// local loopback?
if (pChan->reg_val[14] & 0x10)
if (channel[chan].reg_val[14] & 0x10)
{
pChan->rxData = data;
pChan->reg_val[0] |= 0x01; // Rx character available
channel[chan].rxData = data;
channel[chan].reg_val[0] |= 0x01; // Rx character available
}
pChan->reg_val[1] |= 0x01; // All sent
pChan->reg_val[0] |= 0x04; // Tx empty
pChan->txUnderrun = 1;
pChan->txIRQPending = 1;
updateirqs();
}
break;
case 3:
/* Channel A (Modem Port) Data */
pChan = &channel[0];
if (pChan->txEnable)
{
pChan->txData = data;
// local loopback?
if (pChan->reg_val[14] & 0x10)
{
pChan->rxData = data;
pChan->reg_val[0] |= 0x01; // Rx character available
}
pChan->reg_val[1] |= 0x01; // All sent
pChan->reg_val[0] |= 0x04; // Tx empty
pChan->txUnderrun = 1;
pChan->txIRQPending = 1;
channel[chan].reg_val[1] |= 0x01; // All sent
channel[chan].reg_val[0] |= 0x04; // Tx empty
channel[chan].txUnderrun = 1;
channel[chan].txIRQPending = 1;
updateirqs();
}
break;
}
}
}
/*
AppleTalk check:

View File

@ -43,6 +43,9 @@ public:
DECLARE_READ8_MEMBER(reg_r);
DECLARE_WRITE8_MEMBER(reg_w);
void write_reg(int offset, UINT8 data);
UINT8 read_reg(int offset);
protected:
virtual void device_start() override;
virtual void device_reset() override;

View File

@ -387,6 +387,8 @@
#include "emu.h"
#include "cpu/sparc/sparc.h"
#include "machine/z80scc.h"
#include "bus/rs232/rs232.h"
#define ENA_NOTBOOT 0x80
#define ENA_SDVMA 0x20
@ -394,6 +396,22 @@
#define ENA_RESET 0x04
#define ENA_DIAG 0x01
#define SCC1_TAG "kbdmouse"
#define SCC2_TAG "uart"
#define RS232A_TAG "rs232a"
#define RS232B_TAG "rs232b"
#define ASI_SYSTEM_SPACE 2
#define ASI_SEGMENT_MAP 3
#define ASI_PAGE_MAP 4
#define ASI_USER_INSN 8
#define ASI_SUPER_INSN 9
#define ASI_USER_DATA 10
#define ASI_SUPER_DATA 11
#define ASI_FLUSH_SEGMENT 12
#define ASI_FLUSH_PAGE 13
#define ASI_FLUSH_CONTEXT 14
class sun4_state : public driver_device
{
public:
@ -401,7 +419,10 @@ public:
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_rom(*this, "user1")
, m_kbdmouse(*this, SCC1_TAG)
, m_uart(*this, SCC2_TAG)
, m_rom_ptr(nullptr)
, m_context(0)
, m_system_enable(0)
{
}
@ -416,39 +437,172 @@ protected:
required_device<mb86901_device> m_maincpu;
required_memory_region m_rom;
required_device<z80scc_device> m_kbdmouse;
required_device<z80scc_device> m_uart;
UINT32 read_supervisor_data(UINT32 vaddr, UINT32 mem_mask);
void write_supervisor_data(UINT32 vaddr, UINT32 data, UINT32 mem_mask);
UINT32 *m_rom_ptr;
UINT32 m_context;
UINT16 m_segmap[8][4096];
UINT32 m_pagemap[8192];
UINT32 m_system_enable;
};
#define SEGMENT(vaddr) m_segmap[m_context & 7][((vaddr) >> 18) & 0xfff]
#define PAGE(vaddr) m_pagemap[((m_segmap[m_context & 7][((vaddr) >> 18) & 0xfff] & 0x7f) << 6) | (((vaddr) >> 12) & 0x3f)]
#define PADDR(vaddr) (((PAGE(vaddr) << 12) & 0x0ffff000) | ((vaddr) & 0xfff))
UINT32 sun4_state::read_supervisor_data(UINT32 vaddr, UINT32 mem_mask)
{
UINT32 page = PAGE(vaddr);
bool v = (page & 0x80000000) ? true : false;
bool w = (page & 0x40000000) ? true : false;
bool s = (page & 0x20000000) ? true : false;
bool x = (page & 0x10000000) ? true : false;
int t = (page & 0x0c000000) >> 26;
bool a = (page & 0x02000000) ? true : false;
bool m = (page & 0x01000000) ? true : false;
char mode[4] = { 'M', 'S', '0', '1' };
logerror("supervisor data read: vaddr %08x, paddr %08x, context %d, segment entry %02x, page entry %08x, %c%c%c%c%c%c%c\n", vaddr, PADDR(vaddr), m_context, SEGMENT(vaddr), PAGE(vaddr)
, v ? 'V' : 'v', w ? 'W' : 'w', s ? 'S' : 's', x ? 'X' : 'x', mode[t], a ? 'A' : 'a', m ? 'M' : 'm');
return 0;
}
void sun4_state::write_supervisor_data(UINT32 vaddr, UINT32 data, UINT32 mem_mask)
{
UINT32 page = PAGE(vaddr);
bool v = (page & 0x80000000) ? true : false;
bool w = (page & 0x40000000) ? true : false;
bool s = (page & 0x20000000) ? true : false;
bool x = (page & 0x10000000) ? true : false;
int t = (page & 0x0c000000) >> 26;
bool a = (page & 0x02000000) ? true : false;
bool m = (page & 0x01000000) ? true : false;
char mode[4] = { 'M', 'S', '0', '1' };
logerror("supervisor data write: vaddr %08x, paddr %08x, data %08x, mem_mask %08x, context %d, segment entry %02x, page entry %08x, %c%c%c%c%c%c%c\n", vaddr, PADDR(vaddr), data, mem_mask,
m_context, SEGMENT(vaddr), PAGE(vaddr), v ? 'V' : 'v', w ? 'W' : 'w', s ? 'S' : 's', x ? 'X' : 'x', mode[t], a ? 'A' : 'a', m ? 'M' : 'm');
}
READ32_MEMBER( sun4_state::sun4_mmu_r )
{
UINT8 asi = m_maincpu->get_asi();
if (asi == 2 && !space.debugger_access())
if (!space.debugger_access())
{
switch (offset >> 26)
switch(asi)
{
case 3: // context reg
return m_context;
case ASI_SYSTEM_SPACE:
switch (offset >> 26)
{
case 3: // context reg
logerror("sun4: read context register %08x (& %08x) asi 2, offset %x, PC = %x\n", m_context << 24, mem_mask, offset << 2, m_maincpu->pc());
return m_context << 24;
case 4: // system enable reg
return m_system_enable;
case 4: // system enable reg
logerror("sun4: read system enable register %08x (& %08x) asi 2, offset %x, PC = %x\n", m_system_enable << 24, mem_mask, offset << 2, m_maincpu->pc());
return m_system_enable << 24;
case 6: // bus error register
return 0;
case 8: // (d-)cache tags
logerror("sun4: read dcache tags %08x (& %08x) asi 2, offset %x, PC = %x\n", 0xffffffff, mem_mask, offset << 2, m_maincpu->pc());
return 0xffffffff;
case 8: // (d-)cache tags
logerror("sun4: read dcache tags @ %x, PC = %x\n", offset, m_maincpu->pc());
return 0xffffffff;
case 9: // (d-)cache data
logerror("sun4: read dcache data %08x (& %08x) asi 2, offset %x, PC = %x\n", 0xffffffff, mem_mask, offset << 2, m_maincpu->pc());
return 0xffffffff;
case 9: // (d-)cache data
logerror("sun4: read dcache data @ %x, PC = %x\n", offset, m_maincpu->pc());
return 0xffffffff;
case 15: // Type 1 space passthrough
switch ((offset >> 22) & 15)
{
case 0: // keyboard/mouse
switch (offset & 1)
{
case 0:
{
UINT32 ret = 0;
if (mem_mask & 0xffff0000)
ret |= m_kbdmouse->cb_r(space, 0) << 24;
if (mem_mask & 0x0000ffff)
ret |= m_kbdmouse->db_r(space, 0) << 8;
return ret;
}
case 1:
{
UINT32 ret = 0;
if (mem_mask & 0xffff0000)
ret |= m_kbdmouse->ca_r(space, 0) << 24;
if (mem_mask & 0x0000ffff)
ret |= m_kbdmouse->da_r(space, 0) << 8;
return ret;
}
}
break;
case 1: // serial ports
switch (offset & 1)
{
case 0:
{
UINT32 ret = 0;
if (mem_mask & 0xffff0000)
ret |= m_uart->cb_r(space, 0) << 24;
if (mem_mask & 0x0000ffff)
ret |= m_uart->db_r(space, 0) << 8;
return ret;
}
case 1:
{
UINT32 ret = 0;
if (mem_mask & 0xffff0000)
ret |= m_uart->ca_r(space, 0) << 24;
if (mem_mask & 0x0000ffff)
ret |= m_uart->da_r(space, 0) << 8;
return ret;
}
}
break;
default:
logerror("sun4: read unknown type 1 space at address %x (& %08x) asi 2, offset %x, PC = %x\n", offset << 2, mem_mask, offset << 2, m_maincpu->pc());
}
break;
case 0: // IDPROM - TODO: SPARCstation-1 does not have an ID prom and a timeout should occur.
default:
logerror("sun4: read unknown register (& %08x) asi 2, offset %x, PC = %x\n", mem_mask, offset << 2, m_maincpu->pc());
return 0;
}
break;
case ASI_SEGMENT_MAP:
{
logerror("sun4: read m_segmap[%d][(%08x >> 18) & 0xfff = %03x] = %08x << 24 & %08x\n", m_context & 7, offset << 2, (offset >> 16) & 0xfff, SEGMENT(offset << 2), mem_mask);
UINT32 result = SEGMENT(offset << 2);
while (!(mem_mask & 1))
{
mem_mask >>= 1;
result <<= 1;
}
return result;
}
case ASI_PAGE_MAP: // page map
{
logerror("sun4: read m_pagemap[(m_segmap[%d][(%08x >> 18) & 0xfff = %03x] = %08x << 6) | ((%08x >> 12) & 0x3f)]] = %08x & %08x\n", m_context & 7, offset << 2, (offset >> 16) & 0xfff, SEGMENT(offset << 2), offset << 2, PAGE(offset << 2), mem_mask);
return PAGE(offset << 2);
}
case ASI_SUPER_INSN: // supervisor instruction space
return m_rom_ptr[offset & 0x1ffff]; // wrong, but works for now
case ASI_SUPER_DATA:
return read_supervisor_data(offset << 2, mem_mask);
case 0: // IDPROM - TODO: SPARCstation-1 does not have an ID prom and a timeout should occur.
default:
return 0;
logerror("sun4: read (& %08x) asi %d byte offset %x, PC = %x\n", mem_mask, asi, offset << 2, m_maincpu->pc());
break;
}
}
@ -456,10 +610,6 @@ READ32_MEMBER( sun4_state::sun4_mmu_r )
{
return m_rom_ptr[offset & 0x1ffff];
}
else if (asi < 8 || asi > 11)
{
logerror("sun4: read asi %d byte offset %x, PC = %x\n", asi, offset << 2, m_maincpu->pc());
}
return 0;
}
@ -468,34 +618,107 @@ WRITE32_MEMBER( sun4_state::sun4_mmu_w )
{
UINT8 asi = m_maincpu->get_asi();
if (asi == 2)
switch (asi)
{
switch (offset >> 26)
case 2:
switch (offset >> 26)
{
case 3: // context reg
logerror("sun4: %08x (& %08x) asi 2 to context register, offset %x, PC = %x\n", data, mem_mask, offset << 2, m_maincpu->pc());
m_context = (UINT8)(data >> 24) & 7;
return;
case 4: // system enable reg
logerror("sun4: write %08x (& %08x) asi 2 to system enable register, offset %x, PC = %x\n", data, mem_mask, offset << 2, m_maincpu->pc());
m_system_enable = (UINT8)data;
return;
case 8: // cache tags
logerror("sun4: write %08x (& %08x) asi 2 to cache tags @ %x, PC = %x\n", data, mem_mask, offset << 2, m_maincpu->pc());
return;
case 9: // cache data
logerror("sun4: write %08x (& %08x) asi 2 to cache data @ %x, PC = %x\n", data, mem_mask, offset << 2, m_maincpu->pc());
return;
case 15: // Type 1 space passthrough
switch ((offset >> 22) & 15)
{
case 0: // keyboard/mouse
switch (offset & 1)
{
case 0:
if (mem_mask & 0xffff0000)
m_kbdmouse->cb_w(space, 0, data >> 24);
if (mem_mask & 0x0000ffff)
m_kbdmouse->db_w(space, 0, data >> 24);
break;
case 1:
if (mem_mask & 0xffff0000)
m_kbdmouse->ca_w(space, 0, data >> 24);
if (mem_mask & 0x0000ffff)
m_kbdmouse->da_w(space, 0, data >> 24);
break;
}
break;
case 1: // serial ports
switch (offset & 1)
{
case 0:
if (mem_mask & 0xffff0000)
m_uart->cb_w(space, 0, data >> 24);
if (mem_mask & 0x0000ffff)
m_uart->db_w(space, 0, data >> 24);
break;
case 1:
if (mem_mask & 0xffff0000)
m_uart->ca_w(space, 0, data >> 24);
if (mem_mask & 0x0000ffff)
m_uart->da_w(space, 0, data >> 24);
break;
}
break;
default:
logerror("sun4: write unknown type 1 space %08x (& %08x) asi 2, offset %x, PC = %x\n", data, mem_mask, offset << 2, m_maincpu->pc());
}
break;
case 0: // IDPROM
default:
logerror("sun4: write %08x (& %08x) asi 2 to unknown register, offset %x, PC = %x\n", data, mem_mask, offset << 2, m_maincpu->pc());
return;
}
break;
case 3: // segment map
offset <<= 2;
while (!(mem_mask & 1))
{
mem_mask >>= 1;
data >>= 1;
}
SEGMENT(offset) = data;
//m_segmap[m_context & 7][(offset >> 18) & 0xfff] &= ~(mem_mask >> 16);
//m_segmap[m_context & 7][(offset >> 18) & 0xfff] |= (data >> 16) & (mem_mask >> 16);
logerror("sun4: write m_segmap[%d][(%08x >> 18) & 0xfff = %03x] = %08x & %08x\n", m_context & 7, offset << 2, (offset >> 16) & 0xfff, data, mem_mask);
break;
case ASI_PAGE_MAP: // page map
{
case 3: // context reg
m_context = (UINT8)data;
return;
case 4: // system enable reg
m_system_enable = (UINT8)data;
return;
case 8: // cache tags
logerror("sun4: %08x to cache tags @ %x, PC = %x\n", data, offset, m_maincpu->pc());
return;
case 9: // cache data
logerror("sun4: %08x to cache data @ %x, PC = %x\n", data, offset, m_maincpu->pc());
return;
case 0: // IDPROM
default:
return;
logerror("sun4: write m_pagemap[(m_segmap[%d][(%08x >> 18) & 0xfff = %03x] = %08x << 6) | ((%08x >> 12) & 0x3f)]] = %08x & %08x\n", m_context & 7, offset << 2,
(offset >> 16) & 0xfff, SEGMENT(offset << 2), offset << 2, data, mem_mask);
COMBINE_DATA(&PAGE(offset << 2));
PAGE(offset << 2) &= 0xff00ffff;
break;
}
}
else if (asi < 8 || asi > 11)
{
logerror("sun4: %08x to asi %d byte offset %x, PC = %x\n", data, asi, offset << 2, m_maincpu->pc());
case ASI_SUPER_DATA:
write_supervisor_data(offset << 2, data, mem_mask);
break;
default:
logerror("sun4: write %08x (& %08x) to asi %d byte offset %x, PC = %x\n", data, mem_mask, asi, offset << 2, m_maincpu->pc());
break;
}
}
@ -521,6 +744,21 @@ static MACHINE_CONFIG_START( sun4, sun4_state )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", MB86901, 16670000)
MCFG_DEVICE_ADDRESS_MAP(AS_PROGRAM, sun4_mem)
MCFG_SCC8530_ADD(SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0)
MCFG_SCC8530_ADD(SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0)
MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(RS232A_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(RS232B_TAG, rs232_port_device, write_txd))
MCFG_RS232_PORT_ADD(RS232A_TAG, default_rs232_devices, nullptr)
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, rxa_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, dcda_w))
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, ctsa_w))
MCFG_RS232_PORT_ADD(RS232B_TAG, default_rs232_devices, nullptr)
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, rxb_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, dcdb_w))
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, ctsb_w))
MACHINE_CONFIG_END
/*