Add preliminary Sharp SM590 CPU core [Lord Nightmare, hap]

This commit is contained in:
Lord-Nightmare 2017-05-09 14:24:39 -04:00
parent 790c23ff29
commit 3d18cb2faa
8 changed files with 614 additions and 22 deletions

View File

@ -1769,6 +1769,9 @@ if (CPUS["SM510"]~=null) then
MAME_DIR .. "src/devices/cpu/sm510/kb1013vk1-2.h",
MAME_DIR .. "src/devices/cpu/sm510/kb1013vk1-2op.cpp",
MAME_DIR .. "src/devices/cpu/sm510/kb1013vk1-2core.cpp",
MAME_DIR .. "src/devices/cpu/sm510/sm590.h",
MAME_DIR .. "src/devices/cpu/sm510/sm590op.cpp",
MAME_DIR .. "src/devices/cpu/sm510/sm590core.cpp",
}
end

View File

@ -18,9 +18,9 @@
- *KB1013VK1-2: Soviet-era clone of SM500, minor differences
Sharp SM590 MCU family:
- *SM590: x
- *SM591: x
- *SM595: x
- *SM590: 512x8 ROM, 32x4 RAM
- *SM591: 1kx8 ROM, 56x4 RAM
- *SM595: 768x8 ROM, 32x4 RAM
References:
- 1990 Sharp Microcomputers Data Book
@ -54,7 +54,7 @@
enum
{
SM510_PC=1, SM510_ACC, SM510_BL, SM510_BM,
SM510_PC=1, SM510_ACC, SM510_X, SM510_BL, SM510_BM,
SM510_C, SM510_W
};
@ -144,6 +144,7 @@ void sm510_base_device::device_start()
// register state for debugger
state_add(SM510_PC, "PC", m_pc).formatstr("%04X");
state_add(SM510_ACC, "ACC", m_acc).formatstr("%01X");
state_add(SM510_X, "X", m_x).formatstr("%01X");
state_add(SM510_BL, "BL", m_bl).formatstr("%01X");
state_add(SM510_BM, "BM", m_bm).formatstr("%01X");
state_add(SM510_C, "C", m_c).formatstr("%01X");

View File

