tidy up for pull request

This commit is contained in:
Patrick Mackinlay 2017-01-24 20:19:26 +07:00
parent 17e3abc6b7
commit 24dba19f8c
5 changed files with 480 additions and 406 deletions

File diff suppressed because it is too large Load Diff

View File

@ -137,6 +137,7 @@ enum clipper_exception_vectors
EXCEPTION_INTERRUPT_BASE = 0x800,
};
// trap source values are shifted into the correct field in the psw
enum clipper_cpu_trap_sources
{
CTS_NO_CPU_TRAP = 0 << 24,
@ -157,6 +158,10 @@ enum clipper_memory_trap_sources
MTS_WRITE_PROTECT_FAULT = 7 << 28,
};
// convenience macros for frequently used instruction fields
#define R1 (m_info.r1)
#define R2 (m_info.r2)
// convenience macros for dealing with the psw
#define PSW(mask) (m_psw & PSW_##mask)
#define SSW(mask) (m_ssw & SSW_##mask)
@ -176,27 +181,27 @@ enum clipper_memory_trap_sources
#define UF_SUB(a, b) ((b > 0) && (a < INT_MIN + b))
// CLIPPER logic for carry and overflow flags
#define C_ADD(a, b) ((uint32_t)a + (uint32_t)b < (uint32_t)a)
#define V_ADD(a, b) (OF_ADD((int32_t)a, (int32_t)b) || UF_ADD((int32_t)a, (int32_t)b))
#define C_SUB(a, b) ((uint32_t)a < (uint32_t)b)
#define V_SUB(a, b) (OF_SUB((int32_t)a, (int32_t)b) || UF_SUB((int32_t)a, (int32_t)b))
#define C_ADD(a, b) ((u32)a + (u32)b < (u32)a)
#define V_ADD(a, b) (OF_ADD((s32)a, (s32)b) || UF_ADD((s32)a, (s32)b))
#define C_SUB(a, b) ((u32)a < (u32)b)
#define V_SUB(a, b) (OF_SUB((s32)a, (s32)b) || UF_SUB((s32)a, (s32)b))
class clipper_device : public cpu_device
{
public:
clipper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
clipper_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, u32 clock, const char *shortname, const char *source);
DECLARE_READ_LINE_MEMBER(ssw) { return m_ssw; }
bool supervisor_mode() { return SSW(U) == 0; }
bool mapped_mode() { return SSW(M) != 0; }
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// device_execute_interface overrides
virtual uint32_t execute_min_cycles() const override { return 1; };
virtual uint32_t execute_max_cycles() const override { return 1; }; // FIXME: don't know, especially macro instructions
virtual uint32_t execute_input_lines() const override { return 2; }; // number of input/interrupt lines (irq/nmi)
virtual u32 execute_min_cycles() const override { return 1; };
virtual u32 execute_max_cycles() const override { return 1; }; // FIXME: don't know, especially macro instructions
virtual u32 execute_input_lines() const override { return 2; }; // number of input/interrupt lines (irq/nmi)
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
@ -213,17 +218,17 @@ protected:
// device_disasm_interface overrides
virtual uint32_t disasm_min_opcode_bytes() const override { return 2; } // smallest instruction
virtual uint32_t disasm_max_opcode_bytes() const override { return 8; } // largest instruction
virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) override;
// core registers
uint32_t m_pc;
uint32_t m_psw;
uint32_t m_ssw;
u32 m_pc;
u32 m_psw;
u32 m_ssw;
// integer registers
int32_t *m_r; // active registers
int32_t m_ru[16]; // user registers
int32_t m_rs[16]; // supervisor registers
s32 *m_r; // active registers
s32 m_ru[16]; // user registers
s32 m_rs[16]; // supervisor registers
// floating registers
double m_f[16];
@ -236,37 +241,54 @@ private:
address_space *m_data;
int m_icount;
int m_interrupt_cycles;
int m_irq;
int m_nmi;
// decoded instruction information
struct
{
// decoded operand information
union {
int32_t imm;
uint32_t r2 : 4;
uint16_t macro;
} op;
u8 opcode, subopcode;
u8 r1, r2;
s32 imm;
u16 macro;
// total size of instruction in bytes
uint32_t size;
u32 size;
// computed effective address
uint32_t address;
u32 address;
} m_info;
void clipper_device::decode_instruction(uint16_t insn);
int clipper_device::execute_instruction(uint16_t insn);
void clipper_device::decode_instruction(u16 insn);
int clipper_device::execute_instruction();
bool clipper_device::evaluate_branch();
// condition code evaluation
void clipper_device::evaluate_cc2f(double v0, double v1);
bool clipper_device::evaluate_branch(uint32_t condition);
uint32_t clipper_device::intrap(uint32_t vector, uint32_t pc, uint32_t cts = CTS_NO_CPU_TRAP, uint32_t mts = MTS_NO_MEMORY_TRAP);
uint32_t clipper_device::intrap(u32 vector, u32 pc, u32 cts = CTS_NO_CPU_TRAP, u32 mts = MTS_NO_MEMORY_TRAP);
};
extern const device_type CLIPPER;
class clipper_c100_device : public clipper_device
{
public:
clipper_c100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
class clipper_c300_device : public clipper_device
{
public:
clipper_c300_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
class clipper_c400_device : public clipper_device
{
public:
clipper_c400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
extern const device_type CLIPPER_C100;
extern const device_type CLIPPER_C300;
extern const device_type CLIPPER_C400;
extern CPU_DISASSEMBLE(clipper);
#endif /* __CLIPPER_H__ */

View File

@ -5,10 +5,10 @@
/*
* TODO
* * dynamically switch between C400 and C100/C300 instruction sets
* * handle failures of addressing mode decoding more elegantly
* * improve address decoding to use streams
* * detect various cases of illegal instruction encoding
* - dynamically switch between C400 and C100/C300 instruction sets
* - handle failures of addressing mode decoding more elegantly
* - improve address decoding to use streams
* - detect various cases of illegal instruction encoding
*/
// enable C400 instruction decoding
@ -72,7 +72,7 @@ static const char *const cc[] =
/*
* Decode an addressing mode into a string.
*/
char *address (offs_t pc, uint16_t *insn)
char *address (offs_t pc, u16 *insn)
{
static char buffer[32];
@ -102,8 +102,8 @@ char *address (offs_t pc, uint16_t *insn)
*/
CPU_DISASSEMBLE(clipper)
{
uint16_t *insn = (uint16_t *)oprom;
uint32_t flags = DASMFLAG_SUPPORTED;
u16 *insn = (u16 *)oprom;
u32 flags = DASMFLAG_SUPPORTED;
offs_t bytes;
switch (insn[0] >> 8)
@ -310,7 +310,7 @@ CPU_DISASSEMBLE(clipper)
case 0x3f: util::stream_format(stream, "loadfs r%d,f%d", (insn[1] & 0xf0) >> 4, insn[1] & 0xf); break;
default:
util::stream_format(stream, "macro 0x%04x 0x%04x ; invalid", insn[0], insn[1]);
util::stream_format(stream, "macro 0x%04x 0x%04x", insn[0], insn[1]);
break;
}
bytes = 4;
@ -330,7 +330,7 @@ CPU_DISASSEMBLE(clipper)
case 0x07: util::stream_format(stream, "loadts r%d,f%d", (insn[1] & 0xf0) >> 4, insn[1] & 0xf); break;
#endif
default:
util::stream_format(stream, "macro 0x%04x %04x", insn[0], insn[1]);
util::stream_format(stream, "macro 0x%04x 0x%04x", insn[0], insn[1]);
break;
}
bytes = 4;

View File

@ -1,30 +1,72 @@
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
/*
* An implementation of the Fairchild/Intergraph Cache and Memory Management Unit (CAMMU) designed for use with the CLIPPER CPU family.
*
* Primary reference: http://bitsavers.trailing-edge.com/pdf/fairchild/clipper/CLIPPER%20C300%2032-Bit%20Compute%20Engine.pdf
* Another reference: http://www.eecs.berkeley.edu/Pubs/TechRpts/1986/CSD-86-289.pdf
*
* This implementation is currently at a very early stage, and is only sufficient to handle the bare minimum of boot/diagnostic code.
*
* TODO
* - almost everything
* - map registers
* - refactor hardware tlb
* - address translation
* - faults
* - tlb
* - cache
* - bus errors
*/
#include "cammu.h"
#define VERBOSE 0
// each variant of the cammu has different registers and a different addressing map
// TODO: decode the cammu registers properly
DEVICE_ADDRESS_MAP_START(map, 32, cammu_device)
DEVICE_ADDRESS_MAP_START(map, 32, cammu_c4t_device)
AM_RANGE(0x000, 0xfff) AM_READWRITE(cammu_r, cammu_w)
ADDRESS_MAP_END
const device_type CAMMU = &device_creator<cammu_device>;
DEVICE_ADDRESS_MAP_START(map, 32, cammu_c4i_device)
AM_RANGE(0x000, 0xfff) AM_READWRITE(cammu_r, cammu_w)
ADDRESS_MAP_END
cammu_device::cammu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, CAMMU, "Cache and MMU", tag, owner, clock, "cammu", __FILE__)
DEVICE_ADDRESS_MAP_START(map, 32, cammu_c3_device)
AM_RANGE(0x000, 0xfff) AM_READWRITE(cammu_r, cammu_w)
ADDRESS_MAP_END
const device_type CAMMU_C4T = &device_creator<cammu_c4t_device>;
const device_type CAMMU_C4I = &device_creator<cammu_c4i_device>;
const device_type CAMMU_C3 = &device_creator<cammu_c3_device>;
cammu_c4t_device::cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cammu_device(mconfig, CAMMU_C4T, "C4E/C4T CAMMU", tag, owner, clock, "C4T", __FILE__) { }
cammu_c4i_device::cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cammu_device(mconfig, CAMMU_C4I, "C4I CAMMU", tag, owner, clock, "C4I", __FILE__) { }
cammu_c3_device::cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cammu_device(mconfig, CAMMU_C4T, "C1/C3 CAMMU", tag, owner, clock, "C3", __FILE__) { }
cammu_device::cammu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, const char *shortname, const char *source)
: device_t(mconfig, type, name, tag, owner, clock, shortname, source)
, device_memory_interface(mconfig, *this),
m_main_space_config("main", ENDIANNESS_LITTLE, 32, 32, 0),
m_io_space_config("io", ENDIANNESS_LITTLE, 32, 32, 0),
m_boot_space_config("boot", ENDIANNESS_LITTLE, 32, 32, 0),
m_main_space(nullptr),
m_io_space(nullptr),
m_boot_space(nullptr)
m_boot_space(nullptr),
m_ssw_func(*this)
{ }
void cammu_device::device_start()
{
m_ssw_func.resolve_safe(0);
m_main_space = &space(AS_0);
m_io_space = &space(AS_1);
m_boot_space = &space(AS_2);
@ -48,70 +90,91 @@ const address_space_config *cammu_device::memory_space_config (address_spacenum
READ32_MEMBER(cammu_device::mmu_r)
{
// handle htlb
u32 ssw = m_ssw_func();
u32 address = offset << 2;
//if (m_maincpu->supervisor_mode() && (offset & ~0x1FFF) == 0)
if ((offset & ~0x1FFF) == 0)
// in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb
if ((ssw & 0x40000000) == 0 && (address & ~0x7fff) == 0)
{
switch (offset & 0x3C00)
switch (address & 0xf000)
{
case 0x000:
case 0x400:
case 0x800:
case 0xC00:
return m_main_space->read_dword(offset << 2, mem_mask);
case 0x0000:
case 0x1000:
case 0x1400:
return m_io_space->read_dword((offset & 0x7ff) << 2, mem_mask);
case 0x2000:
case 0x3000:
// pages 0-3: main space pages 0-3
return m_main_space->read_dword(address, mem_mask);
case 0x1800:
case 0x1C00:
return m_boot_space->read_dword((offset & 0x7ff) << 2, mem_mask);
case 0x4000:
case 0x5000:
// pages 4-5: i/o space pages 0-1
return m_io_space->read_dword(address & 0x1fff, mem_mask);
case 0x6000:
case 0x7000:
// pages 6-7: boot space pages 0-1
return m_boot_space->read_dword(address & 0x1fff, mem_mask);
}
}
// address with upper bytes 0 or 0x7f1
if ((offset >> 22) == 0x00 || (offset >> 18) == 0x7f1)
return m_main_space->read_dword(offset << 2, mem_mask);
// FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O
if ((address & 0xff000000) == 0x00000000 || (address & 0xfff00000) == 0x7f100000)
{
#ifdef ICACHE_ENTRIES
// if this is an instruction fetch, check the cache first
if (space.spacenum() == AS_PROGRAM)
{
if (m_icache[offset & (ICACHE_ENTRIES-1)].offset != offset)
{
m_icache[offset & (ICACHE_ENTRIES - 1)].offset = offset;
m_icache[offset & (ICACHE_ENTRIES - 1)].data = m_main_space->read_dword(address, mem_mask);
}
return m_icache[offset & (ICACHE_ENTRIES - 1)].data;
}
else
#endif
return m_main_space->read_dword(address, mem_mask);
}
else
return m_io_space->read_dword(offset << 2, mem_mask);
return m_io_space->read_dword(address, mem_mask);
}
WRITE32_MEMBER(cammu_device::mmu_w)
{
// handle htlb
//if (m_maincpu->supervisor_mode() && (offset & ~0x1FFF) == 0)
if ((offset & ~0x1FFF) == 0)
u32 ssw = m_ssw_func();
u32 address = offset << 2;
// in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb
if ((ssw & 0x40000000) == 0 && (address & ~0x7fff) == 0)
{
switch (offset & 0x3C00)
switch (address & 0xf000)
{
case 0x000:
case 0x400:
case 0x800:
case 0xC00:
// pages 0-3: main space
m_main_space->write_dword(offset << 2, data, mem_mask);
return;
case 0x0000:
case 0x1000:
case 0x1400:
// pages 4-5: pages 0-1 i/o space
m_io_space->write_dword((offset & 0x7ff) << 2, data, mem_mask);
case 0x2000:
case 0x3000:
// pages 0-3: main space pages 0-3
m_main_space->write_dword(address, data, mem_mask);
return;
case 0x1800:
case 0x1C00:
// pages 6-7: pages 0-1 boot space
m_boot_space->write_dword((offset & 0x7ff) << 2, data, mem_mask);
case 0x4000:
case 0x5000:
// pages 4-5: i/o space pages 0-1
m_io_space->write_dword(address & 0x1fff, data, mem_mask);
return;
case 0x6000:
case 0x7000:
// pages 6-7: boot space pages 0-1
m_boot_space->write_dword(address & 0x1fff, data, mem_mask);
return;
}
}
// address with upper byte 0x00 or upper 3 bytes 0x7f1
if ((offset >> 22) == 0x00 || (offset >> 18) == 0x7f1)
m_main_space->write_dword(offset << 2, data, mem_mask);
// FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O
if ((address & 0xff000000) == 0x00000000 || (address & 0xfff00000) == 0x7f100000)
m_main_space->write_dword(address, data, mem_mask);
else
m_io_space->write_dword(offset << 2, data, mem_mask);
m_io_space->write_dword(address, data, mem_mask);
}

View File

@ -8,12 +8,22 @@
#include "emu.h"
// the following enables a very crude instruction cache - it has known (future)
// problems, but speeds up cpu execution quite noticeably in the short term by
// avoiding some of the delays in the mame memory subsystem
#define ICACHE_ENTRIES 32768
#define MCFG_CAMMU_SSW_CB(_sswcb) \
devcb = &cammu_device::static_set_ssw_callback(*device, DEVCB_##_sswcb);
class cammu_device : public device_t, public device_memory_interface
{
public:
cammu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
cammu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, const char *shortname, const char *source);
virtual DECLARE_ADDRESS_MAP(map, 8);
template<class _Object> static devcb_base &static_set_ssw_callback(device_t &device, _Object object) { return downcast<cammu_device &>(device).m_ssw_func.set_callback(object); }
virtual DECLARE_ADDRESS_MAP(map, 32) = 0;
DECLARE_READ32_MEMBER(mmu_r);
DECLARE_WRITE32_MEMBER(mmu_w);
@ -30,6 +40,8 @@ protected:
virtual const address_space_config *memory_space_config (address_spacenum spacenum) const override;
private:
devcb_read32 m_ssw_func;
address_space_config m_main_space_config;
address_space_config m_io_space_config;
address_space_config m_boot_space_config;
@ -39,9 +51,43 @@ private:
address_space *m_boot_space;
u32 m_cammu[1024];
#ifdef ICACHE_ENTRIES
struct icache
{
u32 offset;
u32 data;
} m_icache[ICACHE_ENTRIES];
#endif
};
// device type definition
extern const device_type CAMMU;
class cammu_c4t_device : public cammu_device
{
public:
cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual DECLARE_ADDRESS_MAP(map, 32) override;
};
class cammu_c4i_device : public cammu_device
{
public:
cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual DECLARE_ADDRESS_MAP(map, 32) override;
};
class cammu_c3_device : public cammu_device
{
public:
cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual DECLARE_ADDRESS_MAP(map, 32) override;
};
// device type definitions
extern const device_type CAMMU_C4T;
extern const device_type CAMMU_C4I;
extern const device_type CAMMU_C3;
#endif