From 521af022e3fbecbc049625e3ec25a5ec1ba80869 Mon Sep 17 00:00:00 2001 From: mamehaze <140764005+mamehaze@users.noreply.github.com> Date: Mon, 25 Nov 2024 23:42:46 +0000 Subject: new machines marked as NOT WORKING - Cassette Vision (#11927) * abandoned cassette vison work * remove comment now that the useful table is gone * force github to rebuild because github is being github * add a note based on earlier research * bring this part over from the previous tree too, it seems worth having still * actually use this version instead, I thought it was broken, but it actually has advantages * I've been informed this will be merged if I assign a copyright holder, so as I don't really recognize it as my own design anymore, I'm assigning Vas. * Update cpu.lua * Start cleaning up: * cassvisn_cart.xml: Fixed program region width. * cassvisn_cart.xml: Added Japanese titles and proper markup for release dates. * epoch/cassvisn.cpp: Removed unnecessary byte swapping when loading software list items. * cpu/upd777.cpp: Made order of declarations and definitions more consistent with each other, added more inline and const hints. * tools/unidasm.cpp: Make data source big Endian to match CPU core. * epoch/cassvisn.cpp: Digit grouping for big numbers, better error messages. --------- Co-authored-by: David Haywood Co-authored-by: Vas Crabb --- hash/cassvisn_cart.xml | 215 ++++++ scripts/src/cpu.lua | 17 + src/devices/cpu/upd777/upd777.cpp | 1262 +++++++++++++++++++++++++++++++++ src/devices/cpu/upd777/upd777.h | 165 +++++ src/devices/cpu/upd777/upd777dasm.cpp | 504 +++++++++++++ src/devices/cpu/upd777/upd777dasm.h | 34 + src/mame/epoch/cassvisn.cpp | 112 +++ src/mame/mame.lst | 3 + src/tools/unidasm.cpp | 2 + 9 files changed, 2314 insertions(+) create mode 100644 hash/cassvisn_cart.xml create mode 100644 src/devices/cpu/upd777/upd777.cpp create mode 100644 src/devices/cpu/upd777/upd777.h create mode 100644 src/devices/cpu/upd777/upd777dasm.cpp create mode 100644 src/devices/cpu/upd777/upd777dasm.h create mode 100644 src/mame/epoch/cassvisn.cpp diff --git a/hash/cassvisn_cart.xml b/hash/cassvisn_cart.xml new file mode 100644 index 00000000000..9fbb64e17bb --- /dev/null +++ b/hash/cassvisn_cart.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + Yosaku + 1981 + Epoch + + + + + + + + + + + + + + Baseball + 1981 + Epoch + + + + + + + + + + + + + + + Galaxian + 1981 + Epoch + + + + + + + + + + + + + + Big Sports 12 + 1982 + Epoch + + + + + + + + + + + + + + + Battle Vader + 1982 + Epoch + + + + + + + + + + + + + + PakPak Monster + 1982 + Epoch + + + + + + + + + + + + + + New Baseball + 1982 + Epoch + + + + + + + + + + + + + + Monster Mansion + 1982 + Epoch + + + + + + + + + + + + + + Astro Command + 1982 + Epoch + + + + + + + + + + + + + + Monster Block + 1984 + Epoch + + + + + + + + + + + + + + Elevator Panic + 1984 + Epoch + + + + + + + + + + + + + diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index 96a274222e1..302d4ff83f5 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -4135,6 +4135,23 @@ if opt_tool(CPUS, "HT1130") then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/ht1130/ht1130d.h") end +-------------------------------------------------- +-- UPD777 +--@src/devices/cpu/upd777/upd777.h,CPUS["UPD777"] = true +-------------------------------------------------- + +if CPUS["UPD777"] then + files { + MAME_DIR .. "src/devices/cpu/upd777/upd777.cpp", + MAME_DIR .. "src/devices/cpu/upd777/upd777.h", + } +end + +if opt_tool(CPUS, "UPD777") then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/upd777/upd777dasm.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/upd777/upd777dasm.h") +end + -------------------------------------------------- -- Epson C33 STD, C33 ADV, etc. --@src/devices/cpu/c33/c33common.h,CPUS["C33"] = true diff --git a/src/devices/cpu/upd777/upd777.cpp b/src/devices/cpu/upd777/upd777.cpp new file mode 100644 index 00000000000..fda5e638bb4 --- /dev/null +++ b/src/devices/cpu/upd777/upd777.cpp @@ -0,0 +1,1262 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb + +#include "emu.h" +#include "upd777.h" + +#include "upd777dasm.h" + + +#define LOG_UNHANDLED_OPS (1U << 1) + +#define VERBOSE (LOG_UNHANDLED_OPS) +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(UPD777, upd777_cpu_device, "upd777", "uPD777") + +upd777_cpu_device::upd777_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor data) + : cpu_device(mconfig, type, tag, owner, clock) + , m_datamem(*this, "datamem") + , m_space_config("program", ENDIANNESS_BIG, 16, 11, -1, address_map_constructor(FUNC(upd777_cpu_device::internal_map), this)) + , m_data_config("data", ENDIANNESS_BIG, 8, 7, 0, data) + , m_gfxdecode(*this, "gfxdecode") + , m_palette(*this, "palette") + , m_screen(*this, "screen") + , m_prgregion(*this, "prg") + , m_patregion(*this, "patterns") + , m_port_in(*this, 0xff) +{ +} + +upd777_cpu_device::upd777_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : upd777_cpu_device(mconfig, UPD777, tag, owner, clock, address_map_constructor(FUNC(upd777_cpu_device::internal_data_map), this)) +{ +} + +std::unique_ptr upd777_cpu_device::create_disassembler() +{ + return std::make_unique(); +} + +device_memory_interface::space_config_vector upd777_cpu_device::memory_space_config() const +{ + return space_config_vector{ + std::make_pair(AS_PROGRAM, &m_space_config), + std::make_pair(AS_DATA, &m_data_config) + }; +} + +void upd777_cpu_device::internal_map(address_map &map) +{ + map(0x000, 0x7ff).rom().region("prg", 0); +} + +void upd777_cpu_device::internal_data_map(address_map &map) +{ + // 0x20 groups of 4 7-bit values + // groups 0x00-0x18 are used for sprite/pattern entries with the format + + // 6543210 + // 00 yyyyyyp (y = ypos, p = PRIO) + // 01 xxxxxxx (x = xpos) + // 02 ttttttt (t = pattern) + // 03 YYYRGBS (Y = , RGB = color, S=ySUB) + + map(0x00, 0x7f).ram().share("datamem"); +} + +void upd777_cpu_device::increment_pc() +{ + u16 lowpc = m_pc & 0x07f; + u16 highpc = m_pc & 0x780; + + const u16 xnor = BIT(lowpc, 6) ^ BIT(lowpc, 5) ^ 1; + lowpc = ((lowpc << 1) | xnor) & 0x7f; + + // is returning to the start of the page the correct behavior? + if (lowpc == 0x00) + { + logerror("overflowing PC, returning to start of current page %03x\n", highpc); + // pakpak runs better if you do this, but that is clearly by chance as + // most other cases show this isn't meant to happen + //highpc += 0x80; + //highpc &= 0x7ff; + } + + m_pc = highpc | lowpc; +} + +void upd777_cpu_device::device_start() +{ + space(AS_PROGRAM).specific(m_space); + space(AS_DATA).specific(m_data); + + set_icountptr(m_icount); + + state_add(UPD777_PC, "PC", m_pc); + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); + + state_add(UPD777_A1, "A1", m_a[0]); + state_add(UPD777_A2, "A2", m_a[1]); + state_add(UPD777_A3, "A3", m_a[2]); + state_add(UPD777_A4, "A4", m_a[3]); + + state_add(UPD777_L, "L", m_l); + state_add(UPD777_H, "H", m_h); + + state_add(UPD777_ADDR_STACK0, "ADDR_STACK0", m_stack[0]); + state_add(UPD777_ADDR_STACK1, "ADDR_STACK1", m_stack[1]); + state_add(UPD777_ADDR_STACK2, "ADDR_STACK2", m_stack[2]); + state_add(UPD777_ADDR_STACK_POS, "ADDR_STACK_POS", m_stackpos); + + //state_add(UPD777_SKIP, "SKIP", m_skip); // will always be showing 0 as debugger doesn't hook on skipped opcodes + + save_item(NAME(m_ppc)); + save_item(NAME(m_pc)); + save_item(NAME(m_skip)); + save_item(NAME(m_a)); + save_item(NAME(m_l)); + save_item(NAME(m_ldash)); + save_item(NAME(m_x4)); + save_item(NAME(m_h)); + + save_item(NAME(m_frs)); + save_item(NAME(m_fls)); + + save_item(NAME(m_mode)); + save_item(NAME(m_stb)); + + save_item(NAME(m_stack)); + save_item(NAME(m_stackpos)); + + save_item(NAME(m_disp)); + save_item(NAME(m_gpe)); + save_item(NAME(m_kie)); + save_item(NAME(m_sme)); +} + +void upd777_cpu_device::device_reset() +{ + m_ppc = 0; + m_pc = 0; + + m_a[0] = m_a[1] = m_a[2] = m_a[3] = 0; + m_l = 0; + m_ldash = 0; + m_x4 = 0; + m_h = 0; + + m_frs = 0; + m_fls = 0; + + m_skip = 1; // the first opcode is always 'NOP' so maybe skip is 1 on startup? + + m_stack[0] = m_stack[1] = m_stack[2] = 0; + m_stackpos = 0; + + m_disp = 0; + m_gpe = 0; + m_kie = 0; + m_sme = 0; +} + +inline u16 upd777_cpu_device::fetch() +{ + u16 opcode = m_space.read_word(m_pc); + m_ppc = m_pc; + increment_pc(); + return opcode; +} + + +inline void upd777_cpu_device::set_a11(int a11) +{ + m_pc = (m_pc & 0x3ff) | (a11 & 1) << 10; +} + +inline void upd777_cpu_device::set_new_pc(int newpc) +{ + m_pc = newpc; +} + +// L reg (lower memory pointer) is 2 bit +inline void upd777_cpu_device::set_l(int l) +{ + m_l = l & 0x3; +} + +inline u8 upd777_cpu_device::get_l() const +{ + return m_l & 0x3; +} + +// H reg (upper memory pointer) is 5-bit +inline void upd777_cpu_device::set_h(int h) +{ + m_h = h & 0x1f; +} + +// H reg is used as upper bits of memory address +inline u8 upd777_cpu_device::get_h_shifted() const +{ + return (m_h & 0x1f) << 2; +} + +inline u8 upd777_cpu_device::get_h() const +{ + return m_h & 0x1f; +} + +// M is the content of memory address pointed to by H and L +inline u8 upd777_cpu_device::get_m_data() +{ + u8 addr = get_h_shifted() | get_l(); + return read_data_mem(addr & 0x7f) & 0x7f; +} + +inline void upd777_cpu_device::set_m_data(u8 data) +{ + u8 addr = get_h_shifted() | get_l(); + write_data_mem(addr & 0x7f, data & 0x7f); +} + +// 'A' regs are 7-bit +inline void upd777_cpu_device::set_a1(u8 data) { m_a[0] = data & 0x7f; } +inline void upd777_cpu_device::set_a2(u8 data) { m_a[1] = data & 0x7f; } +inline void upd777_cpu_device::set_a3(u8 data) { m_a[2] = data & 0x7f; } +inline void upd777_cpu_device::set_a4(u8 data) { m_a[3] = data & 0x7f; } + +inline void upd777_cpu_device::set_a1_or_a2(int reg, u8 value) +{ + if (reg == 0) + set_a1(value); + else + set_a2(value); +} + +// 'A' regs are 7-bit +inline u8 upd777_cpu_device::get_a1() const { return m_a[0] & 0x7f; } +inline u8 upd777_cpu_device::get_a2() const { return m_a[1] & 0x7f; } +inline u8 upd777_cpu_device::get_a3() const { return m_a[2] & 0x7f; } +inline u8 upd777_cpu_device::get_a4() const { return m_a[3] & 0x7f; } + +inline u8 upd777_cpu_device::get_a1_or_a2(int reg) const +{ + if (reg == 0) + return get_a1(); + else + return get_a2(); +} + +// FRS/FLS are the 2 7-bit sound registers +inline void upd777_cpu_device::set_frs(u8 frs) { m_frs = frs & 0x7f; } +inline void upd777_cpu_device::set_fls(u8 fls) { m_fls = fls & 0x7f; } + +// MODE is a 7-bit register with the following format +// 6543210 +// rbhpRGB (r = reverberate sound effect, b = brightness, h = hue, p = black/prio, RGB = color) +inline void upd777_cpu_device::set_mode(u8 mode) { m_mode = mode & 0x7f; } + +// single bit enable registers, although they have an important effect on the K->M opcode +inline void upd777_cpu_device::set_disp(u8 data) { m_disp = data & 1; } +inline void upd777_cpu_device::set_gpe(u8 data) { m_gpe = data & 1; } +inline void upd777_cpu_device::set_kie(u8 data) { m_kie = data & 1; } +inline void upd777_cpu_device::set_sme(u8 data) { m_sme = data & 1; } + +inline u8 upd777_cpu_device::get_kie() const { return m_kie & 1; } +inline u8 upd777_cpu_device::get_sme() const { return m_sme & 1; } + + +inline u8 upd777_cpu_device::read_data_mem(u8 addr) +{ + // data memory is 7-bit + return m_data.read_byte(addr) & 0x7f; +} + +inline void upd777_cpu_device::write_data_mem(u8 addr, u8 data) +{ + // data memory is 7-bit + m_data.write_byte(addr, data & 0x7f); +} + +inline void upd777_cpu_device::push_to_stack(u16 addr) +{ + if (m_stackpos < 3) + { + m_stack[m_stackpos] = addr; + m_stackpos++; + } + else + { + logerror("attempting to push to full address stack\n"); + } +} + +inline u16 upd777_cpu_device::pull_from_stack() +{ + if (m_stackpos > 0) + { + m_stackpos--; + return m_stack[m_stackpos]; + } + else + { + logerror("attempting to pull from empty address stack\n"); + return 0; + } +} + +void upd777_cpu_device::do_op() +{ + const u16 inst = fetch(); + + if (inst >= 0b0000'1000'0000 && inst <= 0b0000'1111'1111) + { + // 080 - 0ff Skip if (M[H[5:1],L[2:1]][7:1]-K[7:1]) makes borrow + const int k = inst & 0x7f; + u8 m = get_m_data(); + m = m - k; + if (m & 0x80) + m_skip = 1; + } + else if (inst >= 0b0001'0000'0000 && inst <= 0b0001'0111'1111) + { + // 100-17f M[H[5:1],L[2:1]][7:1]+K[7:1]->M[H[5:1],L[2:1]][7:1], Skip if carry, N->L[2:1] + const int k = inst & 0x1f; + const int n = (inst >> 5) & 0x3; + u8 m = get_m_data(); + m = m + k; + set_m_data(m & 0x7f); + + if (m & 0x80) + m_skip = 1; + + // TODO: prevents infinitely scrolling screen, and allows pakpak to boot, but this does't make logical + // sense, unless the 'Skip if carry' in the text above is specifically meaning this only applies + // when skipping, however if you apply the same to the next opcode it breaks text rendering + // eg 'score' text in the same game. + if (m_skip) + set_l(n); + } + else if (inst >= 0b0001'1000'0000 && inst <= 0b0001'1111'1111) + { + // 180-1ff M[H[5:1],L[2:1]][7:1]-K[7:1]->M[H[5:1],L[2:1]][7:1], Skip if borrow, N->L[2:1] + const int k = inst & 0x1f; + const int n = (inst >> 5) & 0x3; + u8 m = get_m_data(); + m = m - k; + set_m_data(m & 0x7f); + + if (m & 0x80) + m_skip = 1; + + set_l(n); + } + else if (inst >= 0b0100'1000'0000 && inst <= 0b0100'1011'1111) + { + // 480-4bf H[5:1]-K[5:1]->H[5:1], Skip if borrow + const int k = inst & 0x1f; + u8 h = get_h(); + h = h - k; + if (h & 0x20) + m_skip = 1; + set_h(h & 0x1f); + } + else if (inst >= 0b0100'1100'0000 && inst <= 0b0100'1111'1111) + { + // 4c0 - 4ff H[5:1]+K[5:1]->H[5:1], Skip if carry + const int k = inst & 0x1f; + u8 h = get_h(); + h = h + k; + if (h & 0x20) + m_skip = 1; + set_h(h & 0x1f); + } + else if (inst >= 0b0101'0000'0000 && inst <= 0b0101'0111'1111) + { + // 500 - 57f + // When (KIE=0)&(SME=0), Store K[7:1] to M[H[5:1],L[2:1]][7:1] + // When (KIE=1), Store KIN[7:1] to M[H[5:1],L[2:1]][7:1] + // When (SME=1), Store HCL[7:1] to M[H[5:1],L[2:1]][7:1] + const int k = inst & 0x7f; + + if (get_kie()) // documentation does not state if KIE or SME has priority + { + LOGMASKED(LOG_UNHANDLED_OPS, "KIE->M\n", k); + // Inputs for Cassette Vision appear to be read by this + // (selected based on the STB output value?) + set_m_data(m_port_in(m_stb)); + } + else if (get_sme()) + { + LOGMASKED(LOG_UNHANDLED_OPS, "SME->M\n", k); + set_m_data(0); + } + else + { + set_m_data(k & 0x7f); + } + } + else if (inst >= 0b0101'1000'0000 && inst <= 0b0101'1111'1111) + { + // 580 - 5ff Store K[7:6] to L[2:1] and K[5:1] to H[5:1] + const int k = inst & 0x7f; + set_l(k >> 5); + set_h(k & 0x1f); + } + else if (inst >= 0b0110'0000'0000 && inst <= 0b0111'1111'1111) + { + // 600-67f Store K[7:1] to A1[7:1] + // 680-6ff Store K[7:1] to A2[7:1] + // 700-77f Store K[7:1] to A3[7:1] + // 780-7ff Store K[7:1] to A4[7:1] + const int reg = (inst & 0x180) >> 7; + const int k = inst & 0x7f; + switch (reg) + { + case 0: set_a1(k); break; + case 1: set_a2(k); break; + case 2: set_a3(k); break; + case 3: set_a4(k); break; + } + } + else if (inst >= 0b1000'0000'0000 && inst <= 0b1011'1111'1111) + { + // 800 - bff Move K[10:1] to A[10:1], Jump to A[11:1] + u16 fulladdress = (m_ppc & 0x400) | (inst & 0x3ff); + set_new_pc(fulladdress); + } + else if (inst >= 0b1100'0000'0000 && inst <= 0b1111'1111'1111) + { + // c00 - fff Move K[10:1] to A[10:1], 0 to A11, Jump to A[11:1], Push next A[11:1] up to ROM address stack + const int k = inst & 0x3ff; + push_to_stack(m_pc); + set_new_pc(k); + } + else if (((inst & 0b1111'0000'0000) == 0b0010'0000'0000) && ((inst & 0b0000'0000'1100) != 0b0000'0000'0100)) + { + // 0b0010'rrnR'oonn where rr = reg1 (A1, A2, M or H), n = invert condition, R = reg2 (A1 or A2) and oo = optype (only 0,2,3 are valid, no cases here for 1) nn = next l value + + // optype · (AND) + // 200 Skip if (A1[7:1]·A1[7:1]) makes zero, N->L[2:1] + // 220 Skip if (A1[7:1]·A1[7:1]) makes non zero, N->L[2:1] + // 210 Skip if (A1[7:1]·A2[7:1]) makes zero, N->L[2:1] + // 230 Skip if (A1[7:1]·A2[7:1]) makes non zero, N->L[2:1] + // 240 Skip if (A2[7:1]·A1[7:1]) makes zero, N->L[2:1] + // 260 Skip if (A2[7:1]·A1[7:1]) makes non zero, N->L[2:1] + // 250 Skip if (A2[7:1]·A2[7:1]) makes zero, N->L[2:1] + // 270 Skip if (A2[7:1]·A2[7:1]) makes non zero, N->L[2:1] + // 280 Skip if (M[H[5:1],L[2:1]][7:1]·A1[7:1]) makes zero, N->L[2:1] + // 2a0 Skip if (M[H[5:1],L[2:1]][7:1]·A1[7:1]) makes non zero, N->L[2:1] + // 290 Skip if (M[H[5:1],L[2:1]][7:1]·A2[7:1]) makes zero, N->L[2:1] + // 2b0 Skip if (M[H[5:1],L[2:1]][7:1]·A2[7:1]) makes non zero, N->L[2:1] + // 2c0 Skip if (H[5:1]·A1[5:1]) makes zero, N->L[2:1] + // 2e0 Skip if (H[5:1]·A1[5:1]) makes non zero, N->L[2:1] + // 2d0 Skip if (H[5:1]·A2[5:1]) makes zero, N->L[2:1] + // 2f0 Skip if (H[5:1]·A2[5:1]) makes non zero, N->L[2:1] + + // optype = (these are expressed as x=y in the opcopde syntax, but x-y in the description, in reality it seems to act as 'CMP' so x-y = 0) + // 208 Skip if (A1[7:1]-A1[7:1]) makes zero, N->L[2:1] + // 228 Skip if (A1[7:1]-A1[7:1]) makes non zero, N->L[2:1] + // 218 Skip if (A1[7:1]-A2[7:1]) makes zero, N->L[2:1] + // 238 Skip if (A1[7:1]-A2[7:1]) makes non zero, N->L[2:1] + // 248 Skip if (A2[7:1]-A1[7:1]) makes zero, N->L[2:1] + // 268 Skip if (A2[7:1]-A1[7:1]) makes non zero, N->L[2:1] + // 258 Skip if (A2[7:1]-A2[7:1]) makes zero, N->L[2:1] + // 278 Skip if (A2[7:1]-A2[7:1]) makes non zero, N->L[2:1] + // 288 Skip if (M[H[5:1],L[2:1]][7:1]-A1[7:1]) makes zero, N->L[2:1] + // 2a8 Skip if (M[H[5:1],L[2:1]][7:1]-A1[7:1]) makes non zero, N->L[2:1] + // 298 Skip if (M[H[5:1],L[2:1]][7:1]-A2[7:1]) makes zero, N->L[2:1] + // 2b8 Skip if (M[H[5:1],L[2:1]][7:1]-A2[7:1]) makes non zero, N->L[2:1] + // 2c8 Skip if (H[5:1]-A1[5:1]) makes zero, N->L[2:1] + // 2e8 Skip if (H[5:1]-A1[5:1]) makes non zero, N->L[2:1] + // 2d8 Skip if (H[5:1]-A2[5:1]) makes zero, N->L[2:1] + // 2f8 Skip if (H[5:1]-A2[5:1]) makes non zero, N->L[2:1] + + // optype - + // 20c Skip if (A1[7:1]-A1[7:1]) makes borrow, N->L[2:1] + // 22c Skip if (A1[7:1]-A1[7:1]) makes non borrow, N->L[2:1] + // 21c Skip if (A1[7:1]-A2[7:1]) makes borrow, N->L[2:1] + // 23c Skip if (A1[7:1]-A2[7:1]) makes non borrow, N->L[2:1] + // 24c Skip if (A2[7:1]-A1[7:1]) makes borrow, N->L[2:1] + // 26c Skip if (A2[7:1]-A1[7:1]) makes non borrow, N->L[2:1] + // 25c Skip if (A2[7:1]-A2[7:1]) makes borrow, N->L[2:1] + // 27c Skip if (A2[7:1]-A2[7:1]) makes non borrow, N->L[2:1] + // 28c Skip if (M[H[5:1],L[2:1]][7:1]-A1[7:1]) makes borrow, N->L[2:1] + // 2ac Skip if (M[H[5:1],L[2:1]][7:1]-A1[7:1]) makes non borrow, N->L[2:1] + // 29c Skip if (M[H[5:1],L[2:1]][7:1]-A2[7:1]) makes borrow, N->L[2:1] + // 2bc Skip if (M[H[5:1],L[2:1]][7:1]-A2[7:1]) makes non borrow, N->L[2:1] + // 2cc Skip if (H[5:1]-A1[5:1]) makes borrow, N->L[2:1] + // 2ec Skip if (H[5:1]-A1[5:1]) makes non borrow, N->L[2:1] + // 2dc Skip if (H[5:1]-A2[5:1]) makes borrow, N->L[2:1] + // 2fc Skip if (H[5:1]-A2[5:1]) makes non borrow, N->L[2:1] + const int non = inst & 0x20; + const int optype = (inst & 0x0c) >> 2; + const int reg1 = (inst & 0xc0) >> 6; + const int reg2 = (inst & 0x10) >> 4; + const int n = inst & 0x3; + u8 srcreg2 = get_a1_or_a2(reg2); + u8 srcreg1 = 0; + switch (reg1) + { + case 0: srcreg1 = get_a1(); break; + case 1: srcreg1 = get_a2(); break; + case 2: srcreg1 = get_m_data(); break; + case 3: + { + srcreg1 = get_h(); + srcreg2 &= 0x1f; + break; + } + } + + switch (optype) + { + case 0: // AND + { + if (!non) + { + if ((srcreg1 & srcreg2) == 0) // skip if (x·y) makes zero, N->L[2:1] + m_skip = 1; + } + else + { + if ((srcreg1 & srcreg2) != 0) // skip if (x·y) makes non zero, N->L[2:1] + m_skip = 1; + } + break; + } + case 1: // invalid + { + // can't happen, no switch case leads here + break; + } + case 2: // = + { + if (!non) + { + if (srcreg1 == srcreg2) // skip if (x-y) makes zero, N->L[2:1] + m_skip = 1; + } + else + { + if (srcreg1 != srcreg2) // skip if (x-y) makes non zero, N->L[2:1] + m_skip = 1; + } + break; + } + case 3: // - + { + u8 result = srcreg1 - srcreg2; + + if (!non) + { + if (result & 0x80) // skip if (x-y) makes borrow, N->L[2:1] + m_skip = 1; + } + else + { + if ((result & 0x80) == 0) // skip if (x-y) makes non borrow, N->L[2:1] + m_skip = 1; + } + + break; + } + } + + set_l(n); + } + else if ((inst & 0b1111'1010'0000) == 0b0011'0010'0000) + { + // 0b0011'0r1R'oonn (where r = reg1, R = reg2, o = optype, and n = next l value) + // 320 AND A1[7:1] and A1[7:1], store to A1[7:1], N->L[2:1] + // 324 Add A1[7:1] and A1[7:1], store to A1[7:1], N->L[2:1] + // 328 OR A1[7:1] and A1[7:1], store to A1[7:1], N->L[2:1] + // 32c Subtract A1[7:1] and A1[7:1], store to A1[7:1], Skip if borrow, N->L[2:1] + // 330 AND A1[7:1] and A2[7:1], store to A1[7:1], N->L[2:1] + // 334 Add A1[7:1] and A2[7:1], store to A1[7:1], N->L[2:1] + // 338 OR A1[7:1] and A2[7:1], store to A1[7:1], N->L[2:1] + // 33c Subtract A1[7:1] and A2[7:1], store to A1[7:1], Skip if borrow, N->L[2:1] + // 360 AND A2[7:1] and A1[7:1], store to A2[7:1], N->L[2:1] + // 364 Add A2[7:1] and A1[7:1], store to A2[7:1], N->L[2:1] + // 368 OR A2[7:1] and A1[7:1], store to A2[7:1], N->L[2:1] + // 36c Subtract A2[7:1] and A1[7:1], store to A2[7:1], Skip if borrow, N->L[2:1] + // 370 AND A2[7:1] and A2[7:1], store to A2[7:1], N->L[2:1] + // 374 Add A2[7:1] and A2[7:1], store to A2[7:1], N->L[2:1] + // 378 OR A2[7:1] and A2[7:1], store to A2[7:1], N->L[2:1] + // 37c Subtract A2[7:1] and A2[7:1], store to A2[7:1], Skip if borrow, N->L[2:1] + const int optype = (inst & 0x0c) >> 2; + const int reg2 = (inst & 0x10) >> 4; + const int reg1 = (inst & 0x40) >> 6; + const int n = inst & 0x3; + + u8 src1 = get_a1_or_a2(reg1); + u8 src2 = get_a1_or_a2(reg2); + + switch (optype) + { + case 0: // AND + { + src1 = src1 & src2; + break; + } + case 1: // ADD + { + src1 = src1 + src2; + // not in this case? + //if (src1 & 0x80) + // m_skip = 1; + break; + } + case 2: // OR + { + src1 = src1 | src2; + break; + } + case 3: // MINUS + { + src1 = src1 - src2; + if (src1 & 0x80) + m_skip = 1; + break; + } + } + set_a1_or_a2(reg1, src1); + set_l(n); + } + else if ((inst & 0b1111'1110'0000) == 0b0011'1010'0000) + { + // 0b0011'101r'oonn (where r = reg, o = optype, n = next l value) + // 3a0 AND M[H[5:1],L[2:1]][7:1] and A1[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 3a4 Add M[H[5:1],L[2:1]][7:1] and A1[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] Skip if carry + // 3a8 OR M[H[5:1],L[2:1]][7:1] and A1[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 3ac Subtract M[H[5:1],L[2:1]][7:1] and A1[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] Skip if borrow + // 3b0 AND M[H[5:1],L[2:1]][7:1] and A2[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 3b4 Add M[H[5:1],L[2:1]][7:1] and A2[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] Skip if carry + // 3b8 OR M[H[5:1],L[2:1]][7:1] and A2[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 3bc Subtract M[H[5:1],L[2:1]][7:1] and A2[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] Skip if borrow + const int optype = (inst & 0x0c) >> 2; + const int reg2 = (inst & 0x10) >> 4; + const int n = inst & 0x3; + u8 src2 = get_a1_or_a2(reg2); + u8 m = get_m_data(); + + switch (optype) + { + case 0: // AND + { + m = m & src2; + break; + } + case 1: // ADD + { + m = m + src2; + if (m & 0x80) + m_skip = 1; + break; + } + case 2: // OR + { + m = m | src2; + break; + } + case 3: // MINUS + { + m = m - src2; + if (m & 0x80) + m_skip = 1; + break; + } + } + set_m_data(m); + set_l(n); + } + else if ((inst & 0b1111'1110'0000) == 0b0011'1110'0000) + { + // 0b0011'111r'oonn (where r = reg, o = optype, n = next l value) + // 3e0 AND H[5:1] and A1[5:1], store to H[5:1], N->L[2:1] + // 3e4 Add H[5:1] and A1[5:1], store to H[5:1], N->L[2:1] + // 3e8 OR H[5:1] and A1[5:1], store to H[5:1], N->L[2:1] + // 3ec Subtract H[5:1] and A1[5:1], store to H[5:1], Skip if borrow, N->L[2:1] + // 3f0 AND H[5:1] and A2[5:1], store to H[5:1], N->L[2:1] + // 3f4 Add H[5:1] and A2[5:1], store to H[5:1], N->L[2:1] + // 3f8 OR H[5:1] and A2[5:1], store to H[5:1], N->L[2:1] + // 3fc Subtract H[5:1] and A2[5:1], store to H[5:1], Skip if borrow, N->L[2:1] + const int optype = (inst & 0x0c) >> 2; + const int reg2 = (inst & 0x10) >> 4; + const int n = inst & 0x3; + u8 src2 = get_a1_or_a2(reg2) & 0x1f; + u8 h = get_h(); + + switch (optype) + { + case 0: // AND + { + h = h & src2; + break; + } + case 1: // ADD + { + h = h + src2; + break; + } + case 2: // OR + { + h = h | src2; + break; + } + case 3: // MINUS + { + h = h - src2; + if (h & 0x20) + m_skip = 1; + break; + } + } + set_h(h & 0x1f); + set_l(n); + } + else if ((inst & 0b1111'1100'0010) == 0b0100'0100'0000) + { + // 0b0100'01dg'ks0n (where d = DISP, G = GPE, K = KIE, S = SME, n = A11) + // 440 Set D to DISP, G to GPE, K to KIE, S to SME, N->A[11] + const int d = (inst >> 5) & 0x1; + const int g = (inst >> 4) & 0x1; + const int k = (inst >> 3) & 0x1; + const int s = (inst >> 2) & 0x1; + const int n = inst & 0x1; + set_disp(d); + set_gpe(g); + set_kie(k); + set_sme(s); + set_a11(n); + } + else if (inst == 0b0000'0000'0000) + { + // 000 No Operation + // nothing + } + else if (inst == 0b0000'0000'0100) + { + // 004 Skip if (Gun Port Latch) = 1 + LOGMASKED(LOG_UNHANDLED_OPS, "GPL\n"); + } + else if (inst == 0b0000'0000'1000) + { + // 008 Move H[5:1] to Line Buffer Register[5:1] + u8 h = get_h(); + //LOGMASKED(LOG_UNHANDLED_OPS, "H(%02x)->NRM\n", h); + + // this seems to push a value from RAM into the line buffer for the current 4(?) scanlines + u8 m1 = read_data_mem(get_h_shifted() | 0); + u8 m2 = read_data_mem(get_h_shifted() | 1); + u8 m3 = read_data_mem(get_h_shifted() | 2); + u8 m4 = read_data_mem(get_h_shifted() | 3); + push_to_line_buffer(h, m1,m2,m3,m4); + } + else if (inst == 0b0000'0001'1000) + { + // 018 H[5:1]<->X4[5:1], 0->X4[7:6], 0->X3[7:1], 0->X1'[1], 0->A1'[1], L[2:1]<->L'[2:1] + LOGMASKED(LOG_UNHANDLED_OPS, "H<->X\n"); +#if 1 + // this opcode is not well explained! but X4 etc. are referenced on Data RAM & Register Files which makes + // it even more confusing (while L' isn't referenced anywhere else at all!) + u8 temp; + + temp = m_x4; + m_x4 = get_h(); + m_h = temp; + + temp = m_ldash; + m_ldash = get_l(); + set_l(temp); +#endif + } + else if (inst == 0b0000'0010'0000) + { + // 020 Subroutine End, Pop down address stack + u16 addr = pull_from_stack(); + set_new_pc(addr); + } + else if (inst == 0b0000'0100'1001) + { + // 049 Skip if (4H Horizontal Blank) = 1 + //LOGMASKED(LOG_UNHANDLED_OPS, "4H BLK\n"); + if (get_hbl_4_state()) + m_skip = 1; + } + else if (inst == 0b0000'0100'1010) + { + // 04a Skip if (Vertical Blank) = 1, 0->M[[18:00],[3]][1] + LOGMASKED(LOG_UNHANDLED_OPS, "VBLK\n"); + if (get_vbl_state()) + m_skip = 1; + + // TODO: + // need to do the 0->M[[18:00],[3]][1] bit + } + else if (inst == 0b0000'0100'1100) + { + // 04c Skip if (GP&SW/ input) = 1 + LOGMASKED(LOG_UNHANDLED_OPS, "GPSW/\n"); + } + else if (inst == 0b0000'0101'0100) + { + // 054 Move (A4[7:1],A3[7:1],A2[7:1],A1[7:1]) to M[H[5:1]][28:1] + write_data_mem(get_h_shifted() | 0, get_a1()); + write_data_mem(get_h_shifted() | 1, get_a2()); + write_data_mem(get_h_shifted() | 2, get_a3()); + write_data_mem(get_h_shifted() | 3, get_a4()); + } + else if (inst == 0b0000'0101'1000) + { + // 058 Move M[H[5:1]][28:1] to (A4[7:1],A3[7:1],A2[7:1],A1[7:1]) + u8 m1 = read_data_mem(get_h_shifted() | 0); + u8 m2 = read_data_mem(get_h_shifted() | 1); + u8 m3 = read_data_mem(get_h_shifted() | 2); + u8 m4 = read_data_mem(get_h_shifted() | 3); + set_a1(m1); + set_a2(m2); + set_a3(m3); + set_a4(m4); + } + else if (inst == 0b0000'0101'1100) + { + // 05c Exchange (A4[7:1],A3[7:1],A2[7:1],A1[7:1]) and M[H[5:1]][28:1] + u8 m1 = read_data_mem(get_h_shifted() | 0); + u8 m2 = read_data_mem(get_h_shifted() | 1); + u8 m3 = read_data_mem(get_h_shifted() | 2); + u8 m4 = read_data_mem(get_h_shifted() | 3); + write_data_mem(get_h_shifted() | 0, get_a1()); + write_data_mem(get_h_shifted() | 1, get_a2()); + write_data_mem(get_h_shifted() | 2, get_a3()); + write_data_mem(get_h_shifted() | 3, get_a4()); + set_a1(m1); + set_a2(m2); + set_a3(m3); + set_a4(m4); + } + else if (inst == 0b0000'0110'0000) + { + // 060 Subroutine End, Pop down address stack, Skip + u16 addr = pull_from_stack(); + set_new_pc(addr); + m_skip = 1; + } + else if (inst == 0b0011'0000'1000) + { + // 308 Move A1[7:1] to FLS[7:1], 0->L[2:1] + u8 a1 = get_a1(); + set_fls(a1); + set_l(0); + } + else if (inst == 0b0011'0100'1000) + { + // 348 Move A2[7:1] to FLS[7:1], 0->L[2:1] + u8 a2 = get_a2(); + set_fls(a2); + set_l(0); + } + else if (inst == 0b0011'1000'1000) + { + // 388 Move M[H[5:1],L[2:1]][7:1] to FLS[7:1], 0->L[2:1] + u8 m = get_m_data(); + set_fls(m); + set_l(0); + } + else if (inst == 0b0011'0000'1001) + { + // 309 Move A1[7:1] to FRS[7:1], 1->L[2:1] + u8 a1 = get_a1(); + set_frs(a1); + set_l(1); + } + else if (inst == 0b0011'0100'1001) + { + // 349 Move A2[7:1] to FRS[7:1], 1->L[2:1] + u8 a2 = get_a2(); + set_frs(a2); + set_l(1); + } + else if (inst == 0b0011'1000'1001) + { + // 389 Move M[H[5:1],L[2:1]][7:1] to FRS[7:1], 1->L[2:1] + u8 m = get_m_data(); + set_frs(m); + set_l(1); + } + else if ((inst == 0b0000'0010'1000) || (inst == 0b0000'0010'1001)) + { + // 028 Shift STB[4:1], N->STB[1] + // STB is an input strobe / shifter + const int n = inst & 1; + LOGMASKED(LOG_UNHANDLED_OPS, "0x%d->STB\n", n); + + m_stb = (m_stb << 1) | n; + m_stb &= 0xf; + } + + else if ((inst == 0b0011'0000'1010) || (inst == 0b0011'0000'1011)) + { + // 30a Move A1[7:1] to MODE[7:1], 1N->L[2:1] + const int n = (inst & 0x1) + 2; + u8 a1 = get_a1(); + set_mode(a1); + set_l(n); + } + else if ((inst == 0b0011'01001010) || (inst == 0b0011'0100'1011)) + { + // 34a Move A2[7:1] to MODE[7:1], 1N->L[2:1] + const int n = (inst & 0x1) + 2; + u8 a2 = get_a2(); + set_mode(a2); + set_l(n); + } + else if ((inst == 0b0011'1000'1010) || (inst == 0b00111000'1011)) + { + // 38a Move M[H[5:1],L[2:1]][7:1] to MODE[7:1], 1N->L[2:1] + const int n = (inst & 0x1) + 2; + u8 m = get_m_data(); + set_mode(m); + set_l(n); + } + else if ((inst == 0b0100'0000'0000) || (inst == 0b0100'0000'0001)) + { + // 400 N->A[11] + const int n = inst & 0x1; + set_a11(n); + } + else if ((inst == 0b0100'0000'0010) || (inst == 0b0100'0000'0011)) + { + // 402 Jump to (000,M[H[5:1],L[2:1]][5:1],1N), 0->L[2:1], N->A[11] + const int n = inst & 0x1; + LOGMASKED(LOG_UNHANDLED_OPS, "JPM, 0->L, %d->A11\n", n); + set_a11(n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0000'0000) + { + // 300 N->L[2:1] + const int n = inst & 0x3; + set_l(n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0001'0000) + { + // 310 Move A2[7:1] to A1[7:1], N->L[2:1] + const int n = inst & 0x3; + u8 a2 = get_a2(); + set_a1(a2); + set_l(n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0100'0000) + { + // 340 Move A1[7:1] to A2[7:1], N->L[2:1] + const int n = inst & 0x3; + u8 a1 = get_a1(); + set_a2(a1); + set_l(n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0001'1000) + { + // 318 Right shift A1[7:1], 0->A1[7], N->L[2:1] + const int n = inst & 0x3; + u8 a1 = get_a1(); + a1 = a1 >> 1; + set_a1(a1); + set_l(n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0101'1000) + { + // 358 Right shift A2[7:1], 0->A2[7], N->L[2:1] + const int n = inst & 0x3; + u8 a2 = get_a2(); + a2 = a2 >> 1; + set_a2(a2); + set_l(n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'1001'1000) + { + // 398 Right shift M[H[5:1],L[2:1]][7:1], 0->M[H[5:1],L[2:1]][7], N->L[2:1] + const int n = inst & 0x3; + u8 m = get_m_data(); + m = m >> 1; + set_m_data(m); + set_l(n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0001'1100) + { + // 31c Subtract A1[7:1] and A2[7:1], store to A2[7:1], Skip if borrow, N->L[2:1] + const int n = inst & 0x3; + u8 a1 = get_a1(); + u8 a2 = get_a2(); + a2 = a1 - a2; + if (a2 & 0x80) + m_skip = 1; + set_a2(a2); + set_l(n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0100'1100) + { + // 34c Subtract A2[7:1] and A1[7:1], store to A1[7:1], Skip if borrow, N->L[2:1] + const int n = inst & 0x3; + u8 a1 = get_a1(); + u8 a2 = get_a2(); + a1 = a2 - a1; + if (a1 & 0x80) + m_skip = 1; + set_a1(a1); + set_l(n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1000'0000) + { + // 380 Move A1[7:1] to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 390 Move A2[7:1] to M[H[5:1],L[2:1]][7:1], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + u8 src = get_a1_or_a2(reg); + set_m_data(src); + set_l(n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1000'0100) + { + // 384 Exchange M[H[5:1],L[2:1]][7:1] and A1[7:1], N->L[2:1] + // 394 Exchange M[H[5:1],L[2:1]][7:1] and A2[7:1], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + u8 src = get_a1_or_a2(reg); + u8 m = get_m_data(); + set_m_data(src); + set_a1_or_a2(reg,m); + set_l(n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1000'1100) + { + // 38c Move M[H[5:1],L[2:1]][7:1] to A1[7:1], N->L[2:1] + // 39c Move M[H[5:1],L[2:1]][7:1] to A2[7:1], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + u8 m = get_m_data(); + set_a1_or_a2(reg,m); + set_l(n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1100'0000) + { + // 3c0 Move A1[5:1] to H[5:1], N->L[2:1] + // 3d0 Move A2[5:1] to H[5:1], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + u8 src = get_a1_or_a2(reg); + set_h(src); + set_l(n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1100'1100) + { + // 3cc Move H[5:1] to A1[5:1], 0->A1[7:6], N->L[2:1] + // 3dc Move H[5:1] to A2[5:1], 0->A2[7:6], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + u8 h = get_h() & 0x1f; + set_a1_or_a2(reg,h); + set_l(n); + } + else if ((inst & 0b1111'1011'0011) == 0b0000'0011'0000) + { + // 30 Skip if (PD1 input) = 1 + // 34 Skip if (PD2 input) = 1 + // 38 Skip if (PD3 input) = 1 + // 3c Skip if (PD4 input) = 1 + // 70 Skip if (PD1 input) = 0 + // 74 Skip if (PD2 input) = 0 + // 78 Skip if (PD3 input) = 0 + // 7c Skip if (PD4 input) = 0 + const int which = (inst & 0x00c) >> 2; + const int inv = inst & 0x40; + LOGMASKED(LOG_UNHANDLED_OPS, "PD%d %sJ\n", which + 1, inv ? "/" : ""); + } + else + { + LOGMASKED(LOG_UNHANDLED_OPS, "%04x \n", inst); + } +} + +void upd777_cpu_device::execute_run() +{ + while (m_icount > 0) + { + if (m_skip) + { + fetch(); + m_skip = 0; + } + + debugger_instruction_hook(m_pc); + do_op(); + m_icount--; + } +} + +void upd777_cpu_device::execute_set_input(int inputnum, int state) +{ +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +bool upd777_cpu_device::get_vbl_state() +{ + int vpos = m_screen->vpos(); + if (vpos > 240) + return true; + + return false; +} + +bool upd777_cpu_device::get_hbl_4_state() +{ + // I *think* this is Hblank for every 4th line (so a new display list can be written?) + int vpos = m_screen->vpos(); + if ((vpos % 4) == 0) + { + int hpos = m_screen->hpos(); + if (hpos > 200) + return true; + } + + return false; +} + +uint32_t upd777_cpu_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + // this needs to be scanline based, drawing whatever has been pushed to the linebuffer for the current + // group of scanlines! + + bitmap.fill(0, cliprect); + gfx_element *gfx = m_gfxdecode->gfx(0); + gfx_element *gfx2 = m_gfxdecode->gfx(1); + + for (int i = 0; i <= 0x18; i++) + { + u8 s0 = m_datamem[(i * 4) + 0]; + u8 s1 = m_datamem[(i * 4) + 1]; + u8 s2 = m_datamem[(i * 4) + 2]; + u8 s3 = m_datamem[(i * 4) + 3]; + + int ypos = (s0 & 0x7e) >> 1; + //int prio = (s0 & 0x01); + int xpos = (s1 & 0x7f); + int patn = (s2 & 0x7f); + //int ylow = (s3 & 0x70); + int pal = (s3 & 0x0e) >> 1; + //int ysub = (s3 & 0x01); + + if (patn<0x70) + gfx->zoom_transpen(bitmap, cliprect, patn, pal, 0, 0, xpos * 4, ypos * 4, 0x40000, 0x40000, 0); + else + gfx2->zoom_transpen(bitmap, cliprect, patn-0x70, pal, 0, 0, xpos * 4, ypos * 4, 0x40000, 0x40000, 0); + } + + return 0; +} + +// documentation says patterns 0x00 - 0x6e are 7x7 +// and patterns 0x70 - 0x7e are 8x7 +// but they all seem to be stored at 11x7, just with some columns blank? +// this is probably because of how they were read out, over 11 data lines + +// 0x00-0x2f are 'Normal (7x7) +// 0x30-0x67 are 'Bent' (7x7) +// 0x68-0x6f are 'Y Repeat' (7x7) +// 0x70-0x77 are 'XY Repeat' (8x7) +// 0x78-0x7f are 'X Repeat' (8x7) +// +// NOTE, sprite patterns *7 and *f are unused so documentation expresses these ranges as to 66, 6e etc. rather than 67 6f +// +// it isn't clear how the 'Bent' effect etc. is enabled, as clearly not all patterns in this range should use it? + +static const gfx_layout test_layout = +{ + 7,7, + 0x70, + 1, + { 0 }, + { 4,5,6,7,8,9,10 }, + { 0*11,1*11,2*11,3*11,4*11,5*11,6*11 }, + 7*11 +}; + +static const gfx_layout test2_layout = +{ + 8,7, + 0x10, + 1, + { 0 }, + { 3,4,5,6,7,8,9,10 }, + { 0*11,1*11,2*11,3*11,4*11,5*11,6*11 }, + 7*11 +}; + +static GFXDECODE_START( gfx_ud777 ) + GFXDECODE_ENTRY( "patterns", 0x000, test_layout, 0, 8 ) + GFXDECODE_ENTRY( "patterns", 0x436, test2_layout, 0, 8 ) +GFXDECODE_END + + +void upd777_cpu_device::palette_init(palette_device &palette) const +{ + // just a fake palette for now + for (int i = 0; i < palette.entries(); i++) + { + if (i & 1) + { + palette.set_pen_color(i, rgb_t(((i >> 1) & 1) ? 0xff : 0x7f, ((i >> 2) & 1) ? 0xff : 0x7f, ((i >> 3) & 1) ? 0xff : 0x7f)); + } + else + { + palette.set_pen_color(i, rgb_t(0, 0, 0)); + } + } +} + +void upd777_cpu_device::push_to_line_buffer(u8 h, u8 m1, u8 m2, u8 m3, u8 m4) +{ + logerror("sprite %02x pushed to line buffer at scanline %d hpos %d: details %02x %02x %02x %02x\n", h, m_screen->vpos(), m_screen->hpos(), m1, m2, m3, m4); +} + +TIMER_DEVICE_CALLBACK_MEMBER(upd777_cpu_device::scanline_timer) +{ + int scanline = param; + + logerror("scanline %d\n", scanline); +} + +void upd777_cpu_device::device_add_mconfig(machine_config &config) +{ + // or pass the screen from the driver? + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_refresh_hz(60); + m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2000)); + m_screen->set_size(512, 256); + m_screen->set_visarea(0, 512-1, 0, 256-0-1); + m_screen->set_screen_update(FUNC(upd777_cpu_device::screen_update)); + m_screen->set_palette(m_palette); + + TIMER(config, "scantimer").configure_scanline(FUNC(upd777_cpu_device::scanline_timer), "screen", 0, 1); + + GFXDECODE(config, m_gfxdecode, m_palette, gfx_ud777); + PALETTE(config, m_palette, FUNC(upd777_cpu_device::palette_init), 32 * 3).set_entries(0x10); +} + +ROM_START( upd777 ) + ROM_REGION16_BE( 0x1000, "prg", ROMREGION_ERASEFF ) + ROM_REGION( 0x4d0, "patterns", ROMREGION_ERASEFF ) +ROM_END + +const tiny_rom_entry *upd777_cpu_device::device_rom_region() const +{ + return ROM_NAME(upd777); +} + diff --git a/src/devices/cpu/upd777/upd777.h b/src/devices/cpu/upd777/upd777.h new file mode 100644 index 00000000000..cdb787fd104 --- /dev/null +++ b/src/devices/cpu/upd777/upd777.h @@ -0,0 +1,165 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb + +#ifndef MAME_CPU_UPD777_UPD777_H +#define MAME_CPU_UPD777_UPD777_H + +#pragma once + +#include "machine/timer.h" + +#include "emupal.h" +#include "screen.h" + + +class upd777_cpu_device : public cpu_device +{ +public: + upd777_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + enum { + UPD777_PC = 0, + UPD777_A1, + UPD777_A2, + UPD777_A3, + UPD777_A4, + UPD777_SKIP, + UPD777_H, + UPD777_L, + UPD777_ADDR_STACK0, + UPD777_ADDR_STACK1, + UPD777_ADDR_STACK2, + UPD777_ADDR_STACK_POS, + }; + + u16* get_prgregion() { return &m_prgregion[0]; } + u8* get_patregion() { return &m_patregion[0]; } + + auto in_cb() { return m_port_in.bind(); } + +protected: + upd777_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor data); + + virtual void device_start() override; + virtual void device_reset() override; + + virtual void execute_run() override; + virtual void execute_set_input(int inputnum, int state) override; + + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual std::unique_ptr create_disassembler() override; + + virtual space_config_vector memory_space_config() const override; + + bool get_vbl_state(); + bool get_hbl_4_state(); + + + void internal_map(address_map &map); + void internal_data_map(address_map &map); + + required_shared_ptr m_datamem; + +private: + void increment_pc(); + u16 fetch(); + void do_op(); + + + u8 get_l() const; + void set_l(int l); + u8 get_h_shifted() const; + u8 get_h() const; + void set_h(int h); + void set_a11(int a11); + void set_new_pc(int newpc); + + void set_frs(u8 frs); + void set_fls(u8 fls); + void set_mode(u8 mode); + + u8 get_m_data(); + void set_m_data(u8 data); + + u8 get_a1() const; + u8 get_a2() const; + u8 get_a3() const; + u8 get_a4() const; + u8 get_a1_or_a2(int reg) const; + + void set_a1(u8 data); + void set_a2(u8 data); + void set_a3(u8 data); + void set_a4(u8 data); + void set_a1_or_a2(int reg, u8 value); + + void set_disp(u8 data); + void set_gpe(u8 data); + void set_kie(u8 data); + void set_sme(u8 data); + + u8 get_kie() const; + u8 get_sme() const; + + u8 read_data_mem(u8 addr); + void write_data_mem(u8 addr, u8 data); + void push_to_stack(u16 addr); + u16 pull_from_stack(); + + address_space_config m_space_config; + address_space_config m_data_config; + + memory_access<11, 1, -1, ENDIANNESS_BIG>::specific m_space; + memory_access<8, 0, 0, ENDIANNESS_BIG>::specific m_data; + + u32 m_ppc; + u32 m_pc; + s32 m_icount; + u8 m_skip; + u8 m_a[4]; // A1 to A4 + u8 m_h; + u8 m_l; + u16 m_stack[3]; // 3 11-bit registers + u8 m_stackpos; + + u8 m_frs; + u8 m_fls; + + u8 m_mode; + + u8 m_stb; + + // what are these, used by H<->X opcode + u8 m_ldash; + u8 m_x4; + + // single bit enable registers? + u8 m_disp; + u8 m_gpe; + u8 m_kie; + u8 m_sme; + + ///////////////////////////////////// VIDEO RELATED + + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + void push_to_line_buffer(u8 h, u8 m1, u8 m2, u8 m3, u8 m4); + + void palette_init(palette_device &palette) const; + + TIMER_DEVICE_CALLBACK_MEMBER(scanline_timer); + + required_device m_gfxdecode; + required_device m_palette; + required_device m_screen; + required_region_ptr m_prgregion; + required_region_ptr m_patregion; + + devcb_read8 m_port_in; +}; + +DECLARE_DEVICE_TYPE(UPD777, upd777_cpu_device) + +#endif // MAME_CPU_UPD777_UPD777_H diff --git a/src/devices/cpu/upd777/upd777dasm.cpp b/src/devices/cpu/upd777/upd777dasm.cpp new file mode 100644 index 00000000000..fd7597b8bab --- /dev/null +++ b/src/devices/cpu/upd777/upd777dasm.cpp @@ -0,0 +1,504 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb + +#include "emu.h" +#include "upd777dasm.h" + +upd777_disassembler::upd777_disassembler() + : util::disasm_interface() +{ + // init lfsr pc lut + for (u32 i = 0, pc = 0; i < 0x7f; i++) + { + m_l2r[i] = pc; + m_r2l[pc] = i; + const int top1 = (pc & 0x40) >> 6; + const int top2 = (pc & 0x20) >> 5; + const int nor = (top1 ^ top2) ^ 1; + pc = (pc << 1) | nor; + pc &= 0x7f; + } + m_l2r[0x7f] = 0x7f; + m_r2l[0x7f] = 0x7f; +} + + +std::string upd777_disassembler::get_300optype_name(int optype) +{ + switch (optype) + { + case 0x00: return "."; // 'AND' expressed as '·' in documentation, but disassembler isn't keen on that + case 0x01: return "+"; + case 0x02: return "v"; // 'OR' + case 0x03: return "-"; + } + return ""; +} + +std::string upd777_disassembler::get_200optype_name(int optype) +{ + switch (optype) + { + case 0x00: return "."; // 'AND' expressed as '·' in documentation, but disassembler isn't keen on that + case 0x01: return ""; + case 0x02: return "="; + case 0x03: return "-"; + } + return ""; +} + +std::string upd777_disassembler::get_reg_name(int reg) +{ + switch (reg) + { + case 0x00: return "A1"; // general reg A1 + case 0x01: return "A2"; // general reg A2 + case 0x02: return "M"; // content of memory + case 0x03: return "H"; // high address + } + return ""; +} + +offs_t upd777_disassembler::disassemble(std::ostream &stream, offs_t pc, const upd777_disassembler::data_buffer &opcodes, const upd777_disassembler::data_buffer ¶ms) +{ + u16 inst = opcodes.r16(pc); + + if (inst >= 0b0000'1000'0000 && inst <= 0b0000'1111'1111) + { + // 080 - 0ff Skip if (M[H[5:1],L[2:1]][7:1]-K[7:1]) makes borrow + const int k = inst & 0x7f; + util::stream_format(stream, "M-0x%02x", k); + } + else if (inst >= 0b0001'0000'0000 && inst <= 0b0001'0111'1111) + { + // 100-17f M[H[5:1],L[2:1]][7:1]+K[7:1]->M[H[5:1],L[2:1]][7:1], Skip if carry, N->L[2:1] + const int k = inst & 0x1f; + const int n = (inst >> 5) & 0x3; + util::stream_format(stream, "M+0x%02x->M, 0x%d->L", k, n); + } + else if (inst >= 0b0001'1000'0000 && inst <= 0b0001'1111'1111) + { + // 180-1ff M[H[5:1],L[2:1]][7:1]-K[7:1]->M[H[5:1],L[2:1]][7:1], Skip if borrow, N->L[2:1] + const int k = inst & 0x1f; + const int n = (inst >> 5) & 0x3; + util::stream_format(stream, "M-0x%02x->M, 0x%d->L", k, n); + } + else if (inst >= 0b0100'1000'0000 && inst <= 0b0100'1011'1111) + { + // 480-4bf H[5:1]-K[5:1]->H[5:1], Skip if borrow + const int k = inst & 0x1f; + util::stream_format(stream, "H-0x%02x->H BOJ", k); + } + else if (inst >= 0b0100'1100'0000 && inst <= 0b0100'1111'1111) + { + // 4c0 - 4ff H[5:1]+K[5:1]->H[5:1], Skip if carry + const int k = inst & 0x1f; + util::stream_format(stream, "H+0x%02x->H CAJ", k); + } + else if (inst >= 0b0101'0000'0000 && inst <= 0b0101'0111'1111) + { + // 500 - 57f + // When (KIE=0)&(SME=0), Store K[7:1] to M[H[5:1],L[2:1]][7:1] + // When (KIE=1), Store KIN[7:1] to M[H[5:1],L[2:1]][7:1] + // When (SME=1), Store HCL[7:1] to M[H[5:1],L[2:1]][7:1] + const int k = inst & 0x7f; + util::stream_format(stream, "0x%02x->M", k); + } + else if (inst >= 0b0101'1000'0000 && inst <= 0b0101'1111'1111) + { + // 580 - 5ff Store K[7:6] to L[2:1] and K[5:1] to H[5:1] + const int k = inst & 0x7f; + util::stream_format(stream, "0x%02x->L,H", k); + } + else if (inst >= 0b0110'0000'0000 && inst <= 0b0111'1111'1111) + { + // 600-67f Store K[7:1] to A1[7:1] + // 680-6ff Store K[7:1] to A2[7:1] + // 700-77f Store K[7:1] to A3[7:1] + // 780-7ff Store K[7:1] to A4[7:1] + const int reg = (inst & 0x180) >> 7; + const int k = inst & 0x7f; + util::stream_format(stream, "0x%02x->A%d", k, reg+1); + } + else if (inst >= 0b1000'0000'0000 && inst <= 0b1011'1111'1111) + { + // 800 - bff Move K[10:1] to A[10:1], Jump to A[11:1] + u16 fulladdress = (pc & 0x400) | (inst & 0x3ff); + util::stream_format(stream, "JP 0x%03x (%01x:%02x)", fulladdress, (fulladdress & 0x780)>>7, inst & 0x07f); + } + else if (inst >= 0b1100'0000'0000 && inst <= 0b1111'1111'1111) + { + // c00 - fff Move K[10:1] to A[10:1], 0 to A11, Jump to A[11:1], Push next A[11:1] up to ROM address stack + const int k = inst & 0x3ff; + util::stream_format(stream, "JS 0x%03x (%01x:%02x)", k & 0x3ff, (k & 0x380)>>7, k & 0x07f); + } + else if (((inst & 0b1111'0000'0000) == 0b0010'0000'0000) && ((inst & 0b0000'0000'1100) != 0b0000'0000'0100)) + { + // 0b0010'rrnR'oonn where rr = reg1 (A1, A2, M or H), n = invert condition, R = reg2 (A1 or A2) and oo = optype (only 0,2,3 are valid, no cases here for 1) nn = next l value + // + // optype · (AND) + // 200 Skip if (A1[7:1]·A1[7:1]) makes zero, N->L[2:1] + // 220 Skip if (A1[7:1]·A1[7:1]) makes non zero, N->L[2:1] + // 210 Skip if (A1[7:1]·A2[7:1]) makes zero, N->L[2:1] + // 230 Skip if (A1[7:1]·A2[7:1]) makes non zero, N->L[2:1] + // 240 Skip if (A2[7:1]·A1[7:1]) makes zero, N->L[2:1] + // 260 Skip if (A2[7:1]·A1[7:1]) makes non zero, N->L[2:1] + // 250 Skip if (A2[7:1]·A2[7:1]) makes zero, N->L[2:1] + // 270 Skip if (A2[7:1]·A2[7:1]) makes non zero, N->L[2:1] + // 280 Skip if (M[H[5:1],L[2:1]][7:1]·A1[7:1]) makes zero, N->L[2:1] + // 2a0 Skip if (M[H[5:1],L[2:1]][7:1]·A1[7:1]) makes non zero, N->L[2:1] + // 290 Skip if (M[H[5:1],L[2:1]][7:1]·A2[7:1]) makes zero, N->L[2:1] + // 2b0 Skip if (M[H[5:1],L[2:1]][7:1]·A2[7:1]) makes non zero, N->L[2:1] + // 2c0 Skip if (H[5:1]·A1[5:1]) makes zero, N->L[2:1] + // 2e0 Skip if (H[5:1]·A1[5:1]) makes non zero, N->L[2:1] + // 2d0 Skip if (H[5:1]·A2[5:1]) makes zero, N->L[2:1] + // 2f0 Skip if (H[5:1]·A2[5:1]) makes non zero, N->L[2:1] + + // optype = (these are expressed as x=y in the opcopde syntax, but x-y in the description, in reality it seems to act as 'CMP' so x-y = 0) + // 208 Skip if (A1[7:1]-A1[7:1]) makes zero, N->L[2:1] + // 228 Skip if (A1[7:1]-A1[7:1]) makes non zero, N->L[2:1] + // 218 Skip if (A1[7:1]-A2[7:1]) makes zero, N->L[2:1] + // 238 Skip if (A1[7:1]-A2[7:1]) makes non zero, N->L[2:1] + // 248 Skip if (A2[7:1]-A1[7:1]) makes zero, N->L[2:1] + // 268 Skip if (A2[7:1]-A1[7:1]) makes non zero, N->L[2:1] + // 258 Skip if (A2[7:1]-A2[7:1]) makes zero, N->L[2:1] + // 278 Skip if (A2[7:1]-A2[7:1]) makes non zero, N->L[2:1] + // 288 Skip if (M[H[5:1],L[2:1]][7:1]-A1[7:1]) makes zero, N->L[2:1] + // 2a8 Skip if (M[H[5:1],L[2:1]][7:1]-A1[7:1]) makes non zero, N->L[2:1] + // 298 Skip if (M[H[5:1],L[2:1]][7:1]-A2[7:1]) makes zero, N->L[2:1] + // 2b8 Skip if (M[H[5:1],L[2:1]][7:1]-A2[7:1]) makes non zero, N->L[2:1] + // 2c8 Skip if (H[5:1]-A1[5:1]) makes zero, N->L[2:1] + // 2e8 Skip if (H[5:1]-A1[5:1]) makes non zero, N->L[2:1] + // 2d8 Skip if (H[5:1]-A2[5:1]) makes zero, N->L[2:1] + // 2f8 Skip if (H[5:1]-A2[5:1]) makes non zero, N->L[2:1] + + // optype - + // 20c Skip if (A1[7:1]-A1[7:1]) makes borrow, N->L[2:1] + // 22c Skip if (A1[7:1]-A1[7:1]) makes non borrow, N->L[2:1] + // 21c Skip if (A1[7:1]-A2[7:1]) makes borrow, N->L[2:1] + // 23c Skip if (A1[7:1]-A2[7:1]) makes non borrow, N->L[2:1] + // 24c Skip if (A2[7:1]-A1[7:1]) makes borrow, N->L[2:1] + // 26c Skip if (A2[7:1]-A1[7:1]) makes non borrow, N->L[2:1] + // 25c Skip if (A2[7:1]-A2[7:1]) makes borrow, N->L[2:1] + // 27c Skip if (A2[7:1]-A2[7:1]) makes non borrow, N->L[2:1] + // 28c Skip if (M[H[5:1],L[2:1]][7:1]-A1[7:1]) makes borrow, N->L[2:1] + // 2ac Skip if (M[H[5:1],L[2:1]][7:1]-A1[7:1]) makes non borrow, N->L[2:1] + // 29c Skip if (M[H[5:1],L[2:1]][7:1]-A2[7:1]) makes borrow, N->L[2:1] + // 2bc Skip if (M[H[5:1],L[2:1]][7:1]-A2[7:1]) makes non borrow, N->L[2:1] + // 2cc Skip if (H[5:1]-A1[5:1]) makes borrow, N->L[2:1] + // 2ec Skip if (H[5:1]-A1[5:1]) makes non borrow, N->L[2:1] + // 2dc Skip if (H[5:1]-A2[5:1]) makes borrow, N->L[2:1] + // 2fc Skip if (H[5:1]-A2[5:1]) makes non borrow, N->L[2:1] + const int non = inst & 0x20; + const int optype = (inst & 0x0c) >> 2; + const int reg1 = (inst & 0xc0) >> 6; + const int reg2 = (inst & 0x10) >> 4; + const int n = inst & 0x3; + util::stream_format(stream, "%s%s%s, 0x%d->L %s%s", get_reg_name(reg1), get_200optype_name(optype), get_reg_name(reg2), n, (optype == 3) ? "BOJ" : "EQJ", non ? "/" : ""); + } + else if ((inst & 0b1111'1010'0000) == 0b0011'0010'0000) + { + // 0b0011'0r1R'oonn (where r = reg1, R = reg2, o = optype, and n = next l value) + // 320 AND A1[7:1] and A1[7:1], store to A1[7:1], N->L[2:1] + // 324 Add A1[7:1] and A1[7:1], store to A1[7:1], N->L[2:1] + // 328 OR A1[7:1] and A1[7:1], store to A1[7:1], N->L[2:1] + // 32c Subtract A1[7:1] and A1[7:1], store to A1[7:1], Skip if borrow, N->L[2:1] + // 330 AND A1[7:1] and A2[7:1], store to A1[7:1], N->L[2:1] + // 334 Add A1[7:1] and A2[7:1], store to A1[7:1], N->L[2:1] + // 338 OR A1[7:1] and A2[7:1], store to A1[7:1], N->L[2:1] + // 33c Subtract A1[7:1] and A2[7:1], store to A1[7:1], Skip if borrow, N->L[2:1] + // 360 AND A2[7:1] and A1[7:1], store to A2[7:1], N->L[2:1] + // 364 Add A2[7:1] and A1[7:1], store to A2[7:1], N->L[2:1] + // 368 OR A2[7:1] and A1[7:1], store to A2[7:1], N->L[2:1] + // 36c Subtract A2[7:1] and A1[7:1], store to A2[7:1], Skip if borrow, N->L[2:1] + // 370 AND A2[7:1] and A2[7:1], store to A2[7:1], N->L[2:1] + // 374 Add A2[7:1] and A2[7:1], store to A2[7:1], N->L[2:1] + // 378 OR A2[7:1] and A2[7:1], store to A2[7:1], N->L[2:1] + // 37c Subtract A2[7:1] and A2[7:1], store to A2[7:1], Skip if borrow, N->L[2:1] + const int optype = (inst & 0x0c) >> 2; + const int reg2 = (inst & 0x10) >> 4; + const int reg1 = (inst & 0x40) >> 6; + const int n = inst & 0x3; + util::stream_format(stream, "%s%s%s->%s, 0x%d->L %s", get_reg_name(reg1), get_300optype_name(optype), get_reg_name(reg2), get_reg_name(reg1), n, (optype == 3) ? "BOJ" : ""); + } + else if ((inst & 0b1111'1110'0000) == 0b0011'1010'0000) + { + // 0b0011'101r'oonn (where r = reg, o = optype, n = next l value) + // 3a0 AND M[H[5:1],L[2:1]][7:1] and A1[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 3a4 Add M[H[5:1],L[2:1]][7:1] and A1[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] Skip if carry + // 3a8 OR M[H[5:1],L[2:1]][7:1] and A1[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 3ac Subtract M[H[5:1],L[2:1]][7:1] and A1[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] Skip if borrow + // 3b0 AND M[H[5:1],L[2:1]][7:1] and A2[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 3b4 Add M[H[5:1],L[2:1]][7:1] and A2[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] Skip if carry + // 3b8 OR M[H[5:1],L[2:1]][7:1] and A2[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 3bc Subtract M[H[5:1],L[2:1]][7:1] and A2[7:1], store to M[H[5:1],L[2:1]][7:1], N->L[2:1] Skip if borrow + const int optype = (inst & 0x0c) >> 2; + const int reg2 = (inst & 0x10) >> 4; + const int n = inst & 0x3; + util::stream_format(stream, "M%s%s->M, 0x%d->L", get_300optype_name(optype), get_reg_name(reg2), n); + } + else if ((inst & 0b1111'1110'0000) == 0b0011'1110'0000) + { + // 0b0011'111r'oonn (where r = reg, o = optype, n = next l value) + // 3e0 AND H[5:1] and A1[5:1], store to H[5:1], N->L[2:1] + // 3e4 Add H[5:1] and A1[5:1], store to H[5:1], N->L[2:1] + // 3e8 OR H[5:1] and A1[5:1], store to H[5:1], N->L[2:1] + // 3ec Subtract H[5:1] and A1[5:1], store to H[5:1], Skip if borrow, N->L[2:1] + // 3f0 AND H[5:1] and A2[5:1], store to H[5:1], N->L[2:1] + // 3f4 Add H[5:1] and A2[5:1], store to H[5:1], N->L[2:1] + // 3f8 OR H[5:1] and A2[5:1], store to H[5:1], N->L[2:1] + // 3fc Subtract H[5:1] and A2[5:1], store to H[5:1], Skip if borrow, N->L[2:1] + const int optype = (inst & 0x0c) >> 2; + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + util::stream_format(stream, "H%s%s->H, 0x%d->L", get_300optype_name(optype), get_reg_name(reg), n); + } + else if ((inst & 0b1111'1100'0010) == 0b0100'0100'0000) + { + // 0b0100'01dg'ks0n (where d = DISP, G = GPE, K = KIE, S = SME, n = A11) + // 440 Set D to DISP, G to GPE, K to KIE, S to SME, N->A[11] + const int d = (inst >> 5) & 0x1; + const int g = (inst >> 4) & 0x1; + const int k = (inst >> 3) & 0x1; + const int s = (inst >> 2) & 0x1; + const int n = inst & 0x1; + util::stream_format(stream, "%d->D, %d->G, %d->K, %d->S, %d->A11", d, g, k, s, n); + } + else if (inst == 0b0000'0000'0000) + { + // 000 No Operation + util::stream_format(stream, "NOP"); + } + else if (inst == 0b0000'0000'0100) + { + // 004 Skip if (Gun Port Latch) = 1 + util::stream_format(stream, "GPL"); + } + else if (inst == 0b0000'0000'1000) + { + // 008 Move H[5:1] to Line Buffer Register[5:1] + util::stream_format(stream, "H->NRM"); + } + else if (inst == 0b0000'0001'1000) + { + // 018 H[5:1]<->X4[5:1], 0->X4[7:6], 0->X3[7:1], 0->X1'[1], 0->A1'[1], L[2:1]<->L'[2:1] + util::stream_format(stream, "H<->X"); + } + else if (inst == 0b0000'0010'0000) + { + // 020 Subroutine End, Pop down address stack + util::stream_format(stream, "SRE"); + } + else if (inst == 0b0000'0100'1001) + { + // 049 Skip if (4H Horizontal Blank) = 1 + util::stream_format(stream, "4H BLK"); + } + else if (inst == 0b0000'0100'1010) + { + // 04a Skip if (Vertical Blank) = 1, 0->M[[18:00],[3]][1] + util::stream_format(stream, "VBLK"); + } + else if (inst == 0b0000'0100'1100) + { + // 04c Skip if (GP&SW/ input) = 1 + util::stream_format(stream, "GPSW/"); + } + else if (inst == 0b0000'0101'0100) + { + // 054 Move (A4[7:1],A3[7:1],A2[7:1],A1[7:1]) to M[H[5:1]][28:1] + util::stream_format(stream, "A->MA"); + } + else if (inst == 0b0000'0101'1000) + { + // 058 Move M[H[5:1]][28:1] to (A4[7:1],A3[7:1],A2[7:1],A1[7:1]) + util::stream_format(stream, "MA->A"); + } + else if (inst == 0b0000'0101'1100) + { + // 05c Exchange (A4[7:1],A3[7:1],A2[7:1],A1[7:1]) and M[H[5:1]][28:1] + util::stream_format(stream, "MA<->A"); + } + else if (inst == 0b0000'0110'0000) + { + // 060 Subroutine End, Pop down address stack, Skip + util::stream_format(stream, "SRE+1"); + } + else if (inst == 0b0011'0000'1000) + { + // 308 Move A1[7:1] to FLS[7:1], 0->L[2:1] + util::stream_format(stream, "A1->FLS, 0->L"); + } + else if (inst == 0b0011'0100'1000) + { + // 348 Move A2[7:1] to FLS[7:1], 0->L[2:1] + util::stream_format(stream, "A2->FLS, 0->L"); + } + else if (inst == 0b0011'1000'1000) + { + // 388 Move M[H[5:1],L[2:1]][7:1] to FLS[7:1], 0->L[2:1] + util::stream_format(stream, "M->FLS, 0->L"); + } + else if (inst == 0b0011'0000'1001) + { + // 309 Move A1[7:1] to FRS[7:1], 1->L[2:1] + util::stream_format(stream, "A1->FRS, 1->L"); + } + else if (inst == 0b0011'0100'1001) + { + // 349 Move A2[7:1] to FRS[7:1], 1->L[2:1] + util::stream_format(stream, "A2->FRS, 1->L"); + } + else if (inst == 0b0011'1000'1001) + { + // 389 Move M[H[5:1],L[2:1]][7:1] to FRS[7:1], 1->L[2:1] + util::stream_format(stream, "M->FRS, 1->L"); + } + else if ((inst == 0b0000'0010'1000) || (inst == 0b0000'0010'1001)) + { + // 028 Shift STB[4:1], N->STB[1] + // STB is an input strobe / shifter + const int n = inst & 1; + util::stream_format(stream, "0x%d->STB", n); + } + else if ((inst == 0b0011'0000'1010) || (inst == 0b0011'0000'1011)) + { + // 30a Move A1[7:1] to MODE[7:1], 1N->L[2:1] + const int n = (inst & 0x1) + 2; + util::stream_format(stream, "A1->MODE, 0x%d->L", n); + } + else if ((inst == 0b0011'01001010) || (inst == 0b0011'0100'1011)) + { + // 34a Move A2[7:1] to MODE[7:1], 1N->L[2:1] + const int n = (inst & 0x1) + 2; + util::stream_format(stream, "A2->MODE, 0x%d->L", n); + } + else if ((inst == 0b0011'1000'1010) || (inst == 0b00111000'1011)) + { + // 38a Move M[H[5:1],L[2:1]][7:1] to MODE[7:1], 1N->L[2:1] + const int n = (inst & 0x1) + 2; + util::stream_format(stream, "M->MODE, 0x%d->L", n); + } + + else if ((inst == 0b0100'0000'0000) || (inst == 0b0100'0000'0001)) + { + // 400 N->A[11] + const int n = inst & 0x1; + util::stream_format(stream, "%d->A11", n); + } + else if ((inst == 0b0100'0000'0010) || (inst == 0b0100'0000'0011)) + { + // 402 Jump to (000,M[H[5:1],L[2:1]][5:1],1N), 0->L[2:1], N->A[11] + const int n = inst & 0x1; + util::stream_format(stream, "JPM, 0->L, %d->A11", n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0000'0000) + { + // 300 N->L[2:1] + const int n = inst & 0x3; + util::stream_format(stream, "0x%d->L", n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0001'0000) + { + // 310 Move A2[7:1] to A1[7:1], N->L[2:1] + const int n = inst & 0x3; + util::stream_format(stream, "A2->A1, 0x%d->L", n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0100'0000) + { + // 340 Move A1[7:1] to A2[7:1], N->L[2:1] + const int n = inst & 0x3; + util::stream_format(stream, "A1->A2, 0x%d->L", n); + } + + else if ((inst & 0b1111'1111'1100) == 0b0011'0001'1000) + { + // 318 Right shift A1[7:1], 0->A1[7], N->L[2:1] + const int n = inst & 0x3; + util::stream_format(stream, "A1->RS, 0x%d->L", n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0101'1000) + { + // 358 Right shift A2[7:1], 0->A2[7], N->L[2:1] + const int n = inst & 0x3; + util::stream_format(stream, "A2->RS, 0x%d->L", n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'1001'1000) + { + // 398 Right shift M[H[5:1],L[2:1]][7:1], 0->M[H[5:1],L[2:1]][7], N->L[2:1] + const int n = inst & 0x3; + util::stream_format(stream, "M->RS, 0x%d->L", n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0001'1100) + { + // 31c Subtract A1[7:1] and A2[7:1], store to A2[7:1], Skip if borrow, N->L[2:1] + const int n = inst & 0x3; + util::stream_format(stream, "A1-A2->A2, 0x%d->L", n); + } + else if ((inst & 0b1111'1111'1100) == 0b0011'0100'1100) + { + // 34c Subtract A2[7:1] and A1[7:1], store to A1[7:1], Skip if borrow, N->L[2:1] + const int n = inst & 0x3; + util::stream_format(stream, "A2-A1->A1, 0x%d->L", n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1000'0000) + { + // 380 Move A1[7:1] to M[H[5:1],L[2:1]][7:1], N->L[2:1] + // 390 Move A2[7:1] to M[H[5:1],L[2:1]][7:1], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + util::stream_format(stream, "A%d->M, 0x%d->L", reg + 1, n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1000'0100) + { + // 384 Exchange M[H[5:1],L[2:1]][7:1] and A1[7:1], N->L[2:1] + // 394 Exchange M[H[5:1],L[2:1]][7:1] and A2[7:1], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + util::stream_format(stream, "M<->A%d, 0x%d->L", reg + 1, n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1000'1100) + { + // 38c Move M[H[5:1],L[2:1]][7:1] to A1[7:1], N->L[2:1] + // 39c Move M[H[5:1],L[2:1]][7:1] to A2[7:1], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + util::stream_format(stream, "M->A%d, 0x%d->L", reg + 1, n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1100'0000) + { + // 3c0 Move A1[5:1] to H[5:1], N->L[2:1] + // 3d0 Move A2[5:1] to H[5:1], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + util::stream_format(stream, "A%d->H, 0x%d->L", reg + 1, n); + } + else if ((inst & 0b1111'1110'1100) == 0b0011'1100'1100) + { + // 3cc Move H[5:1] to A1[5:1], 0->A1[7:6], N->L[2:1] + // 3dc Move H[5:1] to A2[5:1], 0->A2[7:6], N->L[2:1] + const int reg = (inst & 0x10) >> 4; + const int n = inst & 0x3; + util::stream_format(stream, "H->A%d, 0x%d->L", reg + 1, n); + } + else if ((inst & 0b1111'1011'0011) == 0b0000'0011'0000) + { + // 30 Skip if (PD1 input) = 1 + // 34 Skip if (PD2 input) = 1 + // 38 Skip if (PD3 input) = 1 + // 3c Skip if (PD4 input) = 1 + // 70 Skip if (PD1 input) = 0 + // 74 Skip if (PD2 input) = 0 + // 78 Skip if (PD3 input) = 0 + // 7c Skip if (PD4 input) = 0 + const int which = (inst & 0x00c) >> 2; + const int inv = inst & 0x40; + util::stream_format(stream, "PD%d %sJ", which + 1, inv ? "/" : ""); + } + else + { + util::stream_format(stream, "%04x ", inst); + } + + return 1; +} diff --git a/src/devices/cpu/upd777/upd777dasm.h b/src/devices/cpu/upd777/upd777dasm.h new file mode 100644 index 00000000000..b7729edbc30 --- /dev/null +++ b/src/devices/cpu/upd777/upd777dasm.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb + +#ifndef MAME_CPU_UPD777_UPD777DASM_H +#define MAME_CPU_UPD777_UPD777DASM_H + +#pragma once + + +class upd777_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + upd777_disassembler(); + +protected: + // disassembler overrides + virtual u32 opcode_alignment() const override { return 1; } + virtual u32 interface_flags() const override { return NONLINEAR_PC | PAGED; } + virtual u32 page_address_bits() const override { return 7; } + virtual offs_t pc_linear_to_real(offs_t pc) const override { return (pc & ~0x7f) | m_l2r[pc & 0x7f]; } + virtual offs_t pc_real_to_linear(offs_t pc) const override { return (pc & ~0x7f) | m_r2l[pc & 0x7f]; } + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + u8 m_l2r[0x80]; + u8 m_r2l[0x80]; + + std::string get_300optype_name(int optype); + std::string get_200optype_name(int optype); + std::string get_reg_name(int reg); +}; + +#endif // MAME_CPU_UPD777_UPD777DASM_H diff --git a/src/mame/epoch/cassvisn.cpp b/src/mame/epoch/cassvisn.cpp new file mode 100644 index 00000000000..129d5136955 --- /dev/null +++ b/src/mame/epoch/cassvisn.cpp @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb + +/* + +for architecture details see +https://www.oguchi-rd.com/LSI%20products.php +the linked 'design note' contains a large amount of useful information +https://www.oguchi-rd.com/777/777%20Design%20Note.pdf + +*/ + +#include "emu.h" + +#include "bus/generic/carts.h" +#include "bus/generic/slot.h" +#include "cpu/upd777/upd777.h" + +#include "softlist_dev.h" + + +namespace { + +class cassvisn_state : public driver_device +{ +public: + cassvisn_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_cart(*this, "cartslot"), + m_in(*this, "IN%u", 0) + { } + + void cassvisn(machine_config &config); + +protected: + DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load); +private: + u8 input_r(offs_t offset); + + required_device m_maincpu; + required_device m_cart; + required_ioport_array<2> m_in; +}; + +u8 cassvisn_state::input_r(offs_t offset) +{ + return m_in[offset & 1]->read(); +} + +static INPUT_PORTS_START( cassvisn ) + PORT_START("IN0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_START1 ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START2 ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) // Jump on elvpanic + + PORT_START("IN1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON10 ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON9 ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON8 ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON7 ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON6 ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON5 ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) // Jump on monstrmn +INPUT_PORTS_END + +DEVICE_IMAGE_LOAD_MEMBER(cassvisn_state::cart_load) +{ + if (!image.loaded_through_softlist()) + return std::make_pair(image_error::UNSUPPORTED, "Cartridges must be loaded from the software list"); + + auto const prgsize = m_cart->common_get_size("prg"); + if (prgsize != 0xf00) + return std::make_pair(image_error::BADSOFTWARE, "prg region must be 0xf00 bytes in size"); + + m_cart->rom_alloc(prgsize, GENERIC_ROM16_WIDTH, ENDIANNESS_BIG); + m_cart->common_load_rom(m_cart->get_rom_base(), prgsize, "prg"); + uint16_t *prgbase = m_maincpu->get_prgregion(); + memcpy(prgbase, m_cart->get_rom_base(), prgsize); + + auto const patsize = m_cart->common_get_size("pat"); + if (patsize != 0x4d0) + return std::make_pair(image_error::BADSOFTWARE, "pat region patsize must be 0x4d0 bytes in size"); + + m_cart->common_load_rom(m_maincpu->get_patregion(), patsize, "pat"); + + return std::make_pair(std::error_condition(), std::string()); +} + +void cassvisn_state::cassvisn(machine_config &config) +{ + UPD777(config, m_maincpu, 2'000'000); // frequency? UPD774 / UPD778 in some carts? + m_maincpu->in_cb().set(FUNC(cassvisn_state::input_r)); + + GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "cassvisn_cart"); + m_cart->set_width(GENERIC_ROM16_WIDTH); + m_cart->set_device_load(FUNC(cassvisn_state::cart_load)); + m_cart->set_must_be_loaded(true); + + SOFTWARE_LIST(config, "cart_list").set_original("cassvisn_cart"); +} + +ROM_START( cassvisn ) +ROM_END + +} // anonymous namespace + +CONS( 1981, cassvisn, 0, 0, cassvisn, cassvisn, cassvisn_state, empty_init, "Epoch", "Cassette Vision", MACHINE_IS_SKELETON ) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 73ef62b4c7a..d7955d65016 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -17869,6 +17869,9 @@ touryuu // (c) 200? Yuki Enterprise @source:eolith/vegaeo.cpp crazywar // (c) 2002 Eolith +@source:epoch/cassvisn.cpp +cassvisn + @source:epoch/gamepock.cpp gamepock // Epoch Game Pocket Computer diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 4ccce7f1eeb..dadf946e5ac 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -197,6 +197,7 @@ using util::BIT; #include "cpu/unsp/unspdasm.h" #include "cpu/upd177x/upd177xd.h" #include "cpu/upd7725/dasm7725.h" +#include "cpu/upd777/upd777dasm.h" #include "cpu/upd7810/upd7810_dasm.h" #include "cpu/upd78k/upd78k0d.h" #include "cpu/upd78k/upd78k1d.h" @@ -673,6 +674,7 @@ static const dasm_table_entry dasm_table[] = { "unsp12", be, -1, []() -> util::disasm_interface * { return new unsp_12_disassembler; } }, { "unsp20", be, -1, []() -> util::disasm_interface * { return new unsp_20_disassembler; } }, { "upd177x", be, -1, []() -> util::disasm_interface * { return new upd177x_disassembler; } }, + { "upd777", be, -1, []() -> util::disasm_interface * { return new upd777_disassembler; } }, { "upd7725", be, -2, []() -> util::disasm_interface * { return new necdsp_disassembler; } }, { "upd7801", le, 0, []() -> util::disasm_interface * { return new upd7801_disassembler; } }, { "upd78c05", le, 0, []() -> util::disasm_interface * { return new upd78c05_disassembler; } }, -- cgit v1.2.3