@ -220,7 +220,7 @@ protected:
devcb_write8 m_write_r;
// misc internal helpers
void increment_pc();
virtual void increment_pc();
virtual void get_opcode_param() { }
virtual void update_w_latch() { }
@ -228,7 +228,7 @@ protected:
void ram_w(u8 data);
void pop_stack();
void push_stack();
void do_branch(u8 pu, u8 pm, u8 pl);
virtual void do_branch(u8 pu, u8 pm, u8 pl);
u8 bitmask(u16 param);
// opcode handlers

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:hap
// copyright-holders:hap, Jonathan Gevaryahu
/*
Sharp SM510/SM500 MCU family disassembler
@ -38,7 +38,12 @@ enum e_mnemonics
mLC, mLM, mLE, mLAF, mLAS, mLDF, mBS0, mBS1, mXL, mXM, mXI, mXEI, mXD, mXED, mXE, mBM0, mBM1, mSM1,
mAM, mAC, mA10, mAS, mCLL, mCOM, mCLC, mSTC, mSCO, mSAO, mINC, mDEC, mSAM, mSAL, mNOP,
mICD, mOAR, mOA0, mOA1, mDAF, mDAS, mABS, mABF, mCTB, mLD0, mEN,
mBR, mLP, mCBR, mCMS, mRT, mRTS, mSI1, mSI0, mSYN, mTIM, mHLT
mBR, mLP, mCBR, mCMS, mRT, mRTS, mSI1, mSI0, mSYN, mTIM, mHLT,
// SM590 aliases
mCCTRL, mINBL, mDEBL, mXBLA, mADCS, mTR7,
// SM590 uniques
mTAX, mLBLX, mMTR, mSTR, mINBM, mDEBM, mRTA, mBLTA, mEXAX, mTBA, mADS, mADC, mLBMX, mTLS
};
static const char *const s_mnemonics[] =
@ -65,7 +70,12 @@ static const char *const s_mnemonics[] =
"LC", "LM", "LE", "LAF", "LAS", "LDF", "BS0", "BS1", "XL", "XM", "XI", "XEI", "XD", "XED", "XE", "BM0", "BM1", "SM1",
"AM", "AC", "A10", "AS", "CLL", "COM", "CLC", "STC", "SCO", "SAO", "INC", "DEC", "SAM", "SAL", "NOP",
"ICD", "OAR", "OA0", "OA1", "DAF", "DAS", "ABS", "ABF", "CTB", "LD0", "EN",
"BR", "LP", "CBR", "CMS", "RT", "RTS", "SI1", "SI0", "SYN", "TIM", "HLT"
"BR", "LP", "CBR", "CMS", "RT", "RTS", "SI1", "SI0", "SYN", "TIM", "HLT",
//
"CCTRL", "INBL", "DEBL", "XBLA", "ADCS", "TR",
//
"TAX", "LBLX", "MTR", "STR", "INBM", "DEBM", "RTA", "BLTA", "EXAX", "TBA", "ADS", "ADC", "LBMX", "TLS"
};
// number of bits per opcode parameter, 8 or larger means 2-byte opcode
@ -93,7 +103,12 @@ static const u8 s_bits[] =
4, 0, 2, 8, 4, 0, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, 2, 2,
0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0
6, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0,
//
0, 0, 0, 0, 0, 7,
//
4, 4, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2+8
};
#define _OVER DASMFLAG_STEP_OVER
@ -123,11 +138,16 @@ static const u32 s_flags[] =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, _OVER, 0, _OUT, _OUT, 0, 0, 0, 0, _OVER
0, 0, _OVER, 0, _OUT, _OUT, 0, 0, 0, 0, _OVER,
//
0, 0, 0, 0, 0, _OVER,
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _OVER
};
// next program counter in sequence (relative)
static const s8 s_next_pc[0x40] =
static const s8 s_next_pc_6[0x40] =
{
32, -1 /* rollback */, -1, 30, 30, -3, -3, 28, 28, -5, -5, 26, 26, -7, -7, 24,
24, -9, -9, 22, 22, -11, -11, 20, 20, -13, -13, 18, 18, -15, -15, 16,
@ -135,15 +155,27 @@ static const s8 s_next_pc[0x40] =
8, -25, -25, 6, 6, -27, -27, 4, 4, -29, -29, 2, 2, -31, -31, 0 /* gets stuck here */
};
static const s8 s_next_pc_7[0x80] =
{
64, -1 /* rollback */, -1, 62, 62, -3, -3, 60, 60, -5, -5, 58, 58, -7, -7, 56,
56, -9, -9, 54, 54, -11, -11, 52, 52, -13, -13, 50, 50, -15, -15, 48,
48, -17, -17, 46, 46, -19, -19, 44, 44, -21, -21, 42, 42, -23, -23, 40,
40, -25, -25, 38, 38, -27, -27, 36, 36, -29, -29, 34, 34, -31, -31, 32,
32, -33, -33, 30, 30, -35, -35, 28, 28, -37, -37, 26, 26, -39, -39, 24,
24, -41, -41, 22, 22, -43, -43, 20, 20, -45, -45, 18, 18, -47, -47, 16,
16, -49, -49, 14, 14, -51, -51, 12, 12, -53, -53, 10, 10, -55, -55, 8,
8, -57, -57, 6, 6, -59, -59, 4, 4, -61, -61, 2, 2, -63, -63, 0 /* gets stuck here */
};
// common disasm
static offs_t sm510_common_disasm(const u8 *lut_mnemonic, const u8 *lut_extended, std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram)
static offs_t sm510_common_disasm(const u8 *lut_mnemonic, const u8 *lut_extended, std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, const u8 pclen)
{
// get raw opcode
u8 op = oprom[0];
u8 instr = lut_mnemonic[op];
s8 s_next_pc = ((pclen==6)?s_next_pc_6[pc & 0x3f]:s_next_pc_7[pc & 0x7f]);
int len = 1;
int bits = s_bits[instr];
@ -153,7 +185,7 @@ static offs_t sm510_common_disasm(const u8 *lut_mnemonic, const u8 *lut_extended
{
// note: disasm view shows correct parameter, but raw view does not
// note2: oprom array negative index doesn't work either :(
param = oprom[s_next_pc[pc & 0x3f]];
param = oprom[s_next_pc];
len++;
}
@ -186,7 +218,7 @@ static offs_t sm510_common_disasm(const u8 *lut_mnemonic, const u8 *lut_extended
// show param offset
if (bits >= 8)
util::stream_format(stream, " [$%03X]", pc + s_next_pc[pc & 0x3f]);
util::stream_format(stream, " [$%03X]", pc + s_next_pc);
}
return len | s_flags[instr] | DASMFLAG_SUPPORTED;
@ -221,7 +253,7 @@ static const u8 sm510_mnemonic[0x100] =
CPU_DISASSEMBLE(sm510)
{
return sm510_common_disasm(sm510_mnemonic, nullptr, stream, pc, oprom, opram);
return sm510_common_disasm(sm510_mnemonic, nullptr, stream, pc, oprom, opram, 6);
}
@ -263,7 +295,7 @@ CPU_DISASSEMBLE(sm511)
memset(ext, 0, 0x100);
memcpy(ext + 0x30, sm511_extended, 0x10);
return sm510_common_disasm(sm511_mnemonic, ext, stream, pc, oprom, opram);
return sm510_common_disasm(sm511_mnemonic, ext, stream, pc, oprom, opram, 6);
}
@ -305,7 +337,7 @@ CPU_DISASSEMBLE(sm500)
memset(ext, 0, 0x100);
memcpy(ext + 0x00, sm500_extended, 0x10);
return sm510_common_disasm(sm500_mnemonic, ext, stream, pc, oprom, opram);
return sm510_common_disasm(sm500_mnemonic, ext, stream, pc, oprom, opram, 6);
}
@ -347,5 +379,38 @@ CPU_DISASSEMBLE(kb1013vk12)
memset(ext, 0, 0x100);
memcpy(ext + 0x00, kb1013vk12_extended, 0x10);
return sm510_common_disasm(kb1013vk12_mnemonic, ext, stream, pc, oprom, opram);
return sm510_common_disasm(kb1013vk12_mnemonic, ext, stream, pc, oprom, opram, 6);
}
// SM590 disasm
static const u8 sm590_mnemonic[0x100] =
{
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
mNOP, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, // 0
mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, mTAX, // 1
mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, mLBLX, // 2
mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, // 3
mLDA, mEXC, mEXCI, mEXCD, mCOMA, mTAM, mATR, mMTR, mRC, mSC, mSTR, mCCTRL,mRTN, mRTNS, 0, 0, // 4
mINBM, mDEBM, mINBL, mDEBL, mTC, mRTA, mBLTA, mXBLA, 0, 0, 0, 0, mATX, mEXAX, 0, 0, // 5
mTMI, mTMI, mTMI, mTMI, mTBA, mTBA, mTBA, mTBA, mRM, mRM, mRM, mRM, mSM, mSM, mSM, mSM, // 6
mADD, mADS, mADC, mADCS, mLBMX, mLBMX, mLBMX, mLBMX, mTL, mTL, mTL, mTL, mTLS, mTLS, mTLS, mTLS, // 7
mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, // 8
mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, // 9
mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, // A
mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, // B
mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, // C
mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, // D
mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, // E
mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7, mTR7 // F
};
CPU_DISASSEMBLE(sm590)
{
return sm510_common_disasm(sm590_mnemonic, nullptr, stream, pc, oprom, opram, 7);
}

