diff options
Diffstat (limited to 'src/mame/drivers/nc.c')
-rw-r--r-- | src/mame/drivers/nc.c | 1556 |
1 files changed, 1556 insertions, 0 deletions
diff --git a/src/mame/drivers/nc.c b/src/mame/drivers/nc.c new file mode 100644 index 00000000000..7bf13f6d188 --- /dev/null +++ b/src/mame/drivers/nc.c @@ -0,0 +1,1556 @@ +// license:GPL-2.0+ +// copyright-holders:Wilbert Pol, Kevin Thacker +/****************************************************************************** + + nc.c + + NC100/NC150/NC200 Notepad computer + + system driver + + + Thankyou to: + Cliff Lawson, Russell Marks and Tim Surtel + + Documentation: + + NC100: + NC100 I/O Specification by Cliff Lawson, + NC100EM by Russell Marks + NC200: + Dissassembly of the NC200 ROM + e-mail + exchange with Russell Marks + + + NC100: + + Hardware: + - Z80 CPU, 6 MHz + - memory powered by lithium batterys! + - 2 channel tone (programmable frequency beep's) + - LCD screen + - laptop/portable computer + - qwerty keyboard + - serial/parallel connection + - Amstrad custom ASIC chip + - tc8521 real time clock + - intel 8251 compatible uart + - PCMCIA Memory cards supported, up to 1mb! + + NC200: + + Hardware: + - Z80 CPU + - Intel 8251 compatible uart + - upd765 compatible floppy disc controller + - mc146818 real time clock? + - 720k floppy disc drive (compatible with MS-DOS) + (disc drive can be not ready). + - PCMCIA Memory cards supported, up to 1mb! + + TODO: + - find out what the unused key bits are for + (checked all unused bits on nc200! - do not seem to have any use!) + - complete serial (xmodem protocol!) + - overlay would be nice! + - finish NC200 disc drive emulation (closer!) + - add NC150 driver - ROM needed!!! + - on/off control + - check values read from other ports that are not described! + - what is read from unmapped ports? + - what is read from uart when it is off? + - check if uart ints are generated when it is off? + - are ints cancelled if uart is turned off after int has been caused? + - check keyboard ints - are these regular or what?? + + PCMCIA memory cards are stored as a direct dump of the contents. There is no header + information. No distinction is made between RAM and ROM cards. + + Memory card sizes are a power of 2 in size (e.g. 1mb, 512k, 256k etc), + however the code allows any size, but it limits access to power of 2 sizes, with + minimum access being 16k. If a file which is less than 16k is used, no memory card + will be present. If a file which is greater than 1mb is used, only 1mb will be accessed. + + Interrupt system of NC100: + + The IRQ mask is used to control the interrupt sources that can interrupt. + + The IRQ status can be read to determine which devices are interrupting. + Some devices, e.g. serial, cannot be cleared by writing to the irq status + register. These can only be cleared by performing an operation on the + device (e.g. reading a data register). + + Self Test: + + - requires memory save and real time clock save to be working! + (i.e. for MESS nc100 driver, nc100.nv can be created) + - turn off nc (use NMI button) + - reset+FUNCTION+SYMBOL must be pressed together. + + Note: NC200 Self test does not test disc hardware :( + + + + Kevin Thacker [MESS driver] + + ******************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "cpu/z80/z80.h" +#include "includes/nc.h" +#include "machine/mc146818.h" /* for NC200 real time clock */ +#include "machine/rp5c01.h" /* for NC100 real time clock */ +#include "machine/upd765.h" /* for NC200 disk drive interface */ +#include "formats/pc_dsk.h" /* for NC200 disk image */ +#include "sound/beep.h" +#include "machine/ram.h" +#include "rendlay.h" + + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define NC200_DEBUG 1 +#define LOG_DEBUG(x) do { if (NC200_DEBUG) logerror x; } while (0) + + +/* the serial clock is generated by the nc hardware and connected to the i8251 +receive clock and transmit clock inputs */ + +/* + Port 0x00: + ========== + + Display memory start: + + NC100: + bit 7 A15 + bit 6 A14 + bit 5 A13 + bit 4 A12 + bits 3-0 Not Used + NC200: + bit 7 A15 + bit 6 A14 + bit 5 A13 + bits 4-0 Not Used + + Port 0x010-0x013: + ================= + + Memory management control: + + NC100 & NC200: + + 10 controls 0000-3FFF + 11 controls 4000-7FFF + 12 controls 8000-BFFF + 13 controls C000-FFFF + + Port 0x030: + =========== + + NC100: + bit 7 select card register 1=common, 0=attribute + bit 6 parallel interface Strobe signal + bit 5 Not Used + bit 4 uPD4711 line driver, 1=off, 0=on + bit 3 UART clock and reset, 1=off, 0=on + + bits 2-0 set the baud rate as follows + + 000 = 150 + 001 = 300 + 010 = 600 + 011 = 1200 + 100 = 2400 + 101 = 4800 + 110 = 9600 + 111 = 19200 + NC200: + bit 7 select card register 1=common, 0=attribute + bit 6 parallel interface Strobe signal + + bit 5 used in disc interface; (set to 0) + + bit 4 uPD4711 line driver, 1=off, 0=on + bit 3 UART clock and reset, 1=off, 0=on + + bits 2-0 set the baud rate as follows + + 000 = 150 + 001 = 300 + 010 = 600 + 011 = 1200 + 100 = 2400 + 101 = 4800 + 110 = 9600 + 111 = 19200 + + + Port 0x0a0: + =========== + + NC100: + bit 7: memory card present 0 = yes, 1 = no + bit 6: memory card write protected 1 = yes, 0 = no + bit 5: input voltage = 1, if >= to 4 volts + bit 4: mem card battery: 0 = battery low + bit 3: alkaline batteries. 0 if >=3.2 volts + bit 2: lithium battery 0 if >= 2.7 volts + bit 1: parallel interface busy (0 if busy) + bit 0: parallel interface ack (1 if ack) + + NC200: + + bit 7: memory card present 0 = yes, 1 = no + bit 6: memory card write protected 1 = yes, 0 = no + bit 5: lithium battery 0 if >= 2.7 volts + bit 4: input voltage = 1, if >= to 4 volts + bit 3: ?? + bit 2: alkaline batteries. 0 if >=3.2 volts + bit 1: ?? + bit 0: battery power: if 1: batteries are too low for disk usage, if 0: batteries ok for disc usage + + + Port 0x060 (IRQ MASK), Port 0x090 (IRQ STATUS): + =============================================== + + NC100: + bit 7: not used + bit 6: not used + bit 5: not used + bit 4: not used + Bit 3: Key scan interrupt (10ms) + Bit 2: ACK from parallel interface + Bit 1: Tx Ready + Bit 0: Rx Ready + + NC200: + bit 7: ??? + bit 6: RTC alarm? + bit 5: FDC interrupt + bit 4: Power off interrupt + Bit 3: Key scan interrupt (10ms) + Bit 2: serial interrupt (tx ready/rx ready combined) + Bit 1: not used + Bit 0: ACK from parallel interface + + Port 0x070: On/off control + + NC200: + bit 7: nc200 power on/off: 1 = on, 0=off + bit 2: backlight: 1=off, 0=on + bit 1: disk motor: 1=off, 0=disk motor??? + bit 0: upd765 terminal count input +*/ + + + +/* latched interrupts are interrupts that cannot be cleared by writing to the irq +mask. latched interrupts can only be cleared by accessing the interrupting +device e.g. serial chip, fdc */ +/* this is a mask of irqs that are latched, and it is different for nc100 and +nc200 */ + +void nc_state::nc_update_interrupts() +{ + m_irq_status &= ~m_irq_latch_mask; + m_irq_status |= m_irq_latch; + + /* any ints set and they are not masked? */ + if ( + (((m_irq_status & m_irq_mask) & 0x3f)!=0) + ) + { + logerror("int set %02x\n", m_irq_status & m_irq_mask); + /* set int */ + m_maincpu->set_input_line(0, HOLD_LINE); + } + else + { + /* clear int */ + m_maincpu->set_input_line(0, CLEAR_LINE); + } +} + +TIMER_CALLBACK_MEMBER(nc_state::nc_keyboard_timer_callback) +{ + LOG(("keyboard int\n")); + + /* set int */ + m_irq_status |= (1<<3); + + /* update ints */ + nc_update_interrupts(); + + /* don't trigger again, but don't free it */ + m_keyboard_timer->reset(); +} + + +static const char *const nc_bankhandler_r[]={ +"bank1", "bank2", "bank3", "bank4"}; + +static const char *const nc_bankhandler_w[]={ +"bank5", "bank6", "bank7", "bank8"}; + +void nc_state::nc_refresh_memory_bank_config(int bank) +{ + address_space &space = m_maincpu->space(AS_PROGRAM); + UINT8 *ptr; + int mem_type; + int mem_bank; + char bank1[10]; + char bank5[10]; + sprintf(bank1,"bank%d",bank+1); + sprintf(bank5,"bank%d",bank+5); + + mem_type = (m_memory_config[bank]>>6) & 0x03; + mem_bank = m_memory_config[bank] & 0x03f; + + space.install_read_bank((bank * 0x4000), (bank * 0x4000) + 0x3fff, nc_bankhandler_r[bank]); + + switch (mem_type) + { + /* ROM */ + case 3: + case 0: + { + mem_bank &= m_membank_rom_mask; + ptr = (memregion("maincpu")->base() + 0x010000) + (mem_bank << 14); + + membank(bank1)->set_base(ptr); + + space.nop_write((bank * 0x4000), (bank * 0x4000) + 0x3fff); + LOG(("BANK %d: ROM %d\n",bank,mem_bank)); + } + break; + + /* internal RAM */ + case 1: + { + mem_bank &= m_membank_internal_ram_mask; + ptr = m_ram->pointer() + (mem_bank << 14); + + membank(bank1)->set_base(ptr); + membank(bank5)->set_base(ptr); + + space.install_write_bank((bank * 0x4000), (bank * 0x4000) + 0x3fff, nc_bankhandler_w[bank]); + LOG(("BANK %d: RAM\n",bank)); + } + break; + + /* card RAM */ + case 2: + { + /* card connected? */ + if (m_card_status && m_card_ram) + { + mem_bank &= m_membank_card_ram_mask; + ptr = m_card_ram->base() + (mem_bank << 14); + + membank(bank1)->set_base(ptr); + + /* write enabled? */ + if (ioport("EXTRA")->read() & 0x02) + { + /* yes */ + membank(bank5)->set_base(ptr); + space.install_write_bank((bank * 0x4000), (bank * 0x4000) + 0x3fff, nc_bankhandler_w[bank]); + } + else + { + /* no */ + space.nop_write((bank * 0x4000), (bank * 0x4000) + 0x3fff); + } + + LOG(("BANK %d: CARD-RAM\n",bank)); + } + else + { + /* if no card connected, then writes fail */ + space.nop_readwrite((bank * 0x4000), (bank * 0x4000) + 0x3fff); + } + } + break; + } +} + +void nc_state::nc_refresh_memory_config() +{ + nc_refresh_memory_bank_config(0); + nc_refresh_memory_bank_config(1); + nc_refresh_memory_bank_config(2); + nc_refresh_memory_bank_config(3); +} + + +TIMER_DEVICE_CALLBACK_MEMBER(nc_state::dummy_timer_callback) +{ + int inputport_10_state; + int changed_bits; + + inputport_10_state = ioport("EXTRA")->read(); + + changed_bits = inputport_10_state^m_previous_inputport_10_state; + + /* on/off button changed state? */ + if (changed_bits & 0x01) + { + if (inputport_10_state & 0x01) + { + /* on NC100 on/off button causes a nmi, on + nc200 on/off button causes an int */ + switch (m_type) + { + case NC_TYPE_1xx: + { + LOG(("nmi triggered\n")); + m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); + } + break; + + case NC_TYPE_200: + { + m_irq_status |= (1 << 4); + nc_update_interrupts(); + } + break; + } + } + } + + /* memory card write enable/disable state changed? */ + if (changed_bits & 0x02) + { + /* yes refresh memory config */ + nc_refresh_memory_config(); + } + + m_previous_inputport_10_state = inputport_10_state; +} + + + +void nc_state::nc_common_init_machine() +{ + /* setup reset state */ + m_display_memory_start = 0; + + /* setup reset state */ + m_memory_config[0] = 0; + m_memory_config[1] = 0; + m_memory_config[2] = 0; + m_memory_config[3] = 0; + + m_previous_inputport_10_state = ioport("EXTRA")->read(); + + /* setup reset state ints are masked */ + m_irq_mask = 0; + /* setup reset state no ints wanting servicing */ + m_irq_status = 0; + /* at reset set to 0x0ffff */ + + m_irq_latch = 0; + m_irq_latch_mask = 0; + + /* setup reset state */ + m_sound_channel_periods[0] = (m_sound_channel_periods[1] = 0x0ffff); + + /* at reset set to 1 */ + m_poweroff_control = 1; + + nc_refresh_memory_config(); + nc_update_interrupts(); + + /* at reset set to 0x0ff */ + m_uart_control = 0x0ff; +} + +static ADDRESS_MAP_START(nc_map, AS_PROGRAM, 8, nc_state ) + AM_RANGE(0x0000, 0x3fff) AM_READ_BANK("bank1") AM_WRITE_BANK("bank5") + AM_RANGE(0x4000, 0x7fff) AM_READ_BANK("bank2") AM_WRITE_BANK("bank6") + AM_RANGE(0x8000, 0xbfff) AM_READ_BANK("bank3") AM_WRITE_BANK("bank7") + AM_RANGE(0xc000, 0xffff) AM_READ_BANK("bank4") AM_WRITE_BANK("bank8") +ADDRESS_MAP_END + + +READ8_MEMBER(nc_state::nc_memory_management_r) +{ + return m_memory_config[offset]; +} + +WRITE8_MEMBER(nc_state::nc_memory_management_w) +{ + LOG(("Memory management W: %02x %02x\n",offset,data)); + m_memory_config[offset] = data; + + nc_refresh_memory_config(); +} + +WRITE8_MEMBER(nc_state::nc_irq_mask_w) +{ + LOG(("irq mask w: %02x\n", data)); + LOG_DEBUG(("irq mask nc200 w: %02x\n",data & ((1<<4) | (1<<5) | (1<<6) | (1<<7)))); + + /* writing mask clears ints that are to be masked? */ + m_irq_mask = data; + + nc_update_interrupts(); +} + +WRITE8_MEMBER(nc_state::nc_irq_status_w) +{ + LOG(("irq status w: %02x\n", data)); + data = data^0x0ff; + + if (m_type == NC_TYPE_200) + { + /* Russell Marks confirms that on the NC200, the key scan interrupt must be explicitly + cleared. It is not automatically cleared when reading 0x0b9 */ + if ((data & (1<<3))!=0) + { + /* set timer to occur again */ + m_keyboard_timer->reset(attotime::from_msec(10)); + + nc_update_interrupts(); + } + } + + +/* writing to status will clear int, will this re-start the key-scan? */ +#if 0 + if ( + /* clearing keyboard int? */ + ((data & (1<<3))!=0) && + /* keyboard int request? */ + ((m_irq_status & (1<<3))!=0) + ) + { + /* set timer to occur again */ + m_keyboard_timer->reset(attotime::from_msec(10)); + } +#endif + m_irq_status &=~data; + + nc_update_interrupts(); +} + +READ8_MEMBER(nc_state::nc_irq_status_r) +{ + return ~((m_irq_status & (~m_irq_latch_mask)) | m_irq_latch); +} + + +READ8_MEMBER(nc_state::nc_key_data_in_r) +{ + static const char *const keynames[] = { + "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", + "LINE5", "LINE6", "LINE7", "LINE8", "LINE9" + }; + + if (offset==9) + { + /* reading 0x0b9 will clear int and re-start scan procedure! */ + m_irq_status &= ~(1<<3); + + /* set timer to occur again */ + m_keyboard_timer->reset(attotime::from_msec(10)); + + nc_update_interrupts(); + } + + return ioport(keynames[offset])->read(); +} + + +void nc_state::nc_sound_update(int channel) +{ + int on; + int frequency; + int period; + beep_device *beeper_device = NULL; + + switch(channel) + { + case 0: + beeper_device = m_beeper1; + break; + case 1: + beeper_device = m_beeper2; + break; + } + + period = m_sound_channel_periods[channel]; + + /* if top bit is 0, sound is on */ + on = ((period & (1<<15))==0); + + /* calculate frequency from period */ + frequency = (int)(1000000.0f/((float)((period & 0x07fff)<<1) * 1.6276f)); + + /* set state */ + beeper_device->set_state(on); + /* set frequency */ + beeper_device->set_frequency(frequency); +} + +WRITE8_MEMBER(nc_state::nc_sound_w) +{ + LOG(("sound w: %04x %02x\n", offset, data)); + + switch (offset) + { + case 0x0: + { + /* update period value */ + m_sound_channel_periods[0] = + (m_sound_channel_periods[0] & 0x0ff00) | (data & 0x0ff); + + nc_sound_update(0); + } + break; + + case 0x01: + { + m_sound_channel_periods[0] = + (m_sound_channel_periods[0] & 0x0ff) | ((data & 0x0ff)<<8); + + nc_sound_update(0); + } + break; + + case 0x02: + { + /* update period value */ + m_sound_channel_periods[1] = + (m_sound_channel_periods[1] & 0x0ff00) | (data & 0x0ff); + + nc_sound_update(1); + } + break; + + case 0x03: + { + m_sound_channel_periods[1] = + (m_sound_channel_periods[1] & 0x0ff) | ((data & 0x0ff)<<8); + + nc_sound_update(1); + } + break; + + default: + break; + } +} + +static const int baud_rate_table[]= +{ + 128, //150 + 64, //300 + 32, //600 + 16, //1200 + 8, //2400 + 4, //4800 + 2, //9600 + 1, //19200 +}; + +WRITE_LINE_MEMBER(nc_state::write_uart_clock) +{ + m_uart->write_txc(state); + m_uart->write_rxc(state); +} + +WRITE8_MEMBER(nc_state::nc_uart_control_w) +{ + /* same for nc100 and nc200 */ + m_centronics->write_strobe(BIT(data, 6)); + + /* on/off changed state? */ + if (((m_uart_control ^ data) & (1<<3))!=0) + { + /* changed uart from off to on */ + if ((data & (1<<3))==0) + { + machine().device("uart")->reset(); + } + } + + m_uart_clock->set_clock_scale((double)1 / baud_rate_table[(data & 0x07)]); + + m_uart_control = data; +} + +/* NC100 printer emulation */ +/* port 0x040 (write only) = 8-bit printer data */ +/* port 0x030 bit 6 = printer strobe */ + + + +/********************************************************************************************************/ +/* NC100 hardware */ + + + +WRITE8_MEMBER(nc_state::nc100_display_memory_start_w) +{ + /* bit 7: A15 */ + /* bit 6: A14 */ + /* bit 5: A13 */ + /* bit 4: A12 */ + /* bit 3-0: not used */ + m_display_memory_start = (data & 0x0f0)<<(12-4); + + LOG(("disp memory w: %04x\n", (int) m_display_memory_start)); +} + + +WRITE8_MEMBER(nc_state::nc100_uart_control_w) +{ + nc_uart_control_w(space, offset,data); + +// /* is this correct?? */ +// if (data & (1<<3)) +// { +// /* clear latched irq's */ +// m_irq_latch &= ~3; +// nc_update_interrupts(machine); +// } +} + + +WRITE_LINE_MEMBER(nc_state::nc100_tc8521_alarm_callback) +{ + // TODO +} + +WRITE_LINE_MEMBER(nc_state::nc100_txrdy_callback) +{ + m_irq_latch &= ~(1 << 1); + + /* uart on? */ + if ((m_uart_control & (1 << 3)) == 0) + { + if (state) + { + logerror("tx ready\n"); + m_irq_latch |= (1 << 1); + } + } + + nc_update_interrupts(); +} + +WRITE_LINE_MEMBER(nc_state::nc100_rxrdy_callback) +{ + m_irq_latch &= ~(1<<0); + + if ((m_uart_control & (1<<3))==0) + { + if (state) + { + logerror("rx ready\n"); + m_irq_latch |= (1<<0); + } + } + + nc_update_interrupts(); +} + +WRITE_LINE_MEMBER(nc_state::write_nc100_centronics_ack) +{ + m_centronics_ack = state; + + if (state) + m_irq_status |= 0x04; + else + m_irq_status &= ~0x04; + + /* trigger an int if the irq is set */ + nc_update_interrupts(); +} + +WRITE_LINE_MEMBER(nc_state::write_centronics_busy) +{ + m_centronics_busy = state; +} + +void nc_state::machine_reset() +{ + /* 256k of rom */ + m_membank_rom_mask = 0x0f; + + m_membank_internal_ram_mask = 3; + + m_membank_card_ram_mask = 0x03f; + + nc_common_init_machine(); + + /* serial */ + m_irq_latch_mask = (1<<0) | (1<<1); +} + +void nc_state::machine_start() +{ + m_type = NC_TYPE_1xx; + + std::string region_tag; + m_card_ram = memregion(region_tag.assign(m_card->tag()).append(GENERIC_ROM_REGION_TAG).c_str()); + if (m_card_ram) + m_card_size = m_card_ram->bytes(); + else + m_card_size = 0; + + /* keyboard timer */ + m_keyboard_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(nc_state::nc_keyboard_timer_callback),this)); + m_keyboard_timer->adjust(attotime::from_msec(10)); + + m_nvram->set_base(m_ram->pointer(), m_ram->size()); +} + + +WRITE8_MEMBER(nc_state::nc100_poweroff_control_w) +{ + /* bits 7-1: not used */ + /* bit 0: 1 = no effect, 0 = power off */ + m_poweroff_control = data; + LOG(("nc poweroff control: %02x\n",data)); +} + + +/* nc100 version of card/battery status */ +READ8_MEMBER(nc_state::nc100_card_battery_status_r) +{ + int nc_card_battery_status = 0x0fc; + + /* printer */ + nc_card_battery_status |= m_centronics_ack; + nc_card_battery_status |= m_centronics_busy << 1; + + if (m_card_status) + { + /* card present */ + nc_card_battery_status &=~(1<<7); + } + + if (ioport("EXTRA")->read() & 0x02) + { + /* card write enable */ + nc_card_battery_status &=~(1<<6); + } + + /* enough power - see bit assignments where + nc card battery status is defined */ + nc_card_battery_status |= (1<<5); + nc_card_battery_status &= ~((1<<2) | (1<<3)); + + return nc_card_battery_status; +} + +WRITE8_MEMBER(nc_state::nc100_memory_card_wait_state_w) +{ + LOG(("nc100 memory card wait state: %02x\n",data)); +} + + + +static ADDRESS_MAP_START(nc100_io, AS_IO, 8, nc_state ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x00, 0x0f) AM_WRITE(nc100_display_memory_start_w) + AM_RANGE(0x10, 0x13) AM_READWRITE(nc_memory_management_r, nc_memory_management_w) + AM_RANGE(0x20, 0x20) AM_WRITE(nc100_memory_card_wait_state_w) + AM_RANGE(0x30, 0x30) AM_WRITE(nc100_uart_control_w) + AM_RANGE(0x40, 0x40) AM_DEVWRITE("cent_data_out", output_latch_device, write) + AM_RANGE(0x50, 0x53) AM_WRITE(nc_sound_w) + AM_RANGE(0x60, 0x60) AM_WRITE(nc_irq_mask_w) + AM_RANGE(0x70, 0x70) AM_WRITE(nc100_poweroff_control_w) + AM_RANGE(0x90, 0x90) AM_READWRITE(nc_irq_status_r, nc_irq_status_w) + AM_RANGE(0x91, 0x9f) AM_READ(nc_irq_status_r) + AM_RANGE(0xa0, 0xaf) AM_READ(nc100_card_battery_status_r) + AM_RANGE(0xb0, 0xb9) AM_READ(nc_key_data_in_r) + AM_RANGE(0xc0, 0xc0) AM_DEVREADWRITE("uart",i8251_device, data_r, data_w) + AM_RANGE(0xc1, 0xc1) AM_DEVREADWRITE("uart", i8251_device, status_r, control_w) + AM_RANGE(0xd0, 0xdf) AM_DEVREADWRITE("rtc", rp5c01_device, read, write) +ADDRESS_MAP_END + + +/* 2008-05 FP: +Small note about natural keyboard support (both for nc100 and nc200): currently, +- "Shift" (both L & R) and "Caps Lock" do not work in natural mode (to be investigated) +- "Function" is mapped to 'Left Control' +- "Control" is mapped to 'Right Control' +- "Caps Lock" is mapped to 'Right Alt' +- "On" is mapped to 'F1' +- "Stop" is mapped to 'F2' +- "Symbol" is mapped to 'F3' +- "Menu" is mapped to 'F4' +*/ + +static INPUT_PORTS_START(nc100) + PORT_START("LINE0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) + PORT_BIT(0x04, 0x00, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Left (Red)") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, 0x00, IPT_UNUSED) + PORT_BIT(0x80, 0x00, IPT_UNUSED) + + PORT_START("LINE1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Function (Yellow)") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // 5th row, 1st key on left (where 'fn' is on mac keyboards) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Stop") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT(0x10, 0x00, IPT_UNUSED) + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT(0x80, 0x00, IPT_UNUSED) + + PORT_START("LINE2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Symbol") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(F3)) // 5th row, 3rd key (where 'Alt' usually stays) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') + PORT_BIT(0x10, 0x00, IPT_UNUSED) + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, 0x00, IPT_UNUSED) + PORT_BIT(0x80, 0x00, IPT_UNUSED) + + PORT_START("LINE3") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('\xA3') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + + PORT_START("LINE4") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT(0x02, 0x00, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + + PORT_START("LINE5") + PORT_BIT(0x01, 0x00, IPT_UNUSED) + PORT_BIT(0x02, 0x00, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('g') PORT_CHAR('G') + + PORT_START("LINE6") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Down (Blue)") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Del>") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Right (Green)") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('#') PORT_CHAR('~') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + + PORT_START("LINE7") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Menu") PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + + PORT_START("LINE8") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('@') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + + PORT_START("LINE9") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Del<") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR('8') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + + /* these are not part of the nc100 keyboard */ + /* extra */ + PORT_START("EXTRA") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("On Button") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(F1)) + /* pcmcia memory card setting */ + PORT_DIPNAME( 0x02, 0x002, "PCMCIA Memory card write enable") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) +INPUT_PORTS_END + +/**********************************************************************************************************/ +/* NC150 hardware */ +/* to be completed! */ + +#if 0 +void nc_state::nc150_init_machine() +{ + m_membank_internal_ram_mask = 7; + + m_membank_card_ram_mask = 0x03f; + + nc_common_init_machine(machine); +} +#endif + + + +/**********************************************************************************************************/ +/* NC200 hardware */ + +#ifdef UNUSED_FUNCTION +WRITE8_MEMBER(nc_state::nc200_display_memory_start_w) +{ + /* bit 7: A15 */ + /* bit 6: A14 */ + /* bit 5: A13 */ + /* bit 4-0: not used */ + m_display_memory_start = (data & 0x0e0)<<(12-4); + + LOG(("disp memory w: %04x\n", (int) m_display_memory_start)); +} +#endif + + +WRITE_LINE_MEMBER(nc_state::write_nc200_centronics_ack) +{ + if (state) + m_irq_status |= 0x01; + else + m_irq_status &= ~0x01; + + /* trigger an int if the irq is set */ + nc_update_interrupts(); +} + +/* assumption. nc200 uses the same uart chip. The rxrdy and txrdy are combined +together with a or to generate a single interrupt */ + +void nc_state::nc200_refresh_uart_interrupt() +{ + m_irq_latch &=~(1<<2); + + /* uart enabled? */ + if ((m_uart_control & (1<<3))==0) + { + if ((m_nc200_uart_interrupt_irq & 0x03)!=0) + { + m_irq_latch |= (1<<2); + } + } + nc_update_interrupts(); +} + +WRITE_LINE_MEMBER(nc_state::nc200_txrdy_callback) +{ +// m_nc200_uart_interrupt_irq &=~(1<<0); +// +// if (state) +// { +// m_nc200_uart_interrupt_irq |=(1<<0); +// } +// +// nc200_refresh_uart_interrupt(); +} + +WRITE_LINE_MEMBER(nc_state::nc200_rxrdy_callback) +{ + m_nc200_uart_interrupt_irq &=~(1<<1); + + if (state) + { + m_nc200_uart_interrupt_irq |=(1<<1); + } + + nc200_refresh_uart_interrupt(); +} + +WRITE_LINE_MEMBER( nc_state::nc200_fdc_interrupt ) +{ +#if 0 + m_irq_latch &=~(1<<5); + + if (state) + { + m_irq_latch |=(1<<5); + } +#endif + m_irq_status &=~(1<<5); + + if (state) + { + m_irq_status |=(1<<5); + } + + nc_update_interrupts(); +} + +#ifdef UNUSED_FUNCTION +void nc_state::nc200_floppy_drive_index_callback(int drive_id) +{ + LOG_DEBUG(("nc200 index pulse\n")); +// m_irq_status |= (1<<4); + +// nc_update_interrupts(Machine); +} +#endif + +MACHINE_RESET_MEMBER(nc_state, nc200) +{ + /* 512k of rom */ + m_membank_rom_mask = 0x1f; + + m_membank_internal_ram_mask = 7; + + m_membank_card_ram_mask = 0x03f; + + nc_common_init_machine(); + + m_nc200_uart_interrupt_irq = 0; + + /* fdc, serial */ + m_irq_latch_mask = /*(1<<5) |*/ (1<<2); + + nc200_video_set_backlight(0); +} + +MACHINE_START_MEMBER(nc_state, nc200) +{ + m_type = NC_TYPE_200; + + std::string region_tag; + m_card_ram = memregion(region_tag.assign(m_card->tag()).append(GENERIC_ROM_REGION_TAG).c_str()); + if (m_card_ram) + m_card_size = m_card_ram->bytes(); + else + m_card_size = 0; + + /* keyboard timer */ + m_keyboard_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(nc_state::nc_keyboard_timer_callback),this)); + m_keyboard_timer->adjust(attotime::from_msec(10)); + + m_nvram->set_base(m_ram->pointer(), m_ram->size()); +} + +/* +NC200: + + bit 7: memory card present 0 = yes, 1 = no + bit 6: memory card write protected 1=yes 0=no + bit 5: lithium battery 0 if >= 2.7 volts + bit 4: input voltage = 1, if >= to 4 volts + bit 3: ?? + bit 2: alkaline batteries. 0 if >=3.2 volts + bit 1: ?? + bit 0: battery power: if 1: batteries are too low for disk usage, if 0: batteries ok for disc usage +*/ + + +/* nc200 version of card/battery status */ +READ8_MEMBER(nc_state::nc200_card_battery_status_r) +{ + int nc_card_battery_status = 0x0ff; + + /* enough power */ + + /* input voltage ok */ + nc_card_battery_status |=(1<<4); + /* lithium batteries and alkaline batteries have enough power, + and there is enough power for disk usage */ + nc_card_battery_status &=~((1<<5) | (1<<2) | (1<<0)); + + if (m_card_status) + { + /* card present */ + nc_card_battery_status&=~(1<<7); + } + + if (ioport("EXTRA")->read() & 0x02) + { + /* card write enable */ + nc_card_battery_status &=~(1<<6); + } + + return nc_card_battery_status; +} + + +/* port &80: + + bit 0: Parallel interface BUSY + */ + +READ8_MEMBER(nc_state::nc200_printer_status_r) +{ + UINT8 result = 0; + + result |= m_centronics_busy; + + return result; +} + + +WRITE8_MEMBER(nc_state::nc200_uart_control_w) +{ + /* int reset_fdc = (m_uart_control^data) & (1<<5); */ + + nc_uart_control_w(space, offset,data); + + if (data & (1<<3)) + { + m_nc200_uart_interrupt_irq &=~3; + + nc200_refresh_uart_interrupt(); + } + + /* bit 5 is used in disk interface */ + LOG_DEBUG(("bit 5: PC: %04x %02x\n", m_maincpu->pc(), data & (1 << 5))); +} + + +/* bit 7: same as nc100 */ +/* bit 2: ?? */ +/* bit 1: ?? */ +/* %10000110 = 0x086 */ +/* %10000010 = 0x082 */ +/* %10000011 = 0x083 */ +/* writes 86,82 */ + +/* bit 7: nc200 power control: 1=on, 0=off */ +/* bit 1: disk motor?? */ +/* bit 0: UPD765 Terminal Count input */ + +WRITE8_MEMBER(nc_state::nc200_memory_card_wait_state_w) +{ + upd765a_device *fdc = machine().device<upd765a_device>("upd765"); + LOG_DEBUG(("nc200 memory card wait state: PC: %04x %02x\n", m_maincpu->pc(), data)); +#if 0 + floppy_drive_set_motor_state(0, 1); + floppy_drive_set_ready_state(0, 1, 1); +#endif + fdc->tc_w(data & 0x01); +} + +/* bit 2: backlight: 1=off, 0=on */ +/* bit 1 cleared to zero in disk code */ +/* bit 0 seems to be the same as nc100 */ +WRITE8_MEMBER(nc_state::nc200_poweroff_control_w) +{ + LOG_DEBUG(("nc200 power off: PC: %04x %02x\n", m_maincpu->pc(), data)); + + nc200_video_set_backlight(((data ^ (1 << 2)) >> 2) & 0x01); +} + +static ADDRESS_MAP_START(nc200_io, AS_IO, 8, nc_state ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x00, 0x0f) AM_WRITE(nc100_display_memory_start_w) + AM_RANGE(0x10, 0x13) AM_READWRITE(nc_memory_management_r, nc_memory_management_w) + AM_RANGE(0x20, 0x20) AM_WRITE(nc200_memory_card_wait_state_w) + AM_RANGE(0x30, 0x30) AM_WRITE(nc200_uart_control_w) + AM_RANGE(0x40, 0x40) AM_DEVWRITE("cent_data_out", output_latch_device, write) + AM_RANGE(0x50, 0x53) AM_WRITE(nc_sound_w) + AM_RANGE(0x60, 0x60) AM_WRITE(nc_irq_mask_w) + AM_RANGE(0x70, 0x70) AM_WRITE(nc200_poweroff_control_w) + AM_RANGE(0x80, 0x80) AM_READ(nc200_printer_status_r) + AM_RANGE(0x90, 0x90) AM_READWRITE(nc_irq_status_r, nc_irq_status_w) + AM_RANGE(0xa0, 0xa0) AM_READ(nc200_card_battery_status_r) + AM_RANGE(0xb0, 0xb9) AM_READ(nc_key_data_in_r) + AM_RANGE(0xc0, 0xc0) AM_DEVREADWRITE("uart",i8251_device, data_r, data_w) + AM_RANGE(0xc1, 0xc1) AM_DEVREADWRITE("uart", i8251_device, status_r, control_w) + AM_RANGE(0xd0, 0xd1) AM_DEVREADWRITE("mc", mc146818_device, read, write) + AM_RANGE(0xe0, 0xe1) AM_DEVICE("upd765", upd765a_device, map) +ADDRESS_MAP_END + +static INPUT_PORTS_START(nc200) + PORT_START("LINE0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Left (Red)") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, 0x00, IPT_UNUSED) + PORT_BIT(0x80, 0x00, IPT_UNUSED) + + PORT_START("LINE1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Function (Yellow)") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // 5th row, 1st key on left (where 'fn' is on mac keyboards) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Stop") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT(0x10, 0x00, IPT_UNUSED) + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, 0x00, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + + PORT_START("LINE2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Symbol") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(F3)) // 5th row, 3rd key (where 'Alt' usually stays) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT(0x80, 0x00, IPT_UNUSED) + + PORT_START("LINE3") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('\xA3') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + + PORT_START("LINE4") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x20, 0x00, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + + PORT_START("LINE5") + PORT_BIT(0x01, 0x00, IPT_UNUSED) + PORT_BIT(0x02, 0x00, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('g') PORT_CHAR('G') + + PORT_START("LINE6") + PORT_BIT(0x01, 0x00, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Down (Blue)") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Del>") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Right (Green)") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('#') PORT_CHAR('~') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + + PORT_START("LINE7") + PORT_BIT(0x01, 0x00, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Up (White)") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Menu") PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + + PORT_START("LINE8") + PORT_BIT(0x01, 0x00, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('@') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + + PORT_START("LINE9") + PORT_BIT(0x01, 0x00, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Del<") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR('8') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + + /* not part of the nc200 keyboard */ + PORT_START("EXTRA") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("On Button") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(F1)) + /* pcmcia memory card setting */ + PORT_DIPNAME( 0x02, 0x002, "PCMCIA Memory card write enable") + PORT_DIPSETTING( 0x00, DEF_STR( Off) ) + PORT_DIPSETTING( 0x02, DEF_STR( On) ) +INPUT_PORTS_END + +/**********************************************************************************************************/ + +static MACHINE_CONFIG_START( nc100, nc_state ) + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", Z80, /*6000000*/ 4606000) /* Russell Marks says this is more accurate */ + MCFG_CPU_PROGRAM_MAP(nc_map) + MCFG_CPU_IO_MAP(nc100_io) + MCFG_QUANTUM_TIME(attotime::from_hz(60)) + + /* video hardware */ + MCFG_SCREEN_ADD("screen", LCD) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ + MCFG_SCREEN_SIZE(480, 64) + MCFG_SCREEN_VISIBLE_AREA(0, 480-1, 0, 64-1) + MCFG_SCREEN_UPDATE_DRIVER(nc_state, screen_update_nc) + MCFG_SCREEN_PALETTE("palette") + + MCFG_PALETTE_ADD("palette", NC_NUM_COLOURS) + MCFG_PALETTE_INIT_OWNER(nc_state, nc) + + MCFG_DEFAULT_LAYOUT(layout_lcd) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("beep.1", BEEP, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) + MCFG_SOUND_ADD("beep.2", BEEP, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) + + /* printer */ + MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer") + MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(nc_state, write_nc100_centronics_ack)) + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(nc_state, write_centronics_busy)) + + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics") + + /* uart */ + MCFG_DEVICE_ADD("uart", I8251, 0) + MCFG_I8251_RXRDY_HANDLER(WRITELINE(nc_state,nc100_rxrdy_callback)) + MCFG_I8251_TXRDY_HANDLER(WRITELINE(nc_state,nc100_txrdy_callback)) + + MCFG_DEVICE_ADD("uart_clock", CLOCK, 19200) + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(nc_state, write_uart_clock)) + + /* rtc */ + MCFG_DEVICE_ADD("rtc", RP5C01, XTAL_32_768kHz) + MCFG_RP5C01_OUT_ALARM_CB(WRITELINE(nc_state, nc100_tc8521_alarm_callback)) + + /* cartridge */ + MCFG_GENERIC_CARTSLOT_ADD("cardslot", generic_plain_slot, NULL) + MCFG_GENERIC_LOAD(nc_state, nc_pcmcia_card) + MCFG_GENERIC_UNLOAD(nc_state, nc_pcmcia_card) + + /* internal ram */ + MCFG_RAM_ADD(RAM_TAG) + MCFG_RAM_DEFAULT_SIZE("64K") + MCFG_NVRAM_ADD_NO_FILL("nvram") + + /* dummy timer */ + MCFG_TIMER_DRIVER_ADD_PERIODIC("dummy_timer", nc_state, dummy_timer_callback, attotime::from_hz(50)) +MACHINE_CONFIG_END + +static const floppy_format_type ibmpc_floppy_formats[] = { + FLOPPY_PC_FORMAT, + FLOPPY_MFI_FORMAT, + NULL +}; + +static SLOT_INTERFACE_START( ibmpc_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_DERIVED( nc200, nc100 ) + + MCFG_CPU_MODIFY( "maincpu" ) + MCFG_CPU_IO_MAP(nc200_io) + + MCFG_MACHINE_START_OVERRIDE(nc_state, nc200) + MCFG_MACHINE_RESET_OVERRIDE(nc_state, nc200) + + /* video hardware */ + MCFG_SCREEN_MODIFY("screen") + MCFG_SCREEN_SIZE(NC200_SCREEN_WIDTH, NC200_SCREEN_HEIGHT) + MCFG_SCREEN_VISIBLE_AREA(0, NC200_SCREEN_WIDTH-1, 0, NC200_SCREEN_HEIGHT-1) + + MCFG_PALETTE_MODIFY("palette") + MCFG_PALETTE_ENTRIES(NC200_NUM_COLOURS) + MCFG_PALETTE_INIT_OWNER(nc_state, nc) + + /* printer */ + MCFG_DEVICE_MODIFY("centronics") + MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(nc_state, write_nc200_centronics_ack)) + + /* uart */ + MCFG_DEVICE_MODIFY("uart") + MCFG_I8251_RXRDY_HANDLER(WRITELINE(nc_state,nc200_rxrdy_callback)) + MCFG_I8251_TXRDY_HANDLER(WRITELINE(nc_state,nc200_txrdy_callback)) + + /* no rtc */ + MCFG_DEVICE_REMOVE("rtc") + + MCFG_UPD765A_ADD("upd765", true, true) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(nc_state, nc200_fdc_interrupt)) + MCFG_FLOPPY_DRIVE_ADD("upd765:0", ibmpc_floppies, "525dd", ibmpc_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("upd765:1", ibmpc_floppies, "525dd", ibmpc_floppy_formats) + + MCFG_MC146818_ADD( "mc", XTAL_4_194304Mhz ) + + /* internal ram */ + MCFG_RAM_MODIFY(RAM_TAG) + MCFG_RAM_DEFAULT_SIZE("128K") + +MACHINE_CONFIG_END + + +/*************************************************************************** + + Game driver(s) + +***************************************************************************/ + +ROM_START(nc100) + ROM_REGION(((64*1024)+(256*1024)), "maincpu",0) + ROM_SYSTEM_BIOS(0, "106", "ROM v1.06") + ROMX_LOAD("nc100a.rom", 0x010000, 0x040000, CRC(849884f9) SHA1(ff030dd334ca867d620ee4a94b142ef0d93b69b6), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "102dk", "ROM v1.02 Danish") + ROMX_LOAD("nc100_dk_a1.rom", 0x010000, 0x040000, CRC(ebb54923) SHA1(30321011384c5e10204b9a837430c36fc63580d2), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(2, "102de", "ROM v1.02 German") + ROMX_LOAD("nc100_de_a1.rom", 0x010000, 0x040000, CRC(bd9ce223) SHA1(2efb26911832bf1456d76d2508e24c0733dc216d), ROM_BIOS(3)) + ROM_SYSTEM_BIOS(3, "100", "ROM v1.00") + ROMX_LOAD("nc100.rom", 0x010000, 0x040000, CRC(a699eca3) SHA1(ce217d5a298b959ccc3d7bc5c93b1dba043f1339), ROM_BIOS(4)) +ROM_END + + +ROM_START(dw225) + ROM_REGION(((64*1024)+(512*1024)), "maincpu",0) + ROM_LOAD("dr (1.06).ic303", 0x010000, 0x080000, CRC(fcf2f7bd) SHA1(a69951618b24e97154cb4284d215cbf4aa9fb34f)) +ROM_END + + +ROM_START(nc150) + ROM_REGION(((64*1024)+(512*1024)), "maincpu",0) + ROM_SYSTEM_BIOS(0, "b2", "French B2") + ROMX_LOAD("nc150_fr_b2.rom", 0x010000, 0x080000, CRC(be442d14) SHA1(f141d409dc72dc1e6662c21a147231c4df3be6b8), ROM_BIOS(1)) /* French */ + ROM_SYSTEM_BIOS(1, "b1", "Italian B1") + ROMX_LOAD("nc150_it_b1.rom", 0x010000, 0x080000, CRC(1b2fe2fd) SHA1(67eb6bce0b0d4668401d9c8f5a900dc6bd135c21), ROM_BIOS(2)) /* Italian */ +ROM_END + + +ROM_START(nc200) + ROM_REGION(((64*1024)+(512*1024)), "maincpu",0) + ROM_LOAD("nc200.rom", 0x010000, 0x080000, CRC(bb8180e7) SHA1(fb5c93b0a3e199202c6a12548d2617f7a09bae47)) +ROM_END + +/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ +COMP( 1992, nc100, 0, 0, nc100, nc100, nc_state, nc, "Amstrad plc", "NC100", 0 ) +COMP( 1992, dw225, nc100, 0, nc100, nc100, nc_state, nc, "NTS Computer Systems", "DreamWriter 225", 0 ) +COMP( 1992, nc150, nc100, 0, nc100, nc100, nc_state, nc, "Amstrad plc", "NC150", 0 ) +COMP( 1993, nc200, 0, 0, nc200, nc200, nc_state, nc, "Amstrad plc", "NC200", MACHINE_NOT_WORKING ) // boot hangs while checking the MC146818 UIP (update in progress) bit |