diff options
author | 2019-03-25 22:44:58 +0100 | |
---|---|---|
committer | 2019-03-25 22:44:58 +0100 | |
commit | c24473ddff715ecec2e258a6eb38960cf8c8e98e (patch) | |
tree | 8ea44b6396a6129913c0aac13859b5de9965e972 /src/devices/cpu/tms9900 | |
parent | 009cba4fb8102102168ef32870892438327f3705 (diff) | |
parent | 598cd5227223c3b04ca31f0dbc1981256d9ea3ff (diff) |
conflict resolution (nw)
Diffstat (limited to 'src/devices/cpu/tms9900')
-rw-r--r-- | src/devices/cpu/tms9900/tms9900.cpp | 87 | ||||
-rw-r--r-- | src/devices/cpu/tms9900/tms9995.cpp | 108 | ||||
-rw-r--r-- | src/devices/cpu/tms9900/tms9995.h | 2 |
3 files changed, 90 insertions, 107 deletions
diff --git a/src/devices/cpu/tms9900/tms9900.cpp b/src/devices/cpu/tms9900/tms9900.cpp index 8f092a3159d..840fd5d631a 100644 --- a/src/devices/cpu/tms9900/tms9900.cpp +++ b/src/devices/cpu/tms9900/tms9900.cpp @@ -182,11 +182,11 @@ tms99xx_device::tms99xx_device(const machine_config &mconfig, device_type type, : cpu_device(mconfig, type, tag, owner, clock), m_program_config("program", ENDIANNESS_BIG, data_width, prg_addr_bits), m_setoffset_config("setoffset", ENDIANNESS_BIG, data_width, prg_addr_bits), - m_io_config("cru", ENDIANNESS_BIG, 8, cru_addr_bits), + m_io_config("cru", ENDIANNESS_LITTLE, 8, cru_addr_bits + 1, 1), m_prgspace(nullptr), m_cru(nullptr), m_prgaddr_mask((1<<prg_addr_bits)-1), - m_cruaddr_mask((1<<cru_addr_bits)-1), + m_cruaddr_mask((2<<cru_addr_bits)-2), m_clock_out_line(*this), m_wait_line(*this), m_holda_line(*this), @@ -1625,67 +1625,70 @@ void tms99xx_device::register_write() idempotent (i.e. they must not change the state of the queried device). Read returns the number of consecutive CRU bits, with increasing CRU address - from the least significant to the most significant bit; right-aligned + from the least significant to the most significant bit; right-aligned (in + other words, little-endian as opposed to the big-endian order of memory words). There seems to be no handling of wait states during CRU operations on the TMS9900. The TMS9995, in contrast, respects wait states during the transmission of each single bit. + The current emulation of the CRU space involves a 1-bit address shift, + reflecting the one-to-one correspondence between CRU bits and words (not + bytes) in the lower part of the memory space. (On the TMS9980A and TMS9995, + CRUOUT is multiplexed with the least significant address line.) Thus, what + TI's documentation calls the software address (the R12 base value plus the + bit offset multiplied by 2) is used in address maps and CPU-side operations. + MAME's memory architecture automatically translates these to right-justified + hardware addresses in the process of decoding offsets for read/write handlers, + which is more typical of what peripheral devices expect. (Note also that + address spaces do not support data widths narrower than 8 bits, so these + handlers must specify 8-bit types despite only one bit being useful.) + Usage of this method: CRU write: First bit is at rightmost position of m_value. */ void tms99xx_device::cru_input_operation() { - int value, value1; - int offset, location; - - location = (m_cru_address >> 4) & (m_cruaddr_mask>>3); - offset = (m_cru_address>>1) & 0x07; + offs_t cruaddr = m_cru_address & m_cruaddr_mask; + uint16_t value = 0; - // Read 8 bits (containing the desired bits) - value = m_cru->read_byte(location); - - if ((offset + m_count) > 8) // spans two 8 bit cluster + for (int i = 0; i < m_count; i++) { - // Read next 8 bits - location = (location + 1) & (m_cruaddr_mask>>3); - value1 = m_cru->read_byte(location); - value |= (value1 << 8); + // Poll one bit at a time + bool cruin = BIT(m_cru->read_byte(cruaddr), 0); + if (cruin) + value |= 1 << i; - if ((offset + m_count) > 16) // spans three 8 bit cluster - { - // Read next 8 bits - location = (location + 1) & (m_cruaddr_mask>>3); - value1 = m_cru->read_byte(location); - value |= (value1 << 16); - } - } + if (TRACE_CRU) logerror("CRU input operation, address %04x, value %d\n", cruaddr, cruin ? 1 : 0); - // On each machine cycle (2 clocks) only one CRU bit is transmitted - pulse_clock(m_count<<1); + // Increment the CRU address + cruaddr = (cruaddr + 2) & m_cruaddr_mask; - // Shift back the bits so that the first bit is at the rightmost place - m_value = (value >> offset); + // On each machine cycle (2 clocks) only one CRU bit is transmitted + pulse_clock(2); + } - // Mask out what we want - m_value &= (0x0000ffff >> (16-m_count)); + m_value = value; } void tms99xx_device::cru_output_operation() { - int value; - int location; - location = (m_cru_address >> 1) & m_cruaddr_mask; - value = m_value; + offs_t cruaddr = m_cru_address & m_cruaddr_mask; + uint16_t value = m_value; // Write m_count bits from cru_address - for (int i=0; i < m_count; i++) + for (int i = 0; i < m_count; i++) { - if (TRACE_CRU) logerror("CRU output operation, address %04x, value %d\n", location<<1, value & 0x01); - m_cru->write_byte(location, (value & 0x01)); + if (TRACE_CRU) logerror("CRU output operation, address %04x, value %d\n", cruaddr, BIT(value, 0)); + + // Write one bit at a time + m_cru->write_byte(cruaddr, BIT(value, 0)); value >>= 1; - location = (location + 1) & m_cruaddr_mask; + + // Increment the CRU address + cruaddr = (cruaddr + 2) & m_cruaddr_mask; + pulse_clock(2); } } @@ -2164,6 +2167,7 @@ void tms99xx_device::alu_clr_swpb() bool setstatus = true; bool check_ov = true; + bool check_c = true; switch (m_command) { @@ -2181,6 +2185,7 @@ void tms99xx_device::alu_clr_swpb() // LAE dest_new = ~src_val & 0xffff; check_ov = false; + check_c = false; break; case NEG: // LAECO @@ -2223,7 +2228,7 @@ void tms99xx_device::alu_clr_swpb() if (setstatus) { if (check_ov) set_status_bit(ST_OV, ((src_val & 0x8000)==sign) && ((dest_new & 0x8000)!=sign)); - set_status_bit(ST_C, (dest_new & 0x10000) != 0); + if (check_c) set_status_bit(ST_C, (dest_new & 0x10000) != 0); m_current_value = dest_new & 0xffff; compare_and_set_lae(m_current_value, 0); } @@ -2515,6 +2520,7 @@ void tms99xx_device::alu_shift() uint16_t sign = 0; uint32_t value; int count; + bool check_ov = false; switch (m_state) { @@ -2572,6 +2578,7 @@ void tms99xx_device::alu_shift() case SLA: carry = ((value & 0x8000)!=0); value <<= 1; + check_ov = true; if (carry != ((value&0x8000)!=0)) overflow = true; break; case SRC: @@ -2584,7 +2591,7 @@ void tms99xx_device::alu_shift() m_current_value = value & 0xffff; set_status_bit(ST_C, carry); - set_status_bit(ST_OV, overflow); + if (check_ov) set_status_bit(ST_OV, overflow); // only SLA compare_and_set_lae(m_current_value, 0); m_address = m_address_saved; // Register address if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); diff --git a/src/devices/cpu/tms9900/tms9995.cpp b/src/devices/cpu/tms9900/tms9995.cpp index c83f74ac073..09509f4623e 100644 --- a/src/devices/cpu/tms9900/tms9995.cpp +++ b/src/devices/cpu/tms9900/tms9995.cpp @@ -170,7 +170,7 @@ tms9995_device::tms9995_device(const machine_config &mconfig, device_type type, PC_debug(0), m_program_config("program", ENDIANNESS_BIG, 8, 16), m_setoffset_config("setoffset", ENDIANNESS_BIG, 8, 16), - m_io_config("cru", ENDIANNESS_BIG, 8, 16), + m_io_config("cru", ENDIANNESS_LITTLE, 8, 16, 1), m_prgspace(nullptr), m_sospace(nullptr), m_cru(nullptr), @@ -288,8 +288,6 @@ void tms9995_device::device_start() save_item(NAME(m_cru_address)); save_item(NAME(m_cru_value)); save_item(NAME(m_cru_first_read)); - save_item(NAME(m_cru_bits_left)); - save_item(NAME(m_cru_read)); save_pointer(NAME(m_flag),16); save_item(NAME(IR)); save_item(NAME(m_pre_IR)); @@ -1510,10 +1508,13 @@ void tms9995_device::int_prefetch_and_decode() // If the current command is XOP or BLWP, ignore the interrupt if (m_command != XOP && m_command != BLWP) { - if (m_flag[2] && intmask >= 1) m_int_pending |= PENDING_LEVEL1; + // The actual interrupt trigger is an OR of the latch and of + // the interrupt line (for INT1 and INT4); see [1], + // section 2.3.2.1.3 + if ((m_int1_active || m_flag[2]) && intmask >= 1) m_int_pending |= PENDING_LEVEL1; if (m_int_overflow && intmask >= 2) m_int_pending |= PENDING_OVERFLOW; if (m_flag[3] && intmask >= 3) m_int_pending |= PENDING_DECR; - if (m_flag[4] && intmask >= 4) m_int_pending |= PENDING_LEVEL4; + if ((m_int4_active || m_flag[4]) && intmask >= 4) m_int_pending |= PENDING_LEVEL4; } if (m_int_pending!=0) @@ -1562,7 +1563,7 @@ void tms9995_device::prefetch_and_decode() m_value_copy = m_current_value; if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); m_address = PC; - LOGMASKED(LOG_DETAIL, "**** Prefetching new instruction at %04x ****\n", PC); + LOGMASKED(LOG_DETAIL, "** Prefetching new instruction at %04x **\n", PC); } word_read(); // changes m_mem_phase @@ -1575,7 +1576,7 @@ void tms9995_device::prefetch_and_decode() m_current_value = m_value_copy; // restore m_current_value PC = (PC + 2) & 0xfffe; // advance PC if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE); - LOGMASKED(LOG_DETAIL, "++++ Prefetch done ++++\n"); + LOGMASKED(LOG_DETAIL, "++ Prefetch done ++\n"); } } @@ -1688,7 +1689,7 @@ void tms9995_device::service_interrupt() vectorpos = 0x0008; m_intmask = 0x0001; PC = (PC + 2) & 0xfffe; - LOGMASKED(LOG_INT, "***** MID pending\n"); + LOGMASKED(LOG_INT, "** MID pending\n"); m_mid_active = false; } else @@ -1698,7 +1699,7 @@ void tms9995_device::service_interrupt() vectorpos = 0xfffc; m_int_pending &= ~PENDING_NMI; m_intmask = 0; - LOGMASKED(LOG_INT, "***** NMI pending\n"); + LOGMASKED(LOG_INT, "** NMI pending\n"); } else { @@ -1706,9 +1707,12 @@ void tms9995_device::service_interrupt() { vectorpos = 0x0004; m_int_pending &= ~PENDING_LEVEL1; - if (!m_int1_active) m_flag[2] = false; + // Latches must be reset when the interrupt is serviced + // Since the latch is edge-triggered, we should be allowed + // to clear it right here, without considering the line state + m_flag[2] = false; m_intmask = 0; - LOGMASKED(LOG_INT, "***** INT1 pending\n"); + LOGMASKED(LOG_INT, "** INT1 pending\n"); } else { @@ -1717,7 +1721,7 @@ void tms9995_device::service_interrupt() vectorpos = 0x0008; m_int_pending &= ~PENDING_OVERFLOW; m_intmask = 0x0001; - LOGMASKED(LOG_INT, "***** OVERFL pending\n"); + LOGMASKED(LOG_INT, "** OVERFL pending\n"); } else { @@ -1727,15 +1731,16 @@ void tms9995_device::service_interrupt() m_intmask = 0x0002; m_int_pending &= ~PENDING_DECR; m_flag[3] = false; - LOGMASKED(LOG_DEC, "***** DECR pending\n"); + LOGMASKED(LOG_DEC, "** DECR pending\n"); } else { vectorpos = 0x0010; m_intmask = 0x0003; m_int_pending &= ~PENDING_LEVEL4; - if (!m_int4_active) m_flag[4] = false; - LOGMASKED(LOG_INT, "***** INT4 pending\n"); + // See above for clearing the latch + m_flag[4] = false; + LOGMASKED(LOG_INT, "** INT4 pending\n"); } } } @@ -1743,7 +1748,7 @@ void tms9995_device::service_interrupt() } } - LOGMASKED(LOG_INT, "********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2); + LOGMASKED(LOG_INTD, "*** triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2); // just for debugging purposes if (!m_reset) m_log_interrupt = true; @@ -2080,8 +2085,7 @@ void tms9995_device::return_with_address_copy() 1FDA MID flag (only indication, does not trigger when set) The TMS9995 allows for wait states during external CRU access. Therefore - we read one block of 8 bits in one go (as given by the MESS architecture) - but we do iterations for each bit, checking every time for the READY line + we do iterations for each bit, checking every time for the READY line in the main loop. (write) @@ -2092,8 +2096,8 @@ void tms9995_device::return_with_address_copy() */ -#define CRUREADMASK 0x0fff -#define CRUWRITEMASK 0x7fff +#define CRUREADMASK 0xfffe +#define CRUWRITEMASK 0xfffe void tms9995_device::cru_output_operation() { @@ -2129,7 +2133,7 @@ void tms9995_device::cru_output_operation() // of the CPU. However, no wait states are generated for internal // accesses. ([1], section 2.3.3.2) - m_cru->write_byte((m_cru_address >> 1)& CRUWRITEMASK, (m_cru_value & 0x01)); + m_cru->write_byte(m_cru_address & CRUWRITEMASK, (m_cru_value & 0x01)); m_cru_value >>= 1; m_cru_address = (m_cru_address + 2) & 0xfffe; m_count--; @@ -2150,55 +2154,29 @@ void tms9995_device::cru_output_operation() void tms9995_device::cru_input_operation() { - uint16_t crubit; - uint8_t crubyte; - - // Reading is different, since MESS uses 8 bit transfers - // We read 8 bits in one go, then iterate another min(n-1,7) times to allow - // for wait states. - - // read_byte for CRU delivers the first bit on the rightmost position - - int offset = (m_cru_address>>1) & 0x07; - - if (m_cru_first_read || m_cru_bits_left == 0) + if (m_cru_first_read) { - // Read next 8 bits - // 00000000 0rrrrrrr r - // v - // ........ ........ X....... ........ - // - crubyte = m_cru->read_byte((m_cru_address >> 4)& CRUREADMASK); - LOGMASKED(LOG_DETAIL, "Need to get next 8 bits (addresses %04x-%04x): %02x\n", (m_cru_address&0xfff0)+14, m_cru_address&0xfff0, crubyte); - m_cru_read = crubyte << 15; - m_cru_bits_left = 8; - - if (m_cru_first_read) - { - m_cru_read >>= offset; - m_cru_bits_left -= offset; - m_cru_value = 0; - m_cru_first_read = false; - m_pass = m_count; - } - LOGMASKED(LOG_DETAIL, "adjusted value for shift: %06x\n", m_cru_read); + m_cru_value = 0; + m_cru_first_read = false; + m_pass = m_count; } - crubit = (m_cru_read & 0x8000); + // Read a single CRU bit + bool crubit = BIT(m_cru->read_byte(m_cru_address & CRUREADMASK), 0); m_cru_value = (m_cru_value >> 1) & 0x7fff; // During internal reading, the CRUIN line will be ignored. We emulate this // by overwriting the bit which we got from outside. Also, READY is ignored. if (m_cru_address == 0x1fda) { - crubit = m_mid_flag? 0x8000 : 0x0000; + crubit = m_mid_flag; m_check_ready = false; } else { if ((m_cru_address & 0xffe0)==0x1ee0) { - crubit = (m_flag[(m_cru_address>>1)&0x000f]==true)? 0x8000 : 0x0000; + crubit = m_flag[(m_cru_address>>1)&0x000f]; m_check_ready = false; } else @@ -2207,18 +2185,14 @@ void tms9995_device::cru_input_operation() } } - LOGMASKED(LOG_CRU, "CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15); + LOGMASKED(LOG_CRU, "CRU input operation, address %04x, value %d\n", m_cru_address, crubit ? 1 : 0); - m_cru_value |= crubit; + if (crubit) + m_cru_value |= 0x8000; m_cru_address = (m_cru_address + 2) & 0xfffe; - m_cru_bits_left--; - if (m_pass > 1) - { - m_cru_read >>= 1; - } - else + if (m_pass == 1) { // This is the final shift. For both byte and word length transfers, // the first bit is always m_cru_value & 0x0001. @@ -3116,6 +3090,7 @@ void tms9995_device::alu_shift() uint16_t sign = 0; uint32_t value; int count; + bool check_ov = false; switch (m_inst_state) { @@ -3164,6 +3139,7 @@ void tms9995_device::alu_shift() case SLA: carry = ((value & 0x8000)!=0); value <<= 1; + check_ov = true; if (carry != ((value&0x8000)!=0)) overflow = true; break; case SRC: @@ -3176,7 +3152,7 @@ void tms9995_device::alu_shift() m_current_value = value & 0xffff; set_status_bit(ST_C, carry); - set_status_bit(ST_OV, overflow); + if (check_ov) set_status_bit(ST_OV, overflow); // only SLA compare_and_set_lae(m_current_value, 0); m_address = m_address_saved; // Register address LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); @@ -3194,6 +3170,7 @@ void tms9995_device::alu_single_arithm() uint32_t src_val = m_current_value & 0x0000ffff; uint16_t sign = 0; bool check_ov = true; + bool check_c = true; switch (m_command) { @@ -3244,6 +3221,7 @@ void tms9995_device::alu_single_arithm() // LAE dest_new = ~src_val & 0xffff; check_ov = false; + check_c = false; break; case NEG: // LAECO @@ -3271,7 +3249,7 @@ void tms9995_device::alu_single_arithm() } if (check_ov) set_status_bit(ST_OV, ((src_val & 0x8000)==sign) && ((dest_new & 0x8000)!=sign)); - set_status_bit(ST_C, (dest_new & 0x10000) != 0); + if (check_c) set_status_bit(ST_C, (dest_new & 0x10000) != 0); m_current_value = dest_new & 0xffff; compare_and_set_lae(m_current_value, 0); diff --git a/src/devices/cpu/tms9900/tms9995.h b/src/devices/cpu/tms9900/tms9995.h index 72dfc2960a1..531e5208a41 100644 --- a/src/devices/cpu/tms9900/tms9995.h +++ b/src/devices/cpu/tms9900/tms9995.h @@ -245,8 +245,6 @@ private: uint16_t m_cru_address; uint16_t m_cru_value; bool m_cru_first_read; - int m_cru_bits_left; - uint32_t m_cru_read; // CPU-internal CRU flags bool m_flag[16]; |