View File

@ -9,14 +9,14 @@
// internal helpers
inline u8 sm510_base_device::ram_r()
u8 sm510_base_device::ram_r()
{
int bmh = (m_sbm) ? (1 << (m_datawidth-1)) : 0; // from SBM
u8 address = (bmh | m_bm << 4 | m_bl) & m_datamask;
return m_data->read_byte(address) & 0xf;
}
inline void sm510_base_device::ram_w(u8 data)
void sm510_base_device::ram_w(u8 data)
{
int bmh = (m_sbm) ? (1 << (m_datawidth-1)) : 0; // from SBM
u8 address = (bmh | m_bm << 4 | m_bl) & m_datamask;
@ -43,7 +43,7 @@ void sm510_base_device::do_branch(u8 pu, u8 pm, u8 pl)
m_pc = ((pu << 10 & 0xc00) | (pm << 6 & 0x3c0) | (pl & 0x03f)) & m_prgmask;
}
inline u8 sm510_base_device::bitmask(u16 param)
u8 sm510_base_device::bitmask(u16 param)
{
// bitmask from immediate opcode param
return 1 << (param & 3);

View File

@ -0,0 +1,187 @@
// license:BSD-3-Clause
// copyright-holders:hap, Jonathan Gevaryahu
/*
Sharp SM590 MCU family cores
*/
#ifndef _SM590_H_
#define _SM590_H_
#include "sm510.h"
// I/O ports setup
// ..
// pinout reference
/*
16-pin DIP SM590/591/595:
____ ____
_|* \__/ |_
R0.0 <> |_|1 16|_| -- VDD(5v)
_| |_
R0.1 <> |_|2 15|_| <> R2.2
_| |_
R0.2 <> |_|3 14|_| <> R2.1
_| |_
R0.3 <> |_|4 13|_| <> R2.0
_| |_
R3.3/CL2 => |_|5 12|_| <> R1.3
_| |_
CL1 == |_|6 11|_| <> R1.2
_| |_
ACL -> |_|7 10|_| <> R1.1
_| |_
GND -- |_|8 9|_| <> R1.0
|____________|
18-pin DIP SM590/591/595:
____ ____
_|* \__/ |_
R0.0 <> |_|1 18|_| -- VDD(5v)
_| |_
R0.1 <> |_|2 17|_| <> R2.2
_| |_
R2.3 <> |_|3 16|_| <> R3.0
_| |_
R0.2 <> |_|4 15|_| <> R2.1
_| |_
R0.3 <> |_|5 14|_| <> R2.0
_| |_
R3.3/CL2 => |_|6 13|_| <> R1.3
_| |_
CL1 == |_|7 12|_| <> R1.2
_| |_
ACL -> |_|8 11|_| <> R1.1
_| |_
GND -- |_|9 10|_| <> R1.0
|____________|
20-pin DIP SM590/591/595:
____ ____
_|* \__/ |_
R0.0 <> |_|1 20|_| -- VDD(5v)
_| |_
R0.1 <> |_|2 19|_| <> R2.2
_| |_
R2.3 <> |_|3 18|_| <> R3.0
_| |_
R0.2 <> |_|4 17|_| <> R2.1
_| |_
R0.3 <> |_|5 16|_| <> R2.0
_| |_
R3.3/CL2 => |_|6 15|_| <> R1.3
_| |_
CL1 == |_|7 14|_| <> R1.2
_| |_
R3.2 <> |_|8 13|_| <> R3.1
_| |_
ACL -> |_|9 12|_| <> R1.1
_| |_
GND -- |_|10 11|_| <> R1.0
|____________|
*/
class sm590_device : public sm510_base_device
{
public:
sm590_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
sm590_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, u32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source);
protected:
virtual void device_reset() override;
virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) override;
virtual void increment_pc() override;
virtual void execute_one() override;
virtual void get_opcode_param() override;
virtual void do_branch(u8 pu, u8 pm, u8 pl) override;
// opcode handlers
// 00-3f
// adx (same as sm510)
virtual void op_tax();
virtual void op_lblx();
// lax (same as sm510)
// 40-43
virtual void op_lda() override;
virtual void op_exc() override;
// exci (same as sm510)
// excd (same as sm510)
// 44-47
// coma (same as sm510)
// tam (same as sm510)
virtual void op_atr() override;
virtual void op_mtr();
// 48-4b
// rc (same as sm510)
// sc (same as sm510)
virtual void op_str();
// cctrl (same as sm510 cend)
// 4c-4f
// rtn (same as sm510 rtn0)
// rtns (same as sm510 rtn1)
// 4e illegal
// 4f illegal
// 50-53
virtual void op_inbm();
virtual void op_debm();
// inbl (same as sm510 incb)
// debl (same as sm510 decb)
// 54-57
virtual void op_tc() override;
virtual void op_rta();
virtual void op_blta();
// xbla (same as sm510 exbla)
// 58-5b are all illegal
// 5c-5f
// atx (same as sm510)
virtual void op_exax();
// 5e illegal???
// 5f illegal
// 60-6f
// tm (same as sm510 tmi)
virtual void op_tba();
// rm (same as sm510)
// sm (same as sm510)
// 70-73
// add (same as sm510)
virtual void op_ads();
virtual void op_adc();
// adcs (same as sm510 add11)
// 74-7f
virtual void op_lbmx();
virtual void op_tl() override;
virtual void op_tml() override; // aka TLS
// 80-ff
virtual void op_t() override; // aka TR
u8 m_rports[4];
};
extern const device_type SM590;
#endif /* _SM590_H_ */

