diff options
author | 2012-04-15 00:50:27 +0000 | |
---|---|---|
committer | 2012-04-15 00:50:27 +0000 | |
commit | a79525b2717246393c407b8e327e9f6adafd8d17 (patch) | |
tree | 3f5e7140c76ab26654441016349afd3a7d07b496 /src/emu/machine | |
parent | 299ce6042746750145e3af79e5b163c87bb78f64 (diff) |
icecold.c [Sandro Ronco]
- This game has mechanical parts so it's not exactly playable, but it is possible try it until the end giving the expected inputs.
- Imported the i8279 device from MESS and updated to support sensor
mode and mask nibble.
- Made a simple layout and the defined input ports.
New clones marked as GAME_NOT_WORKING
------------------------------------
Zeke's Peak [Sandro Ronco]
Diffstat (limited to 'src/emu/machine')
-rw-r--r-- | src/emu/machine/i8279.c | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/src/emu/machine/i8279.c b/src/emu/machine/i8279.c new file mode 100644 index 00000000000..11f41254c01 --- /dev/null +++ b/src/emu/machine/i8279.c @@ -0,0 +1,499 @@ +/********************************************************************** + + i8279 + +2012-JAN-08 First draft [Robbbert] +2012-JAN-12 Implemented + +Notes: +- All keys MUST be ACTIVE_LOW + + +ToDo: +- Command 5 (Nibble masking and blanking) +- Command 7 (Error Mode) +- Interrupts +- BD pin +- Sensor ram stuff +- save state + + +What has been done: +CMD 0: +- Display Mode +-- Left & Right with no increment are the same thing +-- Right with increment is not emulated yet *** +- Keyboard Mode +-- No particular code has been added for 2-key/N-key rollover, no need +-- Sensor mode is not complete yet *** +-- Encoded and Decoded are done +-- Strobe is done +-- Sensor and FIFO may share the same internal RAM, not sure +CMD 1: +- Clock Divider +-- Value is stored, but internally a fixed value is always used +CMD 2: +- Read FIFO/Sensor RAM +-- FIFO works +-- Sensor RAM works +CMD 3: +- Read Display RAM +-- This works +CMD 4: +- Write Display RAM +-- Right with increment does nothing, the rest is working *** +CMD 5: +- Blank Nibble +-- Not done *** +- Mask Nibble +-- Implemented +CMD 6: +-- All implemented +CMD 7: +- Interrupt +-- Not done +- Error Mode +-- No need to do. + +Interface: +-- All done except BD pin *** + +Status word: +- FIFO bits +-- All done +- Error bit +-- Not done (no need) +- Display unavailable +-- Not done (no need) + + +Items marked (***) can be added if a system appears +that uses this feature. + +**********************************************************************/ + +#include "i8279.h" + +#define LOG 0 + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type I8279 = &device_creator<i8279_device>; + +//------------------------------------------------- +// i8279_device - constructor +//------------------------------------------------- + +i8279_device::i8279_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8279, "Intel 8279", tag, owner, clock) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void i8279_device::device_config_complete() +{ + // inherit a copy of the static data + const i8279_interface *intf = reinterpret_cast<const i8279_interface *>(static_config()); + if (intf != NULL) + { + *static_cast<i8279_interface *>(this) = *intf; + } + + // or initialize to defaults if none provided + else + { + memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb)); + memset(&m_out_sl_cb, 0, sizeof(m_out_sl_cb)); + memset(&m_out_disp_cb, 0, sizeof(m_out_disp_cb)); + memset(&m_out_bd_cb, 0, sizeof(m_out_bd_cb)); + memset(&m_in_rl_cb, 0, sizeof(m_in_rl_cb)); + memset(&m_in_shift_cb, 0, sizeof(m_in_shift_cb)); + memset(&m_in_ctrl_cb, 0, sizeof(m_in_ctrl_cb)); + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8279_device::device_start() +{ + /* resolve callbacks */ + m_out_irq_func.resolve(m_out_irq_cb, *this); + m_out_sl_func.resolve(m_out_sl_cb, *this); + m_out_disp_func.resolve(m_out_disp_cb, *this); + m_out_bd_func.resolve(m_out_bd_cb, *this); + m_in_rl_func.resolve(m_in_rl_cb, *this); + m_in_shift_func.resolve(m_in_shift_cb, *this); + m_in_ctrl_func.resolve(m_in_ctrl_cb, *this); + m_clock = clock(); + m_timer = machine().scheduler().timer_alloc(FUNC(timerproc_callback), (void *)this); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8279_device::device_reset() +{ + UINT8 i; + + // startup values are unknown: setting to 0 + for (i = 2; i < 8; i++) m_cmd[i] = 0; + for (i = 0; i < 8; i++) m_fifo[i] = 0; + for (i = 0; i < 8; i++) m_s_ram[i] = 0; + for (i = 0; i < 16; i++) m_d_ram[i] = 0; + m_status = 0; + m_autoinc = 1; + m_d_ram_ptr = 0; + m_s_ram_ptr = 0; + m_read_flag = 0; + m_scanner = 0; + m_ctrl_key = 1; + m_key_down = 0xffff; + + // from here is confirmed + m_cmd[0] = 8; + m_cmd[1] = 31; + logerror("Initial clock = 3100kHz\n"); + timer_adjust(); +} + + +void i8279_device::timer_adjust() +{ +// Real device runs at about 100kHz internally, clock divider is chosen so that +// this is the case. We do not need such speed, 200Hz is enough. + + //UINT8 divider = (m_cmd[1]) ? m_cmd[1] : 1; + //m_clock = clock() / divider; + + m_clock = 200; + m_timer->adjust(attotime::from_hz(m_clock), 0, attotime::from_hz(m_clock)); +} + + +void i8279_device::clear_display() +{ + // clear all digits + UINT8 i,patterns[4] = { 0, 0, 0x20, 0xff }; + UINT8 data = patterns[(m_cmd[6] & 12) >> 2]; + + // The CD high bit (also done by CA) + if (m_cmd[6] & 0x11) + for (i = 0; i < 16; i++) + m_d_ram[i] = data; + + m_status &= 0x7f; // bit 7 not emulated, but do it anyway + m_d_ram_ptr = 0; // not in the datasheet, but needed + + // The CF bit (also done by CA) + if (m_cmd[6] & 3) + { + m_status &= 0xc0; // blow away fifo + m_s_ram_ptr = 0; // reset sensor pointer + set_irq(0); // reset irq + } +} + + +void i8279_device::set_irq(bool state) +{ + if ( !m_out_irq_func.isnull() ) + m_out_irq_func( state ); +} + + +void i8279_device::new_key(UINT8 data, bool skey, bool ckey) +{ + UINT8 i, rl, sl; + for (i = 0; BIT(data, i); i++); + rl = i; + if (BIT(m_cmd[0], 0)) + { + for (i = 0; !BIT(data, i); i++); + sl = i; + } + else + sl = m_scanner; + + new_fifo( (ckey << 7) | (skey << 6) | (sl << 3) | rl); +} + + +void i8279_device::new_fifo(UINT8 data) +{ + // see if already overrun + if (BIT(m_status, 5)) + return; + + // set overrun flag if full + if (BIT(m_status, 3)) + { + m_status |= 0x20; + return; + } + + m_fifo[m_status & 7] = data; + + // bump fifo size & turn off underrun + UINT8 fifo_size = m_status & 7; + if ((fifo_size)==7) + m_status |= 8; // full + else + m_status = (m_status & 0xe8) + fifo_size + 1; + + if (!fifo_size) + set_irq(1); // something just went into fifo, so int +} + + +TIMER_CALLBACK( i8279_device::timerproc_callback ) +{ + reinterpret_cast<i8279_device*>(ptr)->timer_mainloop(); +} + + +void i8279_device::timer_mainloop() +{ + // control byte 0 + // bit 0 - encoded or decoded keyboard scan + // bits 1,2 - keyboard type + // bit 3 - number of digits to display + // bit 4 - left or right entry + + UINT8 scanner_mask = BIT(m_cmd[0], 0) ? 15 : BIT(m_cmd[0], 3) ? 15 : 7; + bool decoded = BIT(m_cmd[0], 0); + UINT8 kbd_type = (m_cmd[0] & 6) >> 1; + bool shift_key = 1; + bool ctrl_key = 1; + bool strobe_pulse = 0; + + // keyboard + // type 0 = kbd, 2-key lockout + // type 1 = kdb, n-key + // type 2 = sensor + // type 3 = strobed + + // Get shift keys + if ( !m_in_shift_func.isnull() ) + shift_key = m_in_shift_func(); + + if ( !m_in_ctrl_func.isnull() ) + ctrl_key = m_in_ctrl_func(); + + if (ctrl_key && !m_ctrl_key) + strobe_pulse = 1; // low-to-high is a strobe + + m_ctrl_key = ctrl_key; + + // Read a row of keys + + if ( !m_in_rl_func.isnull() ) + { + UINT8 rl = m_in_rl_func(0); + + // see if key still down from last time + UINT16 key_down = (m_scanner << 8) | rl; + if (key_down == m_key_down) + rl = 0xff; + else + if ((rl == 0xff) && (m_scanner == m_key_down >> 8)) + m_key_down = 0xffff; + + // now process new key + if (rl < 0xff || kbd_type == 2) + { + m_key_down = key_down; + switch (kbd_type) + { + case 0: + case 1: + new_key(rl, shift_key, ctrl_key); + break; + case 2: + { + UINT8 addr = m_scanner; + + if (decoded) + for (addr=0; !BIT(m_scanner, addr); addr++); + + rl ^= 0xff; // inverted + if (m_s_ram[addr] != rl) + { + m_s_ram[addr] = rl; + + // IRQ line goes high if a row change value + set_irq(1); + } + } + break; + case 3: + if (strobe_pulse) new_fifo(rl); + break; + } + } + } + + // Increment scanline + + if (decoded) + { + m_scanner<<= 1; + if ((m_scanner & 15)==0) + m_scanner = 1; + } + else + m_scanner++; + + m_scanner &= scanner_mask; // 4-bit port + + if ( !m_out_sl_func.isnull() ) + m_out_sl_func(0, m_scanner); + + // output a digit + + if ( !m_out_disp_func.isnull() ) + m_out_disp_func(0, m_d_ram[m_scanner] ); +} + + +READ8_MEMBER( i8279_device::status_r ) +{ + return m_status; +} + + +READ8_MEMBER( i8279_device::data_r ) +{ + UINT8 i; + bool sensor_mode = ((m_cmd[0] & 6)==4); + UINT8 data; + if (m_read_flag) + { + // read the display ram + data = m_d_ram[m_d_ram_ptr]; + if (m_autoinc) + m_d_ram_ptr++; + } + else + if (sensor_mode) + { + // read sensor ram + data = m_s_ram[m_s_ram_ptr]; + if (m_autoinc) + m_s_ram_ptr++; + else + set_irq(0); + } + else + { + // read a key from fifo + data = m_fifo[0]; + UINT8 fifo_size = m_status & 7; + switch (m_status & 0x38) + { + case 0x00: // no errors + if (!fifo_size) + m_status |= 0x10; // underrun + else + { + for (i = 1; i < 8; i++) + m_fifo[i-1] = m_fifo[i]; + fifo_size--; + if (!fifo_size) + set_irq(0); + } + break; + case 0x28: // overrun + case 0x08: // fifo full + for (i = 1; i < 8; i++) + m_fifo[i-1] = m_fifo[i]; + break; + case 0x10: // underrun + if (!fifo_size) + break; + default: + printf("Invalid status: %X\n", m_status); + } + m_status = (m_status & 0xd0) | fifo_size; // turn off overrun & full + } + + m_d_ram_ptr &= 15; + m_s_ram_ptr &= 7; + return data; +} + + +WRITE8_MEMBER( i8279_device::cmd_w ) +{//printf("Command: %X=%X ",data>>5,data&31); + UINT8 cmd = data >> 5; + data &= 0x1f; + m_cmd[cmd] = data; + switch (cmd) + { + case 0: + if (LOG) logerror("I8279 '%s' kb mode %x, display mode %x\n", tag(), data & 7, (data>>3) & 3); + break; + case 1: + if (data > 1) + { + logerror("Clock set to %dkHz\n",data*100); + timer_adjust(); + } + break; + case 2: + m_read_flag = 0; + if ((m_cmd[0] & 6)==4) // sensor mode only + { + m_autoinc = BIT(data, 4); + m_s_ram_ptr = data & 7; + if (LOG) logerror("I8279 '%s' selct sensor row %x, AI %d\n", tag(), m_s_ram_ptr, m_autoinc); + } + break; + case 3: + m_read_flag = 1; + m_d_ram_ptr = data & 15; + m_autoinc = BIT(data, 4); + break; + case 4: + m_d_ram_ptr = data & 15; + m_autoinc = BIT(data, 4); + break; + case 6: + if (LOG) logerror("I8279 '%s' clear cmd %x\n", tag(), data); + clear_display(); + break; + } +} + + +WRITE8_MEMBER( i8279_device::data_w ) +{//printf("Data: %X ",data); + if (BIT(m_cmd[0], 4) & m_autoinc) + { + // right-entry autoincrement not implemented yet + } + else + { + if (!(m_cmd[5] & 0x04)) + m_d_ram[m_d_ram_ptr] = (m_d_ram[m_d_ram_ptr] & 0xf0) | (data & 0x0f); + if (!(m_cmd[5] & 0x08)) + m_d_ram[m_d_ram_ptr] = (m_d_ram[m_d_ram_ptr] & 0x0f) | (data & 0xf0); + + if (m_autoinc) + m_d_ram_ptr++; + } + m_d_ram_ptr &= 15; +} + |