summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/axc51/axc51.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/axc51/axc51.cpp')
-rw-r--r--src/devices/cpu/axc51/axc51.cpp1575
1 files changed, 1575 insertions, 0 deletions
diff --git a/src/devices/cpu/axc51/axc51.cpp b/src/devices/cpu/axc51/axc51.cpp
new file mode 100644
index 00000000000..0f1ee436f51
--- /dev/null
+++ b/src/devices/cpu/axc51/axc51.cpp
@@ -0,0 +1,1575 @@
+// license:BSD-3-Clause
+// copyright-holders:Steve Ellenoff, Manuel Abadia, Couriersud, David Haywood
+
+/*****************************************************************************
+
+ AXC51-CORE / AX208 SoC (AppoTech Inc.)
+
+ AXC51CORE:
+ somes sources indicate that the extended opcode encoding may change
+ on some CPU models despite all being 'AXC51CORE' however we lack solid
+ information on this at present.
+
+ AX208:
+ The CPU has 0x2000 bytes of internal ROM mapped at 0x8000-0x9fff providing
+ bootcode, operating kernel and many standard library functions
+
+ *****************************************************************************/
+
+#include "emu.h"
+#include "axc51.h"
+#include "axc51dasm.h"
+
+#define LOG_UNSORTED (1U << 1)
+#define LOG_PORTS (1U << 2)
+#define LOG_UNHANDLED (1U << 3)
+#define LOG_UNHANDLED_XSFR (1U << 4)
+
+
+
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+
+DEFINE_DEVICE_TYPE(AX208, ax208_cpu_device, "ax208", "AppoTech AX208 (AXC51-CORE)")
+DEFINE_DEVICE_TYPE(AX208P, ax208p_cpu_device, "ax208p", "AppoTech AX208 (AXC51-CORE) (prototype?)")
+
+/***************************************************************************
+ ADDRESS MAPS
+***************************************************************************/
+
+void axc51base_cpu_device::program_internal(address_map &map)
+{
+ map(0x4000, 0x6fff).ram().share("mainram");
+}
+
+void axc51base_cpu_device::data_internal(address_map &map)
+{
+ map(0x0000, 0x03ff).ram().share("scratchpad"); // DRAM?
+}
+
+void ax208_cpu_device::ax208_internal_program_mem(address_map &map)
+{
+ map(0x4000, 0x6fff).ram().share("mainram");
+ map(0x8000, 0x9fff).rom().region("rom", 0); // this can only be read from code running within the same region
+}
+
+void axc51base_cpu_device::io_internal(address_map& map)
+{
+ map(0x0000, 0x03ff).ram().share("scratchpad");
+ map(0x3000, 0x3fff).rw(FUNC(axc51base_cpu_device::xsfr_read), FUNC(axc51base_cpu_device::xsfr_write));
+ map(0x4000, 0x6fff).ram().share("mainram");
+
+ map(0x7000, 0x77ff).ram(); // JPEG RAM
+}
+
+
+axc51base_cpu_device::axc51base_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor program_map, address_map_constructor data_map, address_map_constructor io_map, int program_width, int data_width, uint8_t features)
+ : cpu_device(mconfig, type, tag, owner, clock)
+ , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0, program_map)
+ , m_data_config("data", ENDIANNESS_LITTLE, 8, 11, 0, data_map)
+ , m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0, io_map)
+ , m_pc(0)
+ , m_features(features)
+ , m_rom_size(program_width > 0 ? 1 << program_width : 0)
+ , m_num_interrupts(5)
+ , m_scratchpad(*this, "scratchpad")
+ , m_mainram(*this, "mainram")
+ , m_port_in_cb(*this, 0xff)
+ , m_port_out_cb(*this)
+ , m_dac_out_cb(*this)
+ , m_spi_in_cb(*this, 0xff)
+ , m_spi_out_cb(*this)
+ , m_spi_out_dir_cb(*this)
+ , m_rtemp(0)
+{
+ for (int i = 0; i < 0x80; i++)
+ {
+ m_sfr_regs[i] = 0x00;
+ m_xsfr_regs[i] = 0x00;
+ }
+
+ m_uid[0] = 0x00; // not used?
+ m_uid[1] = 0x00; // used in RTC / USB code?
+ m_uid[2] = 0x91; // used in crypt code?
+ m_uid[3] = 0xb5;
+}
+
+
+axc51base_cpu_device::axc51base_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int program_width, int data_width, uint8_t features)
+ : axc51base_cpu_device(mconfig, type, tag, owner, clock, address_map_constructor(FUNC(axc51base_cpu_device::program_internal), this), address_map_constructor(FUNC(axc51base_cpu_device::data_internal), this), address_map_constructor(FUNC(axc51base_cpu_device::io_internal), this), program_width, data_width, features)
+{
+}
+
+
+device_memory_interface::space_config_vector axc51base_cpu_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config),
+ std::make_pair(AS_DATA, &m_data_config),
+ std::make_pair(AS_IO, &m_io_config)
+ };
+}
+
+/* Read/Write a byte from/to the Internal RAM indirectly */
+/* (called from indirect addressing) */
+/* these go through DBASE register on axc51 (at least stack accesses) */
+uint8_t axc51base_cpu_device::iram_indirect_read(offs_t a) { return m_data.read_byte((m_sfr_regs[SFR_DBASE] * 4) + a); }
+void axc51base_cpu_device::iram_indirect_write(offs_t a, uint8_t d) { m_data.write_byte((m_sfr_regs[SFR_DBASE] * 4) + a, d); }
+
+/***************************************************************************
+ SHORTCUTS
+***************************************************************************/
+
+/* SFR Registers - These are accessed directly for speed on read */
+/* Read accessors */
+
+#define SET_SFR_A(a,v) do { m_sfr_regs[a] = (v); } while (0)
+
+#define ACC m_sfr_regs[SFR_ACC]
+#define PSW m_sfr_regs[SFR_PSW]
+
+#define P0 ((const uint8_t) m_sfr_regs[SFR_P0])
+#define P1 ((const uint8_t) m_sfr_regs[SFR_P1])
+#define P2 ((const uint8_t) m_sfr_regs[SFR_P2])
+#define P3 ((const uint8_t) m_sfr_regs[SFR_P3])
+#define P4 ((const uint8_t) m_sfr_regs[SFR_P4])
+
+#define SP m_sfr_regs[SFR_SP]
+#define DPL0 m_sfr_regs[SFR_DPL0]
+#define DPH0 m_sfr_regs[SFR_DPH0]
+#define PCON m_sfr_regs[SFR_PCON]
+#define IE m_sfr_regs[SFR_IE]
+#define IE1 m_sfr_regs[SFR_IE1]
+#define IP m_sfr_regs[SFR_IP]
+#define B m_sfr_regs[SFR_B]
+#define ER8 m_sfr_regs[SFR_ER8]
+
+#define DPL1 m_sfr_regs[SFR_DPL1]
+#define DPH1 m_sfr_regs[SFR_DPH1]
+
+
+#define ER00 m_sfr_regs[SFR_ER00]
+#define ER01 m_sfr_regs[SFR_ER01]
+
+#define ER10 m_sfr_regs[SFR_ER10]
+#define ER11 m_sfr_regs[SFR_ER11]
+
+#define ER20 m_sfr_regs[SFR_ER20]
+#define ER21 m_sfr_regs[SFR_ER21]
+
+#define ER30 m_sfr_regs[SFR_ER30]
+#define ER31 m_sfr_regs[SFR_ER31]
+
+#define GP0 m_sfr_regs[SFR_GP0]
+#define GP1 m_sfr_regs[SFR_GP1]
+#define GP2 m_sfr_regs[SFR_GP2]
+#define GP3 m_sfr_regs[SFR_GP3]
+#define GP4 m_sfr_regs[SFR_GP4]
+#define GP5 m_sfr_regs[SFR_GP5]
+#define GP6 m_sfr_regs[SFR_GP6]
+#define GP7 m_sfr_regs[SFR_GP7]
+
+#define R_REG(r) m_scratchpad[(r) | (PSW & 0x18)]
+
+#define DPTR0 ((DPH0<<8) | DPL0)
+#define DPTR1 ((DPH1<<8) | DPL1)
+
+#define ER0 ((ER01<<8) | ER00)
+#define ER1 ((ER11<<8) | ER10)
+#define ER2 ((ER21<<8) | ER20)
+#define ER3 ((ER31<<8) | ER30)
+
+#define SET_PSW(v) do { m_sfr_regs[SFR_PSW] = (v); SET_PARITY(); } while (0)
+#define SET_ACC(v) do { m_sfr_regs[SFR_ACC] = (v); SET_PARITY(); } while (0)
+
+/* These trigger actions on modification and have to be written through SFR_W */
+#define SET_P0(v) iram_write(SFR_P0, v)
+#define SET_P1(v) iram_write(SFR_P1, v)
+#define SET_P2(v) iram_write(SFR_P2, v)
+#define SET_P3(v) iram_write(SFR_P3, v)
+
+/* No actions triggered on write */
+#define SET_REG(r, v) do { m_scratchpad[(r) | (PSW & 0x18)] = (v); } while (0)
+
+#define SET_DPTR0(n) do { DPH0 = ((n) >> 8) & 0xff; DPL0 = (n) & 0xff; } while (0)
+
+#define SET_DPTR1(n) do { DPH1 = ((n) >> 8) & 0xff; DPL1 = (n) & 0xff; } while (0)
+
+#define SET_ER0(n) do { ER01 = ((n) >> 8) & 0xff; ER00 = (n) & 0xff; } while (0)
+#define SET_ER1(n) do { ER11 = ((n) >> 8) & 0xff; ER10 = (n) & 0xff; } while (0)
+#define SET_ER2(n) do { ER21 = ((n) >> 8) & 0xff; ER20 = (n) & 0xff; } while (0)
+#define SET_ER3(n) do { ER31 = ((n) >> 8) & 0xff; ER30 = (n) & 0xff; } while (0)
+
+#define SET_ER8(n) do { ER8 = (n);} while (0)
+
+#define SET_GP0(n) do { GP0 = (n);} while (0)
+#define SET_GP1(n) do { GP1 = (n);} while (0)
+#define SET_GP2(n) do { GP2 = (n);} while (0)
+#define SET_GP3(n) do { GP3 = (n);} while (0)
+#define SET_GP4(n) do { GP4 = (n);} while (0)
+#define SET_GP5(n) do { GP5 = (n);} while (0)
+#define SET_GP6(n) do { GP6 = (n);} while (0)
+#define SET_GP7(n) do { GP7 = (n);} while (0)
+
+/* Macros for Setting Flags */
+#define SET_X(R, v) do { R = (v);} while (0)
+
+#define SET_CY(n) SET_PSW((PSW & 0x7f) | (n<<7)) //Carry Flag
+#define SET_AC(n) SET_PSW((PSW & 0xbf) | (n<<6)) //Aux.Carry Flag
+#define SET_EC(n) SET_PSW((PSW & 0xdf) | (n<<5)) //Extended Instruction Carry Flag EC (not FO)
+#define SET_RS(n) SET_PSW((PSW & 0xe7) | (n<<3)) //R Bank Select
+#define SET_OV(n) SET_PSW((PSW & 0xfb) | (n<<2)) //Overflow Flag
+#define SET_EZ(n) SET_PSW((PSW & 0xfd) | (n<<1)) //Extended Instruction Zero Flag EZ
+#define SET_P(n) SET_PSW((PSW & 0xfe) | (n<<0)) //Parity Flag
+
+#define SET_BIT(R, n, v) do { R = (R & ~(1<<(n))) | ((v) << (n));} while (0)
+#define GET_BIT(R, n) (((R)>>(n)) & 0x01)
+
+/* Macros for accessing flags */
+
+#define GET_CY GET_BIT(PSW, 7)
+#define GET_AC GET_BIT(PSW, 6)
+#define GET_EC GET_BIT(PSW, 5) //Extended Instruction Carry Flag EC (not FO)
+#define GET_RS GET_BIT(PSW, 3)
+#define GET_OV GET_BIT(PSW, 2)
+#define GET_EZ GET_BIT(PSW, 1) //Extended Instruction Zero Flag EZ
+#define GET_P GET_BIT(PSW, 0)
+
+#define GET_DMAIRQEN GET_BIT(IE1, 6)
+
+#define GET_EA GET_BIT(IE, 7)
+#define GET_SDCIRQEN GET_BIT(IE, 6)
+#define GET_SPIIRQEN GET_BIT(IE, 5)
+#define GET_USBIRQEN GET_BIT(IE, 4)
+#define GET_T3IRQEN GET_BIT(IE, 3)
+#define GET_T2IRQEN GET_BIT(IE, 2)
+#define GET_T1IRQEN GET_BIT(IE, 1)
+#define GET_T0IRQEN GET_BIT(IE, 0)
+
+#define SET_PARITY() do {m_recalc_parity |= 1;} while (0)
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+void axc51base_cpu_device::clear_current_irq()
+{
+ LOGMASKED(LOG_UNHANDLED,"clear irq\n");
+}
+
+uint8_t axc51base_cpu_device::r_acc() { return m_sfr_regs[SFR_ACC]; }
+
+uint8_t axc51base_cpu_device::r_psw() { return m_sfr_regs[SFR_PSW]; }
+
+
+offs_t axc51base_cpu_device::external_ram_iaddr(offs_t offset, offs_t mem_mask)
+{
+ if (mem_mask == 0x00ff)
+ return (offset & mem_mask) | 0x000;
+
+ return offset;
+}
+
+/* Internal ram read/write */
+
+uint8_t axc51base_cpu_device::iram_read(size_t offset)
+{
+ return (((offset) < 0x80) ? m_data.read_byte(offset) : sfr_read(offset & 0x7f));
+}
+
+void axc51base_cpu_device::iram_write(size_t offset, uint8_t data)
+{
+ if ((offset) < 0x80)
+ m_data.write_byte(offset, data);
+ else
+ sfr_write(offset & 0x7f, data);
+}
+
+/*Push the current PC to the stack*/
+void axc51base_cpu_device::push_pc()
+{
+ uint8_t tmpSP = SP+1; //Grab and Increment Stack Pointer
+ iram_indirect_write(tmpSP, (m_pc & 0xff)); //Store low byte of PC to Internal Ram (Use iram_indirect_write to store stack above 128 bytes)
+ tmpSP++; // ""
+ SP = tmpSP; // ""
+ iram_indirect_write(tmpSP, ( (m_pc & 0xff00) >> 8)); //Store hi byte of PC to next address in Internal Ram (Use iram_indirect_write to store stack above 128 bytes)
+}
+
+/*Pop the current PC off the stack and into the pc*/
+void axc51base_cpu_device::pop_pc()
+{
+ uint8_t tmpSP = SP; //Grab Stack Pointer
+ m_pc = (iram_indirect_read(tmpSP--) & 0xff) << 8; //Store hi byte to PC (must use iram_indirect_read to access stack pointing above 128 bytes)
+ m_pc = m_pc | iram_indirect_read(tmpSP--); //Store lo byte to PC (must use iram_indirect_read to access stack pointing above 128 bytes)
+ SP = tmpSP; //Decrement Stack Pointer
+}
+
+//Set the PSW Parity Flag
+void axc51base_cpu_device::set_parity()
+{
+ //This flag will be set when the accumulator contains an odd # of bits set..
+ uint8_t p = 0;
+ int i;
+ uint8_t a = ACC;
+
+ for (i=0; i<8; i++) { //Test for each of the 8 bits in the ACC!
+ p ^= (a & 1);
+ a = (a >> 1);
+ }
+
+ SET_P(p & 1);
+}
+
+uint8_t axc51base_cpu_device::bit_address_r(uint8_t offset)
+{
+ uint8_t word;
+ uint8_t mask;
+ int bit_pos;
+ int distance; /* distance between bit addressable words */
+ /* 1 for normal bits, 8 for sfr bit addresses */
+
+ m_last_bit = offset;
+
+ //User defined bit addresses 0x20-0x2f (values are 0x0-0x7f)
+ if (offset < 0x80) {
+ distance = 1;
+ word = ( (offset & 0x78) >> 3) * distance + 0x20;
+ bit_pos = offset & 0x7;
+ mask = (0x1 << bit_pos);
+ return((iram_read(word) & mask) >> bit_pos);
+ }
+ //SFR bit addressable registers
+ else {
+ distance = 8;
+ word = ( (offset & 0x78) >> 3) * distance + 0x80;
+ bit_pos = offset & 0x7;
+ mask = (0x1 << bit_pos);
+ return ((iram_read(word) & mask) >> bit_pos);
+ }
+}
+
+
+void axc51base_cpu_device::bit_address_w(uint8_t offset, uint8_t bit)
+{
+ int word;
+ uint8_t mask;
+ int bit_pos;
+ uint8_t result;
+ int distance;
+
+ /* User defined bit addresses 0x20-0x2f (values are 0x0-0x7f) */
+ if (offset < 0x80) {
+ distance = 1;
+ word = ((offset & 0x78) >> 3) * distance + 0x20;
+ bit_pos = offset & 0x7;
+ bit = (bit & 0x1) << bit_pos;
+ mask = ~(1 << bit_pos) & 0xff;
+ result = iram_read(word) & mask;
+ result = result | bit;
+ iram_write(word, result);
+ }
+ /* SFR bit addressable registers */
+ else {
+ distance = 8;
+ word = ((offset & 0x78) >> 3) * distance + 0x80;
+ bit_pos = offset & 0x7;
+ bit = (bit & 0x1) << bit_pos;
+ mask = ~(1 << bit_pos) & 0xff;
+ result = iram_read(word) & mask;
+ result = result | bit;
+ iram_write(word, result);
+ }
+}
+
+void axc51base_cpu_device::do_add_flags(uint8_t a, uint8_t data, uint8_t c)
+{
+ uint16_t result = a+data+c;
+ int16_t result1 = (int8_t)a+(int8_t)data+c;
+
+ SET_CY((result & 0x100) >> 8);
+ result = (a&0x0f)+(data&0x0f)+c;
+ SET_AC((result & 0x10) >> 4);
+ SET_OV(result1 < -128 || result1 > 127);
+}
+
+void axc51base_cpu_device::do_sub_flags(uint8_t a, uint8_t data, uint8_t c)
+{
+ uint16_t result = a-(data+c);
+ int16_t result1 = (int8_t)a-(int8_t)(data+c);
+
+ SET_CY((result & 0x100) >> 8);
+ result = (a&0x0f)-((data&0x0f)+c);
+ SET_AC((result & 0x10) >> 4);
+ SET_OV((result1 < -128 || result1 > 127));
+}
+
+uint32_t axc51base_cpu_device::get_dptr0_with_autoinc(uint8_t auto_inc)
+{
+ uint32_t addr = external_ram_iaddr(DPTR0, 0xffff);
+ if (auto_inc) // auto-increment enabled
+ {
+ if (m_sfr_regs[SFR_DPCON] & 0x20) // DPID0 DPTR0 increase direction control
+ {
+ uint16_t dptr = (DPTR0)-1;
+ SET_DPTR0(dptr);
+ }
+ else
+ {
+ uint16_t dptr = (DPTR0)+1;
+ SET_DPTR0(dptr);
+ }
+ }
+ return addr;
+}
+
+uint32_t axc51base_cpu_device::get_dptr1_with_autoinc(uint8_t auto_inc)
+{
+ uint32_t addr = external_ram_iaddr(DPTR1, 0xffff);
+ if (auto_inc) // auto-increment enabled
+ {
+ if (m_sfr_regs[SFR_DPCON] & 0x10) // DPID1 DPTR1 increase direction control
+ {
+ uint16_t dptr = (DPTR1)-1;
+ SET_DPTR1(dptr);
+ }
+ else
+ {
+ uint16_t dptr = (DPTR1)+1;
+ SET_DPTR1(dptr);
+ }
+ }
+ return addr;
+}
+
+uint32_t axc51base_cpu_device::process_dptr_access()
+{
+ uint8_t auto_inc = m_sfr_regs[SFR_DPCON] & 0x08;
+ uint32_t addr = (m_sfr_regs[SFR_DPCON] & 0x01) ? get_dptr1_with_autoinc(auto_inc) : get_dptr0_with_autoinc(auto_inc);
+
+ if (m_sfr_regs[SFR_DPCON] & 0x04)
+ {
+ // auto toggle DPR
+ m_sfr_regs[SFR_DPCON] ^= 0x01;
+ }
+
+ return addr;
+}
+
+
+/***************************************************************************
+ OPCODES
+***************************************************************************/
+
+#define OPHANDLER( _name ) void axc51base_cpu_device::_name (uint8_t r)
+
+#include "axc51ops.hxx"
+#include "axc51extops.hxx"
+
+
+
+void axc51base_cpu_device::execute_op(uint8_t op)
+{
+ if (m_recalc_parity)
+ {
+ set_parity();
+ m_recalc_parity = 0;
+ }
+
+ m_last_op = op;
+
+ switch( op )
+ {
+ case 0x00: nop(op); break; //NOP
+ case 0x01: ajmp(op); break; //AJMP code addr
+ case 0x02: ljmp(op); break; //LJMP code addr
+ case 0x03: rr_a(op); break; //RR A
+ case 0x04: inc_a(op); break; //INC A
+ case 0x05: inc_mem(op); break; //INC data addr
+
+ case 0x06:
+ case 0x07: inc_ir(op&1); break; //INC @R0/@R1
+
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f: inc_r(op&7); break; //INC R0 to R7
+
+ case 0x10: jbc(op); break; //JBC bit addr, code addr
+ case 0x11: acall(op); break; //ACALL code addr
+ case 0x12: lcall(op); break; //LCALL code addr
+ case 0x13: rrc_a(op); break; //RRC A
+ case 0x14: dec_a(op); break; //DEC A
+ case 0x15: dec_mem(op); break; //DEC data addr
+
+ case 0x16:
+ case 0x17: dec_ir(op&1); break; //DEC @R0/@R1
+
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f: dec_r(op&7); break; //DEC R0 to R7
+
+ case 0x20: jb(op); break; //JB bit addr, code addr
+ case 0x21: ajmp(op); break; //AJMP code addr
+ case 0x22: ret(op); break; //RET
+ case 0x23: rl_a(op); break; //RL A
+ case 0x24: add_a_byte(op); break; //ADD A, #data
+ case 0x25: add_a_mem(op); break; //ADD A, data addr
+
+ case 0x26:
+ case 0x27: add_a_ir(op&1); break; //ADD A, @R0/@R1
+
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f: add_a_r(op&7); break; //ADD A, R0 to R7
+
+ case 0x30: jnb(op); break; //JNB bit addr, code addr
+ case 0x31: acall(op); break; //ACALL code addr
+ case 0x32: reti(op); break; //RETI
+ case 0x33: rlc_a(op); break; //RLC A
+ case 0x34: addc_a_byte(op); break; //ADDC A, #data
+ case 0x35: addc_a_mem(op); break; //ADDC A, data addr
+
+ case 0x36:
+ case 0x37: addc_a_ir(op&1); break; //ADDC A, @R0/@R1
+
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f: addc_a_r(op&7); break; //ADDC A, R0 to R7
+
+ case 0x40: jc(op); break; //JC code addr
+ case 0x41: ajmp(op); break; //AJMP code addr
+ case 0x42: orl_mem_a(op); break; //ORL data addr, A
+ case 0x43: orl_mem_byte(op); break; //ORL data addr, #data
+ case 0x44: orl_a_byte(op); break;
+ case 0x45: orl_a_mem(op); break; //ORL A, data addr
+
+ case 0x46:
+ case 0x47: orl_a_ir(op&1); break; //ORL A, @RO/@R1
+
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f: orl_a_r(op&7); break; //ORL A, RO to R7
+
+ case 0x50: jnc(op); break; //JNC code addr
+ case 0x51: acall(op); break; //ACALL code addr
+ case 0x52: anl_mem_a(op); break; //ANL data addr, A
+ case 0x53: anl_mem_byte(op); break; //ANL data addr, #data
+ case 0x54: anl_a_byte(op); break; //ANL A, #data
+ case 0x55: anl_a_mem(op); break; //ANL A, data addr
+
+ case 0x56:
+ case 0x57: anl_a_ir(op&1); break; //ANL A, @RO/@R1
+
+ case 0x58:
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5d:
+ case 0x5e:
+ case 0x5f: anl_a_r(op&7); break; //ANL A, RO to R7
+
+ case 0x60: jz(op); break; //JZ code addr
+ case 0x61: ajmp(op); break; //AJMP code addr
+ case 0x62: xrl_mem_a(op); break; //XRL data addr, A
+ case 0x63: xrl_mem_byte(op); break; //XRL data addr, #data
+ case 0x64: xrl_a_byte(op); break; //XRL A, #data
+ case 0x65: xrl_a_mem(op); break; //XRL A, data addr
+
+ case 0x66:
+ case 0x67: xrl_a_ir(op&1); break; //XRL A, @R0/@R1
+
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f: xrl_a_r(op&7); break; //XRL A, R0 to R7
+
+ case 0x70: jnz(op); break; //JNZ code addr
+ case 0x71: acall(op); break; //ACALL code addr
+ case 0x72: orl_c_bitaddr(op); break; //ORL C, bit addr
+ case 0x73: jmp_iadptr(op); break; //JMP @A+DPTR
+ case 0x74: mov_a_byte(op); break; //MOV A, #data
+ case 0x75: mov_mem_byte(op); break; //MOV data addr, #data
+
+ case 0x76:
+ case 0x77: mov_ir_byte(op&1); break; //MOV @R0/@R1, #data
+
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f: mov_r_byte(op&7); break; //MOV R0 to R7, #data
+
+ case 0x80: sjmp(op); break; //SJMP code addr
+ case 0x81: ajmp(op); break; //AJMP code addr
+ case 0x82: anl_c_bitaddr(op); break; //ANL C, bit addr
+ case 0x83: movc_a_iapc(op); break; //MOVC A, @A + PC
+ case 0x84: div_ab(op); break; //DIV AB
+ case 0x85: mov_mem_mem(op); break; //MOV data addr, data addr
+
+ case 0x86:
+ case 0x87: mov_mem_ir(op&1); break; //MOV data addr, @R0/@R1
+
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f: mov_mem_r(op&7); break; //MOV data addr,R0 to R7
+
+ case 0x90: mov_dptr_byte(op); break; //MOV DPTR, #data
+ case 0x91: acall(op); break; //ACALL code addr
+ case 0x92: mov_bitaddr_c(op); break; //MOV bit addr, C
+ case 0x93: movc_a_iadptr(op); break; //MOVC A, @A + DPTR
+ case 0x94: subb_a_byte(op); break; //SUBB A, #data
+ case 0x95: subb_a_mem(op); break; //SUBB A, data addr
+
+ case 0x96:
+ case 0x97: subb_a_ir(op&1); break; //SUBB A, @R0/@R1
+
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f: subb_a_r(op&7); break; //SUBB A, R0 to R7
+
+ case 0xa0: orl_c_nbitaddr(op); break; //ORL C, /bit addr
+ case 0xa1: ajmp(op); break; //AJMP code addr
+ case 0xa2: mov_c_bitaddr(op); break; //MOV C, bit addr
+ case 0xa3: inc_dptr(op); break; //INC DPTR
+ case 0xa4: mul_ab(op); break; //MUL AB
+ case 0xa5: axc51_extended_a5(op); break;
+
+ case 0xa6:
+ case 0xa7: mov_ir_mem(op&1); break; //MOV @R0/@R1, data addr
+
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf: mov_r_mem(op&7); break; //MOV R0 to R7, data addr
+
+ case 0xb0: anl_c_nbitaddr(op); break; //ANL C,/bit addr
+ case 0xb1: acall(op); break; //ACALL code addr
+ case 0xb2: cpl_bitaddr(op); break; //CPL bit addr
+ case 0xb3: cpl_c(op); break; //CPL C
+ case 0xb4: cjne_a_byte(op); break; //CJNE A, #data, code addr
+ case 0xb5: cjne_a_mem(op); break; //CJNE A, data addr, code addr
+
+ case 0xb6:
+ case 0xb7: cjne_ir_byte(op&1); break; //CJNE @R0/@R1, #data, code addr
+
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf: cjne_r_byte(op&7); break; //CJNE R0 to R7, #data, code addr
+
+ case 0xc0: push(op); break; //PUSH data addr
+ case 0xc1: ajmp(op); break; //AJMP code addr
+ case 0xc2: clr_bitaddr(op); break; //CLR bit addr
+ case 0xc3: clr_c(op); break; //CLR C
+ case 0xc4: swap_a(op); break; //SWAP A
+ case 0xc5: xch_a_mem(op); break; //XCH A, data addr
+
+ case 0xc6:
+ case 0xc7: xch_a_ir(op&1); break; //XCH A, @RO/@R1
+
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf: xch_a_r(op&7); break; //XCH A, RO to R7
+
+ case 0xd0: pop(op); break; //POP data addr
+ case 0xd1: acall(op); break; //ACALL code addr
+ case 0xd2: setb_bitaddr(op); break; //SETB bit addr
+ case 0xd3: setb_c(op); break; //SETB C
+ case 0xd4: da_a(op); break; //DA A
+ case 0xd5: djnz_mem(op); break; //DJNZ data addr, code addr
+
+ case 0xd6:
+ case 0xd7: xchd_a_ir(op&1); break; //XCHD A, @R0/@R1
+
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf: djnz_r(op&7); break; //DJNZ R0 to R7,code addr
+
+ case 0xe0: movx_a_idptr(op); break; //MOVX A,@DPTR
+ case 0xe1: ajmp(op); break; //AJMP code addr
+
+ case 0xe2:
+ case 0xe3: movx_a_ir(op&1); break; //MOVX A, @R0/@R1
+
+ case 0xe4: clr_a(op); break; //CLR A
+ case 0xe5: mov_a_mem(op); break; //MOV A, data addr
+ case 0xe6:
+ case 0xe7: mov_a_ir(op&1); break; //MOV A,@RO/@R1
+
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef: mov_a_r(op&7); break; //MOV A,R0 to R7
+
+ case 0xf0: movx_idptr_a(op); break; //MOVX @DPTR,A
+ case 0xf1: acall(op); break; //ACALL code addr
+
+ case 0xf2:
+ case 0xf3: movx_ir_a(op&1); break; //MOVX @R0/@R1,A
+
+ case 0xf4: cpl_a(op); break; //CPL A
+ case 0xf5: mov_mem_a(op); break; //MOV data addr, A
+
+ case 0xf6:
+ case 0xf7: mov_ir_a(op&1); break; //MOV @R0/@R1, A
+
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff: mov_r_a(op&7); break; //MOV R0 to R7, A
+ default:
+ illegal(op);
+ }
+}
+
+/***************************************************************************
+ OPCODE CYCLES
+***************************************************************************/
+
+/* # of oscilations each opcode requires*/
+const uint8_t axc51base_cpu_device::axc51_cycles[256] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+};
+
+uint16_t axc51base_cpu_device::get_irq_base()
+{
+ int base = 0;
+
+ switch (m_sfr_regs[SFR_DPCON] & 0xc0)
+ {
+ case 0x00:
+ case 0xc0:
+ base = 0; // invalid
+ break;
+
+ case 0x80:
+ base = 0x8000;
+ break;
+
+ case 0x40:
+ base = 0x4000;
+ break;
+ }
+
+ return base;
+}
+
+TIMER_CALLBACK_MEMBER(axc51base_cpu_device::timer0_cb)
+{
+ // TODO: this logic is not correct
+
+ m_timer0irq = true;
+}
+
+TIMER_CALLBACK_MEMBER(axc51base_cpu_device::dactimer_cb)
+{
+ // TODO: this logic is not correct
+
+ m_dactimerirq = true;
+}
+
+
+void axc51base_cpu_device::check_irqs()
+{
+ // TODO: this logic is not correct
+
+ if (!GET_EA)
+ return;
+
+ uint16_t base = get_irq_base();
+
+ if (!base)
+ return;
+
+ if (m_timer0irq && GET_T0IRQEN)
+ {
+ push_pc();
+ m_pc = base + V_TIMER0;
+ m_timer0irq = false;
+ }
+ else if (m_dactimerirq && GET_DMAIRQEN)
+ {
+ push_pc();
+ m_pc = base + V_DAC;
+ m_dactimerirq = false;
+ }
+}
+
+
+
+
+void axc51base_cpu_device::execute_set_input(int irqline, int state)
+{
+ uint32_t new_state = (m_last_line_state & ~(1 << irqline)) | ((state != CLEAR_LINE) << irqline);
+ /* detect 0->1 transitions */
+ //uint32_t tr_state = (~m_last_line_state) & new_state;
+
+ // TODO
+
+ m_last_line_state = new_state;
+}
+
+/* Execute cycles - returns number of cycles actually run */
+void axc51base_cpu_device::execute_run()
+{
+ uint8_t op;
+
+ /* external interrupts may have been set since we last checked */
+ m_inst_cycles = 0;
+ check_irqs();
+
+ m_icount -= m_inst_cycles;
+
+ do
+ {
+ /* Read next opcode */
+ m_ppc = m_pc;
+ debugger_instruction_hook(m_pc);
+ op = m_program.read_byte(m_pc++);
+
+ /* process opcode and count cycles */
+ m_inst_cycles = axc51_cycles[op];
+ execute_op(op);
+
+ /* burn the cycles */
+ m_icount -= m_inst_cycles;
+
+ check_irqs();
+
+ } while( m_icount > 0 );
+}
+
+uint8_t axc51base_cpu_device::xsfr_read(offs_t offset)
+{
+ offset &= 0x7f;
+
+ LOGMASKED(LOG_UNHANDLED_XSFR,"%s: reading unhandled XSFR reg %04x\n", machine().describe_context(), offset + 0x3000);
+
+ return m_xsfr_regs[offset];
+}
+
+void axc51base_cpu_device::xsfr_write(offs_t offset, uint8_t data)
+{
+ offset &= 0x7f;
+
+ switch (offset)
+ {
+ case XSFR_PUP0: // 0x3010
+ case XSFR_PUP1: // 0x3011
+ case XSFR_PUP2: // 0x3012
+ case XSFR_PUP3: // 0x3013
+ case XSFR_PUP4: // 0x3014
+
+ case XSFR_PDN0: // 0x3015
+ case XSFR_PDN1: // 0x3016
+ case XSFR_PDN2: // 0x3017
+ case XSFR_PDN3: // 0x3018
+ case XSFR_PDN4: // 0x3019
+ break;
+
+ case XSFR_PHD0: // 0x301a
+ case XSFR_PHD1: // 0x301b
+ case XSFR_PHD2: // 0x301c
+ case XSFR_PHD3: // 0x301d
+ case XSFR_PHD4: // 0x301e
+ break;
+
+ default:
+ LOGMASKED(LOG_UNHANDLED_XSFR,"%s: writing to unhandled XSFR reg %04x data %02x\n", machine().describe_context(), offset + 0x3000, data);
+ break;
+
+ }
+ m_xsfr_regs[offset] = data;
+}
+
+
+void axc51base_cpu_device::sfr_write(size_t offset, uint8_t data)
+{
+ /* update register */
+ switch (offset)
+ {
+ case SFR_P0: write_port(0, data); break;
+ case SFR_P1: write_port(1, data); break;
+ case SFR_P2: write_port(2, data); break;
+ case SFR_P3: write_port(3, data); break;
+ case SFR_PSW: SET_PARITY(); break;
+ case SFR_ACC: SET_PARITY(); break;
+ case SFR_IP: break;
+
+ case SFR_B:
+ case SFR_SP:
+ case SFR_DPL0:
+ case SFR_DPH0:
+ case SFR_PCON:
+ break;
+
+ case SFR_DPL1: // 0x84
+ case SFR_DPH1: // 0x85
+ break;
+
+ case SFR_IE:
+ break;
+
+ case SFR_IE1:
+ break;
+
+ case SFR_GP0: // 0xa1
+ case SFR_GP1: // 0xa2
+ case SFR_GP2: // 0xa3
+ case SFR_GP3: // 0xa4
+ case SFR_GP4: // 0xb1
+ case SFR_GP5: // 0xb2
+ case SFR_GP6: // 0xb3
+ case SFR_GP7: // 0xb5
+ break;
+
+ case SFR_DACLCH: // 0xa6
+ m_dac_out_cb[0](data);
+ break;
+
+ case SFR_DACRCH: // 0xa7
+ m_dac_out_cb[1](data);
+ break;
+
+ case SFR_P0DIR: // 0xba
+ case SFR_P1DIR: // 0xbb
+ case SFR_P2DIR: // 0xbc
+ case SFR_P3DIR: // 0xbd
+ case SFR_P4DIR: // 0xbe
+ break;
+
+ case SFR_ER00: // 0xe6
+ case SFR_ER01: // 0xe7
+ case SFR_ER10: // 0xe8
+ case SFR_ER11: // 0xe9
+ case SFR_ER20: // 0xea
+ case SFR_ER21: // 0xeb
+ case SFR_ER30: // 0xec
+ case SFR_ER31: // 0xed
+ case SFR_ER8: // 0xee
+ break;
+
+ case SFR_P4: write_port(4, data); break; // 0xb4
+
+ case SFR_TMR0CON: // 0xf8
+ case SFR_TMR0CNT: // 0xf9
+ case SFR_TMR0PR: // 0xfa
+ case SFR_TMR0PSR: // 0xfb
+ break;
+
+ case SFR_IE2CRPT: // 0x95 controls automatic encryption
+ ie2crypt_w(data);
+ return;
+
+ case SFR_DPCON: dpcon_w(data); return; // 0x86
+
+ case SFR_DBASE: // 0x9b
+ m_sfr_regs[SFR_DBASE] = data;
+ return;
+
+
+ case SFR_SPIDMAADR: spidmaadr_w(data); return; // 0xd6
+ case SFR_SPIDMACNT: spidmacnt_w(data); return; // 0xd7
+ case SFR_SPICON: spicon_w(data); return; // 0xd8
+ case SFR_SPIBUF: spibuf_w(data); return; // 0xd9
+ case SFR_SPIBAUD: spibaud_w(data); return; // 0xda
+
+
+ default:
+ LOGMASKED(LOG_UNHANDLED,"%s: attemping to write to an invalid/non-implemented SFR address: %02x data=%02x\n", machine().describe_context(), (uint32_t)offset, data);
+ /* no write in this case according to manual */
+ return;
+ }
+ m_sfr_regs[offset] = data;
+}
+
+uint8_t axc51base_cpu_device::read_port(int i)
+{
+ uint8_t latched_out_data = 0x00;
+ uint8_t port_direction = 0x00;
+ uint8_t pup = 0x00;
+ uint8_t pdn = 0x00;
+
+ // direction 0xff = all bits set to input?
+
+ // pdn and pup registers are mentioned as 'pull down' and 'pull up' but other than
+ // there being 5 of them it isn't clear if they're used for these ports or not
+
+ switch (i)
+ {
+ case 0: latched_out_data = P0; port_direction = m_sfr_regs[SFR_P0DIR]; pup = m_xsfr_regs[XSFR_PUP0]; pdn = m_xsfr_regs[XSFR_PDN0]; break;
+ case 1: latched_out_data = P1; port_direction = m_sfr_regs[SFR_P1DIR]; pup = m_xsfr_regs[XSFR_PUP1]; pdn = m_xsfr_regs[XSFR_PDN1]; break;
+ case 2: latched_out_data = P2; port_direction = m_sfr_regs[SFR_P2DIR]; pup = m_xsfr_regs[XSFR_PUP2]; pdn = m_xsfr_regs[XSFR_PDN2]; break;
+ case 3: latched_out_data = P3; port_direction = m_sfr_regs[SFR_P3DIR]; pup = m_xsfr_regs[XSFR_PUP3]; pdn = m_xsfr_regs[XSFR_PDN3]; break;
+ case 4: latched_out_data = P4; port_direction = m_sfr_regs[SFR_P4DIR]; pup = m_xsfr_regs[XSFR_PUP4]; pdn = m_xsfr_regs[XSFR_PDN4]; break;
+ }
+
+ uint8_t incoming = m_port_in_cb[i]();
+
+ LOGMASKED(LOG_PORTS,"%s: reading port %d with direction %02x pup %02x pdn %02x latched output %02x incoming data %02x\n", machine().describe_context(), i, port_direction, pup, pdn, latched_out_data, incoming);
+ return incoming;
+}
+
+void axc51base_cpu_device::write_port(int i, uint8_t data)
+{
+ uint8_t port_direction = 0x00;
+ uint8_t pup = 0x00;
+ uint8_t pdn = 0x00;
+
+ switch (i)
+ {
+ case 0: port_direction = m_sfr_regs[SFR_P0DIR]; pup = m_xsfr_regs[XSFR_PUP0]; pdn = m_xsfr_regs[XSFR_PDN0]; break;
+ case 1: port_direction = m_sfr_regs[SFR_P1DIR]; pup = m_xsfr_regs[XSFR_PUP1]; pdn = m_xsfr_regs[XSFR_PDN1]; break;
+ case 2: port_direction = m_sfr_regs[SFR_P2DIR]; pup = m_xsfr_regs[XSFR_PUP2]; pdn = m_xsfr_regs[XSFR_PDN2]; break;
+ case 3: port_direction = m_sfr_regs[SFR_P3DIR]; pup = m_xsfr_regs[XSFR_PUP3]; pdn = m_xsfr_regs[XSFR_PDN3]; break;
+ case 4: port_direction = m_sfr_regs[SFR_P4DIR]; pup = m_xsfr_regs[XSFR_PUP4]; pdn = m_xsfr_regs[XSFR_PDN4]; break;
+ }
+
+ LOGMASKED(LOG_PORTS,"%s: writing port %d with direction %02x pup %02x pdn %02x data %02x\n", machine().describe_context(), i, port_direction, pup, pdn, data);
+ m_port_out_cb[i](data); // also send port direction??
+}
+
+uint8_t axc51base_cpu_device::sfr_read(size_t offset)
+{
+ switch (offset)
+ {
+ case SFR_P0: return read_port(0);
+ case SFR_P1: return read_port(1);
+ case SFR_P2: return read_port(2);
+ case SFR_P3: return read_port(3);
+
+ case SFR_PSW:
+ case SFR_ACC:
+ case SFR_B:
+ case SFR_SP:
+ case SFR_DPL0:
+ case SFR_DPH0:
+ case SFR_PCON:
+ case SFR_IE:
+ case SFR_IE1:
+
+ case SFR_DPL1: // 0x84
+ case SFR_DPH1: // 0x85
+
+ case SFR_IP:
+
+ case SFR_GP0: // 0xa1
+ case SFR_GP1: // 0xa2
+ case SFR_GP2: // 0xa3
+ case SFR_GP3: // 0xa4
+ case SFR_GP4: // 0xb1
+ case SFR_GP5: // 0xb2
+ case SFR_GP6: // 0xb3
+ case SFR_GP7: // 0xb5
+ return m_sfr_regs[offset];
+
+ case SFR_P4: // 0xb4
+ return read_port(4);
+
+ case SFR_P0DIR: // 0xba
+ case SFR_P1DIR: // 0xbb
+ case SFR_P2DIR: // 0xbc
+ case SFR_P3DIR: // 0xbd
+ case SFR_P4DIR: // 0xbe
+
+ case SFR_ER00: // 0xe6
+ case SFR_ER01: // 0xe7
+ case SFR_ER10: // 0xe8
+ case SFR_ER11: // 0xe9
+ case SFR_ER20: // 0xea
+ case SFR_ER21: // 0xeb
+ case SFR_ER30: // 0xec
+ case SFR_ER31: // 0xed
+ case SFR_ER8: // 0xee
+
+ case SFR_TMR0CON: // 0xf8
+ case SFR_TMR0CNT: // 0xf9
+ case SFR_TMR0PR: // 0xfa
+ case SFR_TMR0PSR: // 0xfb
+
+ case SFR_IE2CRPT: // 0x95 controls automatic encryption
+ return m_sfr_regs[offset];
+
+
+ case SFR_DPCON: // 0x86
+ return dpcon_r();
+
+ case SFR_IRTCON: // 0x9f
+ return 0x00;// machine().rand();
+
+ case SFR_SPICON: // 0xd8
+ return spicon_r();
+
+ case SFR_SPIBUF: // 0xd9
+ return spibuf_r();
+
+ case SFR_UID0: return m_uid[0]; // 0xe2 Chip-ID, can only be read from code in internal area?
+ case SFR_UID1: return m_uid[1]; // 0xe3
+ case SFR_UID2: return m_uid[2]; // 0xe4
+ case SFR_UID3: return m_uid[3]; // 0xe5
+
+ case SFR_LFSRFIFO: // 0xf6
+ return 0x00;// machine().rand();
+
+ case SFR_UARTSTA: // 0xfc
+ return uartsta_r();
+
+ /* Illegal or non-implemented sfr */
+ default:
+ LOGMASKED(LOG_UNHANDLED,"%s: attemping to read an invalid/non-implemented SFR address: %02x\n", machine().describe_context(), (uint32_t)offset);
+ /* according to the manual, the read may return random bits */
+ return 0xff;
+ }
+}
+
+
+void axc51base_cpu_device::device_start()
+{
+ space(AS_PROGRAM).cache(m_program);
+ space(AS_DATA).specific(m_data);
+ space(AS_IO).specific(m_io);
+
+ /* Save states */
+ save_item(NAME(m_ppc));
+ save_item(NAME(m_pc));
+ save_item(NAME(m_last_op));
+ save_item(NAME(m_last_bit));
+ save_item(NAME(m_last_line_state) );
+ save_item(NAME(m_recalc_parity) );
+ save_item(NAME(m_sfr_regs));
+ save_item(NAME(m_xsfr_regs));
+
+ state_add( SFR_STATEREG_PC, "PC", m_pc).formatstr("%04X");
+ state_add( SFR_STATEREG_SP, "SP", SP).formatstr("%02X");
+ state_add( SFR_STATEREG_PSW, "PSW", PSW).formatstr("%02X");
+ state_add( SFR_STATEREG_ACC, "A", ACC).formatstr("%02X");
+ state_add( SFR_STATEREG_B, "B", B).formatstr("%02X");
+ state_add<uint16_t>( SFR_STATEREG_DPTR0, "DPTR0", [this](){ return DPTR0; }, [this](uint16_t dp){ SET_DPTR0(dp); }).formatstr("%04X");
+ state_add<uint16_t>( SFR_STATEREG_DPTR1, "DPTR1", [this](){ return DPTR1; }, [this](uint16_t dp){ SET_DPTR1(dp); }).formatstr("%04X");
+ state_add( SFR_STATEREG_DPH0, "DPH0", DPH0).noshow();
+ state_add( SFR_STATEREG_DPL0, "DPL0", DPL0).noshow();
+ state_add( SFR_STATEREG_IE, "IE", IE).formatstr("%02X");
+ state_add( SFR_STATEREG_IP, "IP", IP).formatstr("%02X");
+ if (m_rom_size > 0)
+ state_add<uint8_t>( SFR_STATEREG_P0, "P0", [this](){ return P0; }, [this](uint8_t p){ SET_P0(p); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_P1, "P1", [this](){ return P1; }, [this](uint8_t p){ SET_P1(p); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_P2, "P2", [this](){ return P2; }, [this](uint8_t p){ SET_P2(p); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_P3, "P3", [this](){ return P3; }, [this](uint8_t p){ SET_P3(p); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_R0, "R0", [this](){ return R_REG(0); }, [this](uint8_t r){ SET_REG(0, r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_R1, "R1", [this](){ return R_REG(1); }, [this](uint8_t r){ SET_REG(1, r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_R2, "R2", [this](){ return R_REG(2); }, [this](uint8_t r){ SET_REG(2, r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_R3, "R3", [this](){ return R_REG(3); }, [this](uint8_t r){ SET_REG(3, r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_R4, "R4", [this](){ return R_REG(4); }, [this](uint8_t r){ SET_REG(4, r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_R5, "R5", [this](){ return R_REG(5); }, [this](uint8_t r){ SET_REG(5, r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_R6, "R6", [this](){ return R_REG(6); }, [this](uint8_t r){ SET_REG(6, r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_R7, "R7", [this](){ return R_REG(7); }, [this](uint8_t r){ SET_REG(7, r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_RB, "RB", [this](){ return (PSW & 0x18)>>3; }, [this](uint8_t rb){ SET_RS(rb); }).mask(0x03).formatstr("%02X");
+
+ state_add<uint16_t>( SFR_STATEREG_ER0, "ER0", [this](){ return ER0; }, [this](uint16_t dp){ SET_ER0(dp); }).formatstr("%04X");
+ state_add<uint16_t>( SFR_STATEREG_ER1, "ER1", [this](){ return ER1; }, [this](uint16_t dp){ SET_ER1(dp); }).formatstr("%04X");
+ state_add<uint16_t>( SFR_STATEREG_ER2, "ER2", [this](){ return ER2; }, [this](uint16_t dp){ SET_ER2(dp); }).formatstr("%04X");
+ state_add<uint16_t>( SFR_STATEREG_ER3, "ER3", [this](){ return ER3; }, [this](uint16_t dp){ SET_ER3(dp); }).formatstr("%04X");
+
+ state_add<uint8_t>( SFR_ER8, "ER8", [this](){ return ER8; }, [this](uint8_t r){ SET_ER8(r); }).formatstr("%02X");
+
+ state_add<uint8_t>( SFR_STATEREG_GP0, "GP0", [this](){ return GP0; }, [this](uint8_t r){ SET_GP0(r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_GP1, "GP1", [this](){ return GP1; }, [this](uint8_t r){ SET_GP1(r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_GP2, "GP2", [this](){ return GP2; }, [this](uint8_t r){ SET_GP2(r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_GP3, "GP3", [this](){ return GP3; }, [this](uint8_t r){ SET_GP3(r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_GP4, "GP4", [this](){ return GP4; }, [this](uint8_t r){ SET_GP4(r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_GP5, "GP5", [this](){ return GP5; }, [this](uint8_t r){ SET_GP5(r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_GP6, "GP6", [this](){ return GP6; }, [this](uint8_t r){ SET_GP6(r); }).formatstr("%02X");
+ state_add<uint8_t>( SFR_STATEREG_GP7, "GP7", [this](){ return GP7; }, [this](uint8_t r){ SET_GP7(r); }).formatstr("%02X");
+
+
+
+ state_add( STATE_GENPC, "GENPC", m_pc ).noshow();
+ state_add( STATE_GENPCBASE, "CURPC", m_pc ).noshow();
+ state_add( STATE_GENFLAGS, "GENFLAGS", m_rtemp).formatstr("%8s").noshow();
+
+ set_icountptr(m_icount);
+
+ m_timer0 = timer_alloc(FUNC(axc51base_cpu_device::timer0_cb), this);
+ m_dactimer = timer_alloc(FUNC(axc51base_cpu_device::dactimer_cb), this);
+
+}
+
+void axc51base_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ str = string_format("%c%c%c%c%c%c%c%c",
+ PSW & 0x80 ? 'C':'.',
+ PSW & 0x40 ? 'A':'.',
+ PSW & 0x20 ? 'c':'.', // EC
+ PSW & 0x10 ? '0':'.',
+ PSW & 0x08 ? '1':'.',
+ PSW & 0x04 ? 'V':'.',
+ PSW & 0x02 ? 'z':'.', // EZ
+ PSW & 0x01 ? 'P':'.');
+ break;
+ }
+}
+
+/* Reset registers to the initial values */
+void axc51base_cpu_device::device_reset()
+{
+ m_last_line_state = 0;
+
+ /* Flag as NO IRQ in Progress */
+ m_last_op = 0;
+ m_last_bit = 0;
+
+ /* these are all defined reset states */
+ m_ppc = m_pc;
+ m_pc = 0;
+ SP = 0x7;
+ SET_PSW(0);
+ SET_ACC(0);
+ DPH0 = 0;
+ DPL0 = 0;
+ B = 0;
+ IP = 0;
+ IE = 0;
+ PCON = 0;
+
+ /* set the port configurations to all 1's */
+ SET_P3(0xff);
+ SET_P2(0xff);
+ SET_P1(0xff);
+ SET_P0(0xff);
+
+ m_recalc_parity = 0;
+
+ m_spi_dma_addr = 0;
+
+// m_timer0->adjust(attotime::never);
+// m_dactimer->adjust(attotime::never);
+
+
+ m_timer0->adjust(attotime::from_hz(120), 0, attotime::from_hz(120));
+ m_dactimer->adjust(attotime::from_hz(8000), 0, attotime::from_hz(8000));
+}
+
+
+std::unique_ptr<util::disasm_interface> axc51base_cpu_device::create_disassembler()
+{
+ return std::make_unique<axc51core_disassembler>();
+}
+
+
+
+
+/*
+
+SFR_SPICON (at 0xd8)
+
+7 SPIPND (0 = Send not finished, 1 = finished)
+6 SPISM (0 = Master, 1 = Slave)
+5 SPIRT (RX/TX select for 2-wire mode / DMA, 0 = TX, 1 = RX)
+4 SPIWS (0 = 3-wire mode, 1 = 2-wire mode)
+3 SPIGSEL (0 = group 0, 1 = group 1)
+2 SPIEDGE (if SPIIDST == 0 then 0 = falling edge, 1 = rising edge, if SPIIDST == 1 inverted)
+1 SPIDST (0 = clock signal is 0 when idle, 1 = clock signal is 1 when idle)
+0 SPIEN (0 = SPI disable, 1 = enable)
+*/
+
+uint8_t axc51base_cpu_device::spicon_r()
+{
+ uint8_t result = m_sfr_regs[SFR_SPICON] | 0x80;
+// LOGMASKED(LOG_UNSORTED,"%s: sfr_read SFR_SPICON %02x\n", machine().describe_context(), result);
+ return result;
+}
+
+/*
+
+SFR_UARTSTA (at 0xfc)
+
+7 UTRXNB (9th bit of data of RX buffer)
+6 FEF (0 = stop bit was 1 in last frame, 1 = stop bit was 0)
+5 RXIF (0 = receive not done, 1 = done)
+4 TXIF (0 = transmit not done, 1 = done)
+3 ---
+2 ---
+1 ---
+0 PSEL (UART port / pin select)
+
+*/
+
+uint8_t axc51base_cpu_device::uartsta_r()
+{
+ //uint8_t result = m_sfr_regs[SFR_UARTSTA];
+ uint8_t result = 0x30;
+ LOGMASKED(LOG_UNSORTED, "%s: sfr_read SFR_UARTSTA %02x\n", machine().describe_context(), result);
+ return result;
+}
+
+
+void axc51base_cpu_device::spicon_w(uint8_t data)
+{
+// LOGMASKED(LOG_UNSORTED,"%s: sfr_write SFR_SPICON %02x\n", machine().describe_context(), data);
+ m_sfr_regs[SFR_SPICON] = data;
+ m_spi_out_dir_cb((data & 0x20) ? true : false);
+}
+
+
+
+uint8_t axc51base_cpu_device::dpcon_r()
+{
+ LOGMASKED(LOG_UNSORTED,"%s: sfr_read SFR_DPCON\n", machine().describe_context());
+ return m_sfr_regs[SFR_DPCON];
+}
+
+uint8_t axc51base_cpu_device::spibuf_r()
+{
+ // TODO: encryption here (if enabled)
+ uint8_t ret = m_spi_in_cb();
+ if (m_sfr_regs[SFR_IE2CRPT] & 0x03)
+ ret = machine().rand();
+
+ return ret;
+}
+
+void axc51base_cpu_device::spibuf_w(uint8_t data)
+{
+ // TODO: encryption here (if enabled)
+ m_spi_out_cb(data);
+}
+
+void axc51base_cpu_device::spibaud_w(uint8_t data)
+{
+ LOGMASKED(LOG_UNSORTED,"%s: sfr_write SFR_SPIBAUD %02x\n", machine().describe_context(), data);
+ m_sfr_regs[SFR_SPIBAUD] = data;
+}
+
+/*
+SFR_DPCON (at 0x86)
+
+7 IA 01 = vector base 0x4003, 10 = vector base 0x8003, 00/11 invalid
+6 IA
+5 DPID0 DPTR0 increase direction control, 0 = increase, 1 = decrease
+4 DPID1 DPTR1 increase direction control, 0 = increase, 1 = descrese
+3 DPAID DPTR auto increase enable
+2 DPTSL DPSEL auto-toggle enable (0 = no auto toggle, 1 = auto toggle)
+1 ---
+0 DPSEL DPTR Select (0 = use DPTR0, 1 = use DPTR1)
+*/
+
+void axc51base_cpu_device::dpcon_w(uint8_t data)
+{
+ m_sfr_regs[SFR_DPCON] = data;
+}
+
+/*
+SFR_IE2CRPT (at 0x95)
+
+7 ----
+6 ----
+5 wdt_int_enable
+4 soft_int
+3 sd_do_crypt
+2 sd_di_crypt
+1 spi_do_crypt
+0 spi_di_crypt
+
+*/
+
+void axc51base_cpu_device::ie2crypt_w(uint8_t data)
+{
+ LOGMASKED(LOG_UNSORTED,"%s: sfr_write SFR_IE2CRPT %02x\n", machine().describe_context(), data);
+ m_sfr_regs[SFR_IE2CRPT] = data;
+
+ if (data & 0x03)
+ {
+ LOGMASKED(LOG_UNSORTED,"SPI encryption turned on!\n");
+ }
+
+ if (data & 0x0c)
+ {
+ LOGMASKED(LOG_UNSORTED,"SD Card encryption turned on!\n");
+ }
+}
+
+
+
+
+void axc51base_cpu_device::spidmaadr_w(uint8_t data)
+{
+ m_sfr_regs[SFR_SPIDMAADR] = data;
+
+ m_spi_dma_addr <<= 8;
+ m_spi_dma_addr = (m_spi_dma_addr & 0xff00) | data;
+
+}
+
+void axc51base_cpu_device::spidmacnt_w(uint8_t data)
+{
+ m_sfr_regs[SFR_SPIDMACNT] = data;
+
+ if (((m_sfr_regs[SFR_SPICON]) & 0x20) == 0x20) // Read from SPI
+ {
+ for (int i = 0; i < (data + 1) * 2; i++)
+ {
+ spibuf_w(0x00); // clock
+ uint8_t romdat = spibuf_r();
+ m_io.write_byte(m_spi_dma_addr++, romdat); // is this the correct destination space?
+ }
+ }
+ else
+ {
+ for (int i = 0; i < (data + 1) * 2; i++)
+ {
+ uint8_t ramdat = m_io.read_byte(m_spi_dma_addr++);
+ spibuf_w(ramdat);
+ }
+
+ }
+}
+
+ROM_START( ax208 ) // assume all production ax208 chips use this internal ROM
+ ROM_REGION( 0x2000, "rom", 0 )
+ ROM_LOAD("ax208.bin", 0x0000, 0x2000, CRC(b85f954a) SHA1(0dc7ab9bdaf73231d4d6627fe6308fe8103e1bbc) )
+ROM_END
+
+const tiny_rom_entry *ax208_cpu_device::device_rom_region() const
+{
+ return ROM_NAME( ax208 );
+}
+
+void ax208_cpu_device::device_reset()
+{
+ axc51base_cpu_device::device_reset();
+ set_state_int(SFR_STATEREG_PC, 0x8000);
+}
+
+
+// AX208 (specific CPU)
+
+ax208_cpu_device::ax208_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : axc51base_cpu_device(mconfig, type, tag, owner, clock, address_map_constructor(FUNC(ax208_cpu_device::ax208_internal_program_mem), this), address_map_constructor(FUNC(ax208_cpu_device::data_internal), this), address_map_constructor(FUNC(axc51base_cpu_device::io_internal), this), 0, 8)
+{
+}
+
+ax208_cpu_device::ax208_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ax208_cpu_device(mconfig, AX208, tag, owner, clock)
+{
+}
+
+
+std::unique_ptr<util::disasm_interface> ax208_cpu_device::create_disassembler()
+{
+ return std::make_unique<ax208_disassembler>();
+}
+
+
+
+
+ax208p_cpu_device::ax208p_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ax208_cpu_device(mconfig, AX208P, tag, owner, clock)
+{
+}
+
+ROM_START( ax208p ) // this is an early revision of the internal AX208 code, some functions are moved around so it isn't entirely compatible
+ ROM_REGION( 0x2000, "rom", 0 )
+ ROM_LOAD("mask208.bin", 0x0000, 0x2000, CRC(52396183) SHA1(b119000f93251894a352ecf675ee42f2e5c347bd) )
+ROM_END
+
+const tiny_rom_entry *ax208p_cpu_device::device_rom_region() const
+{
+ return ROM_NAME( ax208p );
+}
+
+