View File

@ -0,0 +1,190 @@
// license:BSD-3-Clause
// copyright-holders:hap, Jonathan Gevaryahu
/*
Sharp SM590 MCU core implementation
*/
#include "emu.h"
#include "sm590.h"
#include "debugger.h"
// MCU types
const device_type SM590 = device_creator<sm590_device>;
//const device_type SM591 = device_creator<sm591_device>;
//const device_type SM595 = device_creator<sm595_device>;
// internal memory maps
static ADDRESS_MAP_START(program_1x128x4, AS_PROGRAM, 8, sm510_base_device)
AM_RANGE(0x000, 0x200) AM_ROM
ADDRESS_MAP_END
/*static ADDRESS_MAP_START(program_2x128x4, AS_PROGRAM, 8, sm510_base_device)
AM_RANGE(0x000, 0x400) AM_ROM
ADDRESS_MAP_END
static ADDRESS_MAP_START(program_1x128x4_1x128x2, AS_PROGRAM, 8, sm510_base_device)
AM_RANGE(0x000, 0x300) AM_ROM
ADDRESS_MAP_END*/
static ADDRESS_MAP_START(data_16x2x4, AS_DATA, 8, sm510_base_device)
AM_RANGE(0x00, 0x0f) AM_RAM
AM_RANGE(0x10, 0x1f) AM_RAM
ADDRESS_MAP_END
/*
static ADDRESS_MAP_START(data_16x3.5x4, AS_DATA, 8, sm510_base_device)
AM_RANGE(0x00, 0x0f) AM_RAM
AM_RANGE(0x10, 0x1f) AM_RAM
AM_RANGE(0x20, 0x2f) AM_RAM
AM_RANGE(0x30, 0x37) AM_RAM
ADDRESS_MAP_END
*/
// device definitions
sm590_device::sm590_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: sm510_base_device(mconfig, SM590, "SM590", tag, owner, clock, 4 /* stack levels */, 10 /* prg width */, ADDRESS_MAP_NAME(program_1x128x4), 5 /* data width */, ADDRESS_MAP_NAME(data_16x2x4), "sm590", __FILE__)
{ }
//sm590_device::sm591_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
// : sm510_base_device(mconfig, SM591, "SM591", tag, owner, clock, 4 /* stack levels */, 10 /* prg width */, ADDRESS_MAP_NAME(program_2x128x4), 6 /* data width */, ADDRESS_MAP_NAME(data_16x3.5x4), "sm591", __FILE__)
//{ }
//sm590_device::sm595_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
// : sm510_base_device(mconfig, SM595, "SM595", tag, owner, clock, 4 /* stack levels */, 10 /* prg width */, ADDRESS_MAP_NAME(program_1x128x4_1x128x2), 5 /* data width */, ADDRESS_MAP_NAME(data_16x2x4), "sm595", __FILE__)
//{ }
sm590_device::sm590_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, u32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source)
: sm510_base_device(mconfig, type, name, tag, owner, clock, stack_levels, prgwidth, program, datawidth, data, shortname, source)
{ }
// disasm
offs_t sm590_device::disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options)
{
extern CPU_DISASSEMBLE(sm590);
return CPU_DISASSEMBLE_NAME(sm590)(this, stream, pc, oprom, opram, options);
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void sm590_device::device_reset()
{
// ACL
m_skip = false;
m_halt = false;
m_sbm = false;
m_op = m_prev_op = 0;
do_branch(0, 0, 0);
m_prev_pc = m_pc;
m_rports[0] = m_rports[1] = m_rports[2] = m_rports[3] = 0;
//m_write_r(0, 0, 0xff);
}
//-------------------------------------------------
// execute
//-------------------------------------------------
void sm590_device::increment_pc()
{
// PL(program counter low 7 bits) is a simple LFSR: newbit = (bit0==bit1)
// PU,PM(high bits) specify page, PL specifies steps within page
int feed = ((m_pc >> 1 ^ m_pc) & 1) ? 0 : 0x40;
m_pc = feed | (m_pc >> 1 & 0x3f) | (m_pc & ~0x7f);
}
void sm590_device::get_opcode_param()
{
// TL, TLS(TML) opcodes are 2 bytes
if ((m_op & 0xf8) == 0x78)
{
m_icount--;
m_param = m_program->read_byte(m_pc);
increment_pc();
}
}
void sm590_device::execute_one()
{
switch (m_op & 0xf0) // opcodes with 4 bit params
{
case 0x00: op_adx(); break;
case 0x10: op_tax(); break;
case 0x20: op_lblx(); break;
case 0x30: op_lax(); break;
case 0x80: case 0x90: case 0xa0: case 0xb0:
case 0xc0: case 0xd0: case 0xe0: case 0xf0:
op_t(); break; // aka tr
default: // opcodes with 2 bit params
switch (m_op & 0xfc)
{
case 0x60: op_tmi(); break; // aka tm
case 0x64: op_tba(); break;
case 0x68: op_rm(); break;
case 0x6c: op_sm(); break;
case 0x74: op_lbmx(); break;
case 0x78: op_tl(); break;
case 0x7c: op_tml(); break; // aka tls
default: // everything else
switch (m_op)
{
case 0x40: op_lda(); break;
case 0x41: op_exc(); break;
case 0x42: op_exci(); break;
case 0x43: op_excd(); break;
case 0x44: op_coma(); break;
case 0x45: op_tam(); break;
case 0x46: op_atr(); break;
case 0x47: op_mtr(); break;
case 0x48: op_rc(); break;
case 0x49: op_sc(); break;
case 0x4a: op_str(); break;
case 0x4b: op_cend(); break; // aka cctrl
case 0x4c: op_rtn0(); break; // aka rtn
case 0x4d: op_rtn1(); break; // aka rtns
// 4e, 4f illegal
case 0x50: op_inbm(); break;
case 0x51: op_debm(); break;
case 0x52: op_incb(); break; // aka inbl
case 0x53: op_decb(); break; // aka debl
case 0x54: op_tc(); break; // check this?
case 0x55: op_rta(); break;
case 0x56: op_blta(); break;
case 0x57: op_exbla(); break; // aka xbla
// 58, 59, 5a, 5b illegal
case 0x5c: op_atx(); break;
case 0x5d: op_exax(); break;
// 5e is illegal???
// 5f is illegal
case 0x70: op_add(); break;
case 0x71: op_ads(); break;
case 0x72: op_adc(); break;
case 0x73: op_add11(); break; // aka adcs
/*// extended opcodes
case 0x5e:
m_op = m_op << 8 | m_param;
switch (m_param)
{
case 0x00: op_cend(); break;
case 0x04: op_dta(); break;
default: op_illegal(); break;
}
break; // 0x5e*/
default: op_illegal(); break;
}
break; // 0xff
}
break; // 0xfc
} // big switch
}

View File

@ -0,0 +1,146 @@
// license:BSD-3-Clause
// copyright-holders:hap, Jonathan Gevaryahu
// SM590 opcode handlers
#include "emu.h"
#include "sm590.h"
// internal helpers
void sm590_device::do_branch(u8 pu, u8 pm, u8 pl)
{
// set new PC(Pu/Pm/Pl)
m_pc = (((u16)pu << 9 & 0x200) | ((u16)pm << 7 & 0x180) | (pl & 0x07f)) & m_prgmask;
}
// instruction set
void sm590_device::op_lblx()
{
// LBL x: load BL with 4-bit immediate value
m_bl = (m_op & 0xf);
}
void sm590_device::op_tax()
{
// TAX: skip next if ACC equals 4-bit immediate value
m_skip = (m_acc == (m_op & 0xf));
}
void sm590_device::op_lda()
{
// LDA: load ACC with RAM
m_acc = ram_r();
}
void sm590_device::op_exc()
{
// EXC: exchange ACC with RAM
u8 a = m_acc;
m_acc = ram_r();
ram_w(a);
}
void sm590_device::op_atr()
{
// ATR: output ACC to R(BL)
m_rports[m_bl & 0x3] = m_acc; // is the mask for BL correct here? if BL is >= 4, do the writes just go nowhere?
}
void sm590_device::op_mtr()
{
// MTR: output RAM to R(BL)
m_rports[m_bl & 0x3] = ram_r(); // is the mask for BL correct here? if BL is >= 4, do the writes just go nowhere?
}
void sm590_device::op_str()
{
// STR: output ACC to RAM
ram_w(m_acc);
}
void sm590_device::op_inbm()
{
// INBM: increment BM
m_bm = (m_bm + 1) & 0x3; // is this mask correct?
}
void sm590_device::op_debm()
{
// DEBM: decrement BM
m_bm = (m_bm - 1) & 0x3; // is this mask correct?
}
void sm590_device::op_tc()
{
// TC: skip next if carry
m_skip = m_c;
}
void sm590_device::op_rta()
{
// RTA: load ACC with R(BL)
m_acc = m_rports[m_bl & 0x3]; // TODO: need a read function for this; is the mask for BL correct here? if BL is >= 4, do we always read 0 or F?
}
void sm590_device::op_blta()
{
// BLTA: load ACC with BL
m_acc = m_bl;
}
void sm590_device::op_exax()
{
// EXAX: exchange X with ACC
u8 a = m_acc;
m_acc = m_x;
m_x = a;
}
void sm590_device::op_tba()
{
// TBA x: skip next if ACC bit is set
m_skip = ((m_acc & bitmask(m_op)) != 0);
}
void sm590_device::op_ads()
{
// ADS: add RAM to ACC, skip next on carry
m_acc += ram_r();
m_skip = (m_c == 1);
m_acc &= 0xf;
}
void sm590_device::op_adc()
{
// ADC: add RAM and carry to ACC and carry
m_acc += ram_r() + m_c;
m_c = m_acc >> 4 & 1;
m_acc &= 0xf;
}
void sm590_device::op_lbmx()
{
// LBM x: load BM with 2-bit immediate value
m_bm = (m_op & 0x3);
}
void sm590_device::op_tl()
{
// TL xyz: long jump (same as sm510 TL except m_op and m_param masks)
do_branch((m_op & 2)>>1, (((m_op & 1)<<1)|((m_param&0x80)?1:0)), m_param & 0x7f);
}
void sm590_device::op_tml() // aka TLS
{
// TLS xyz: long call (same as sm510 TML except m_param mask)
push_stack();
do_branch((m_op & 2)>>1, (((m_op & 1)<<1)|((m_param&0x80)?1:0)), m_param & 0x7f);
}
void sm590_device::op_t()
{
// TR xy: jump(transfer) within current page (same as sm510 T except m_op/m_pc mask)
m_pc = (m_pc & ~0x7f) | (m_op & 0x7f);
}