// license:GPL-2.0+
// copyright-holders:Wilbert Pol, Kevin Thacker
/******************************************************************************
nc.cpp
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:
Disassembly of the NC200 ROM + e-mail
exchange with Russell Marks
NC100:
Hardware:
- Z80 CPU, 6 MHz
- memory powered by lithium batteries!
- 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 "includes/nc.h"
#include "cpu/z80/z80.h"
#include "machine/mc146818.h" // for NC200 real time clock
#include "machine/rp5c01.h" // for NC100 real time clock
#include "formats/pc_dsk.h" // for NC200 disk image
#include "screen.h"
#include "speaker.h"
#define LOG_GENERAL (1U << 0)
#define LOG_DEBUG (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_DEBUG)
#include "logmacro.h"
#define LOGDEBUG(...) LOGMASKED(LOG_DEBUG, __VA_ARGS__)
/* 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_t *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_nc_type)
{
case NC_TYPE_1xx:
LOG("nmi triggered\n");
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
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::machine_reset()
{
/* 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;
}
void nc_state::nc_map(address_map &map)
{
map(0x0000, 0x3fff).bankr("bank1").bankw("bank5");
map(0x4000, 0x7fff).bankr("bank2").bankw("bank6");
map(0x8000, 0xbfff).bankr("bank3").bankw("bank7");
map(0xc000, 0xffff).bankr("bank4").bankw("bank8");
}
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);
LOGDEBUG("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;
/* 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();
}
WRITE8_MEMBER(nc200_state::nc200_irq_status_w)
{
LOG("irq status w: %02x\n", data);
data = data ^ 0x0ff;
/* 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();
}
nc_irq_status_w(space, offset, data, mem_mask);
}
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 = nullptr;
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_clock(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)
{
m_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", m_display_memory_start);
}
WRITE8_MEMBER(nc100_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(nc100_state::nc100_tc8521_alarm_callback)
{
// TODO
}
WRITE_LINE_MEMBER(nc100_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(nc100_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(nc100_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 nc100_state::machine_reset()
{
/* 256k of rom */
m_membank_rom_mask = 0x0f;
m_membank_internal_ram_mask = 3;
m_membank_card_ram_mask = 0x03f;
nc_state::machine_reset();
/* serial */
m_irq_latch_mask = (1<<0) | (1<<1);
}
WRITE8_MEMBER(nc100_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(nc100_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(nc100_state::nc100_memory_card_wait_state_w)
{
LOG("nc100 memory card wait state: %02x\n",data);
}
void nc100_state::nc100_io(address_map &map)
{
map.global_mask(0xff);
map.unmap_value_high();
map(0x00, 0x0f).w(FUNC(nc100_state::nc100_display_memory_start_w));
map(0x10, 0x13).rw(FUNC(nc100_state::nc_memory_management_r), FUNC(nc100_state::nc_memory_management_w));
map(0x20, 0x20).w(FUNC(nc100_state::nc100_memory_card_wait_state_w));
map(0x30, 0x30).w(FUNC(nc100_state::nc100_uart_control_w));
map(0x40, 0x40).w("cent_data_out", FUNC(output_latch_device::bus_w));
map(0x50, 0x53).w(FUNC(nc100_state::nc_sound_w));
map(0x60, 0x60).w(FUNC(nc100_state::nc_irq_mask_w));
map(0x70, 0x70).w(FUNC(nc100_state::nc100_poweroff_control_w));
map(0x90, 0x90).rw(FUNC(nc100_state::nc_irq_status_r), FUNC(nc100_state::nc_irq_status_w));
map(0x91, 0x9f).r(FUNC(nc100_state::nc_irq_status_r));
map(0xa0, 0xaf).r(FUNC(nc100_state::nc100_card_battery_status_r));
map(0xb0, 0xb9).r(FUNC(nc100_state::nc_key_data_in_r));
map(0xc0, 0xc1).rw(m_uart, FUNC(i8251_device::read), FUNC(i8251_device::write));
map(0xd0, 0xdf).rw("rtc", FUNC(tc8521_device::read), FUNC(tc8521_device::write));
}
/* 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(0xA3)
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_state::machine_reset();
}
#endif
/**********************************************************************************************************/
/* NC200 hardware */
#ifdef UNUSED_FUNCTION
WRITE8_MEMBER(nc200_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", m_display_memory_start);
}
#endif
WRITE_LINE_MEMBER(nc200_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 nc200_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(nc200_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(nc200_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(nc200_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)
{
LOGDEBUG("nc200 index pulse\n");
// m_irq_status |= (1<<4);
// nc_update_interrupts(Machine);
}
#endif
void nc200_state::machine_reset()
{
/* 512k of rom */
m_membank_rom_mask = 0x1f;
m_membank_internal_ram_mask = 7;
m_membank_card_ram_mask = 0x03f;
nc_state::machine_reset();
m_nc200_uart_interrupt_irq = 0;
/* fdc, serial */
m_irq_latch_mask = /*(1<<5) |*/ (1<<2);
nc200_video_set_backlight(0);
}
void nc_state::machine_start()
{
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(nc200_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(nc200_state::nc200_printer_status_r)
{
uint8_t result = 0;
result |= m_centronics_busy;
return result;
}
WRITE8_MEMBER(nc200_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 */
LOGDEBUG("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(nc200_state::nc200_memory_card_wait_state_w)
{
LOGDEBUG("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
m_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(nc200_state::nc200_poweroff_control_w)
{
LOGDEBUG("nc200 power off: PC: %04x %02x\n", m_maincpu->pc(), data);
nc200_video_set_backlight(((data ^ (1 << 2)) >> 2) & 0x01);
}
void nc200_state::nc200_io(address_map &map)
{
map.global_mask(0xff);
map(0x00, 0x0f).w(FUNC(nc200_state::nc100_display_memory_start_w));
map(0x10, 0x13).rw(FUNC(nc200_state::nc_memory_management_r), FUNC(nc200_state::nc_memory_management_w));
map(0x20, 0x20).w(FUNC(nc200_state::nc200_memory_card_wait_state_w));
map(0x30, 0x30).w(FUNC(nc200_state::nc200_uart_control_w));
map(0x40, 0x40).w("cent_data_out", FUNC(output_latch_device::bus_w));
map(0x50, 0x53).w(FUNC(nc200_state::nc_sound_w));
map(0x60, 0x60).w(FUNC(nc200_state::nc_irq_mask_w));
map(0x70, 0x70).w(FUNC(nc200_state::nc200_poweroff_control_w));
map(0x80, 0x80).r(FUNC(nc200_state::nc200_printer_status_r));
map(0x90, 0x90).rw(FUNC(nc200_state::nc_irq_status_r), FUNC(nc200_state::nc200_irq_status_w));
map(0xa0, 0xa0).r(FUNC(nc200_state::nc200_card_battery_status_r));
map(0xb0, 0xb9).r(FUNC(nc200_state::nc_key_data_in_r));
map(0xc0, 0xc1).rw(m_uart, FUNC(i8251_device::read), FUNC(i8251_device::write));
map(0xd0, 0xd1).rw("mc", FUNC(mc146818_device::read), FUNC(mc146818_device::write));
map(0xe0, 0xe1).m(m_fdc, FUNC(upd765a_device::map));
}
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(0xA3)
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
/**********************************************************************************************************/
MACHINE_CONFIG_START(nc_state::nc_base)
/* basic machine hardware */
MCFG_DEVICE_ADD("maincpu", Z80, /*6000000*/ 4606000) /* Russell Marks says this is more accurate */
MCFG_DEVICE_PROGRAM_MAP(nc_map)
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_PALETTE("palette")
MCFG_PALETTE_ADD("palette", NC_NUM_COLOURS)
MCFG_PALETTE_INIT_OWNER(nc_state, nc)
/* sound hardware */
SPEAKER(config, "mono").front_center();
MCFG_DEVICE_ADD("beep.1", BEEP, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
MCFG_DEVICE_ADD("beep.2", BEEP, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
/* printer */
MCFG_DEVICE_ADD("centronics", CENTRONICS, centronics_devices, "printer")
MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(*this, nc_state, write_centronics_busy))
MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics")
/* uart */
I8251(config, m_uart, 0);
MCFG_DEVICE_ADD("uart_clock", CLOCK, 19200)
MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(*this, nc_state, write_uart_clock))
/* cartridge */
MCFG_GENERIC_CARTSLOT_ADD("cardslot", generic_plain_slot, nullptr)
MCFG_GENERIC_LOAD(nc_state, nc_pcmcia_card)
MCFG_GENERIC_UNLOAD(nc_state, nc_pcmcia_card)
/* internal ram */
RAM(config, m_ram).set_default_size("64K");
NVRAM(config, "nvram", nvram_device::DEFAULT_NONE);
/* dummy timer */
MCFG_TIMER_DRIVER_ADD_PERIODIC("dummy_timer", nc_state, dummy_timer_callback, attotime::from_hz(50))
MACHINE_CONFIG_END
MACHINE_CONFIG_START(nc100_state::nc100)
nc_base(config);
MCFG_DEVICE_MODIFY("maincpu")
MCFG_DEVICE_IO_MAP(nc100_io)
/* video hardware */
MCFG_SCREEN_MODIFY("screen")
MCFG_SCREEN_SIZE(480, 64)
MCFG_SCREEN_VISIBLE_AREA(0, 480-1, 0, 64-1)
MCFG_SCREEN_UPDATE_DRIVER(nc100_state, screen_update_nc100)
/* printer */
MCFG_DEVICE_MODIFY("centronics")
MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(*this, nc100_state, write_nc100_centronics_ack))
/* uart */
m_uart->rxrdy_handler().set(FUNC(nc100_state::nc100_rxrdy_callback));
m_uart->txrdy_handler().set(FUNC(nc100_state::nc100_txrdy_callback));
/* rtc */
tc8521_device &rtc(TC8521(config, "rtc", XTAL(32'768)));
rtc.out_alarm_callback().set(FUNC(nc100_state::nc100_tc8521_alarm_callback));
MACHINE_CONFIG_END
static const floppy_format_type ibmpc_floppy_formats[] = {
FLOPPY_PC_FORMAT,
FLOPPY_MFI_FORMAT,
nullptr
};
static void ibmpc_floppies(device_slot_interface &device)
{
device.option_add("525dd", FLOPPY_525_DD);
}
MACHINE_CONFIG_START(nc200_state::nc200)
nc_base(config);
MCFG_DEVICE_MODIFY("maincpu")
MCFG_DEVICE_IO_MAP(nc200_io)
/* 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_SCREEN_UPDATE_DRIVER(nc200_state, screen_update_nc200)
MCFG_PALETTE_MODIFY("palette")
MCFG_PALETTE_ENTRIES(NC200_NUM_COLOURS)
MCFG_PALETTE_INIT_OWNER(nc200_state, nc)
/* printer */
MCFG_DEVICE_MODIFY("centronics")
MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(*this, nc200_state, write_nc200_centronics_ack))
/* uart */
m_uart->rxrdy_handler().set(FUNC(nc200_state::nc200_rxrdy_callback));
m_uart->txrdy_handler().set(FUNC(nc200_state::nc200_txrdy_callback));
UPD765A(config, m_fdc, true, true);
m_fdc->intrq_wr_callback().set(FUNC(nc200_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_DEVICE_ADD("mc", MC146818, 4.194304_MHz_XTAL)
/* internal ram */
m_ram->set_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(0))
ROM_SYSTEM_BIOS(1, "102dk", "ROM v1.02 Danish")
ROMX_LOAD("nc100_dk_a1.rom", 0x010000, 0x040000, CRC(ebb54923) SHA1(30321011384c5e10204b9a837430c36fc63580d2), ROM_BIOS(1))
ROM_SYSTEM_BIOS(2, "102de", "ROM v1.02 German")
ROMX_LOAD("nc100_de_a1.rom", 0x010000, 0x040000, CRC(bd9ce223) SHA1(2efb26911832bf1456d76d2508e24c0733dc216d), ROM_BIOS(2))
ROM_SYSTEM_BIOS(3, "100", "ROM v1.00")
ROMX_LOAD("nc100.rom", 0x010000, 0x040000, CRC(a699eca3) SHA1(ce217d5a298b959ccc3d7bc5c93b1dba043f1339), ROM_BIOS(3))
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(0)) // French
ROM_SYSTEM_BIOS(1, "b1", "Italian B1")
ROMX_LOAD("nc150_it_b1.rom", 0x010000, 0x080000, CRC(1b2fe2fd) SHA1(67eb6bce0b0d4668401d9c8f5a900dc6bd135c21), ROM_BIOS(1)) // 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 CLASS INIT COMPANY FULLNAME FLAGS
COMP( 1992, nc100, 0, 0, nc100, nc100, nc100_state, init_nc, "Amstrad plc", "NC100", 0 )
COMP( 1992, dw225, nc100, 0, nc100, nc100, nc100_state, init_nc, "NTS Computer Systems", "DreamWriter 225", 0 )
COMP( 1992, nc150, nc100, 0, nc100, nc100, nc100_state, init_nc, "Amstrad plc", "NC150", 0 )
COMP( 1993, nc200, 0, 0, nc200, nc200, nc200_state, init_nc, "Amstrad plc", "NC200", MACHINE_NOT_WORKING ) // boot hangs while checking the MC146818 UIP (update in progress) bit