diff --git a/.gitattributes b/.gitattributes index 69536aaa194..9d1ee588127 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2341,6 +2341,8 @@ src/emu/machine/netlist.c svneol=native#text/plain src/emu/machine/netlist.h svneol=native#text/plain src/emu/machine/nmc9306.c svneol=native#text/plain src/emu/machine/nmc9306.h svneol=native#text/plain +src/emu/machine/nsc810.c svneol=native#text/plain +src/emu/machine/nsc810.h svneol=native#text/plain src/emu/machine/nscsi_bus.c svneol=native#text/plain src/emu/machine/nscsi_bus.h svneol=native#text/plain src/emu/machine/nscsi_cb.c svneol=native#text/plain diff --git a/src/emu/machine/nsc810.c b/src/emu/machine/nsc810.c new file mode 100644 index 00000000000..38b6d34adcc --- /dev/null +++ b/src/emu/machine/nsc810.c @@ -0,0 +1,311 @@ +/* + * nsc810.c + * + * Created on: 10/03/2014 + * + * TODO: + * - 128 byte RAM + * - other timer modes (only mode 1 - event counter - is implemented currently) + * - port bit set/clear + * - and lots of other stuff + */ + +#include "nsc810.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +#define LOG (1) + +const device_type NSC810 = &device_creator; + +nsc810_device::nsc810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NSC810, "National Semiconductor NSC810", tag, owner, clock, "nsc810", __FILE__), + m_portA_r(*this), + m_portB_r(*this), + m_portC_r(*this), + m_portA_w(*this), + m_portB_w(*this), + m_portC_w(*this), + m_timer0_out(*this), + m_timer1_out(*this) +{ +} + +void nsc810_device::device_start() +{ + m_portA_r.resolve_safe(0); + m_portB_r.resolve_safe(0); + m_portC_r.resolve_safe(0); + m_portA_w.resolve_safe(); + m_portB_w.resolve_safe(); + m_portC_w.resolve_safe(); + m_timer0_out.resolve_safe(); + m_timer1_out.resolve_safe(); + + m_portA_w(0); + m_portB_w(0); + m_portC_w(0); + m_timer0_out(0); + m_timer1_out(0); + + m_timer0 = timer_alloc(TIMER0_CLOCK); + m_timer1 = timer_alloc(TIMER1_CLOCK); +} + +void nsc810_device::device_reset() +{ + m_portA_latch = 0; + m_portB_latch = 0; + m_portC_latch = 0; + m_ddrA = 0; + m_ddrB = 0; + m_ddrC = 0; + m_mode = 0; + m_timer0_mode = 0; + m_timer1_mode = 0; + m_timer0_counter = 0; + m_timer1_counter = 0; + m_timer0_running = false; + m_timer1_running = false; + m_ramselect = false; +} + +void nsc810_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER0_CLOCK: + m_timer0_counter--; + if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02) + { + if(m_timer0_counter == 0) + { + m_timer0_out(ASSERT_LINE); + m_timer0_counter = m_timer0_base; + if(LOG) logerror("NSC810 '%s': Timer 0 output set\n",tag()); + } + } + break; + case TIMER1_CLOCK: + m_timer1_counter--; + if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02) + { + if(m_timer1_counter == 0) + { + m_timer1_out(ASSERT_LINE); + m_timer1_counter = m_timer1_base; + if(LOG) logerror("NSC810 '%s': Timer 1 output set\n",tag()); + } + } + break; + } +} + +READ8_MEMBER(nsc810_device::read) +{ + UINT8 res = 0xff; + + if(m_ramselect) + { + // TODO: 128 byte RAM access + } + else + { + // Register access + switch(offset & 0x1f) + { + case REG_PORTA: + res = m_portA_latch &= m_ddrA; + res |= (m_portA_r() & ~m_ddrA); + //if(LOG) logerror("NSC810 '%s': Port A data read %02x\n",tag(),res); + break; + case REG_PORTB: + res = m_portB_latch &= m_ddrB; + res |= (m_portB_r() & ~m_ddrB); + //if(LOG) logerror("NSC810 '%s': Port B data read %02x\n",tag(),res); + break; + case REG_PORTC: + res = m_portC_latch &= m_ddrC; + res |= (m_portC_r() & ~m_ddrC); + //if(LOG) logerror("NSC810 '%s': Port C data read %02x\n",tag(),res); + break; + case REG_MODE_TIMER0: + res = m_timer0_mode; + break; + case REG_MODE_TIMER1: + res = m_timer1_mode; + break; + case REG_TIMER0_LOW: + res = m_timer0_counter & 0xff; + if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02) + { + m_timer0_out(CLEAR_LINE); + if(LOG) logerror("NSC810 '%s': Timer 0 output reset\n",tag()); + } + break; + case REG_TIMER0_HIGH: + res = m_timer0_counter >> 8; + if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02) + { + m_timer0_out(CLEAR_LINE); + if(LOG) logerror("NSC810 '%s': Timer 0 output reset\n",tag()); + } + break; + case REG_TIMER1_LOW: + res = m_timer1_counter & 0xff; + if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02) + { + m_timer1_out(0); + if(LOG) logerror("NSC810 '%s': Timer 1 output reset\n",tag()); + } + break; + case REG_TIMER1_HIGH: + res = m_timer1_counter >> 8; + if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02) + { + m_timer1_out(0); + if(LOG) logerror("NSC810 '%s': Timer 1 output reset\n",tag()); + } + break; + default: + if(LOG) logerror("NSC810 '%s': unused port %02x read\n",tag(),offset); + } + } + return res; +} + +WRITE8_MEMBER(nsc810_device::write) +{ + UINT32 rate; + + if(m_ramselect) + { + // TODO: 128 byte RAM access + } + else + { + // Register access + switch(offset & 0x1f) + { + case REG_PORTA: + m_portA_latch = data & ~m_ddrA; + m_portA_w(data & m_ddrA); + if(LOG) logerror("NSC810 '%s': Port A data write %02x\n",tag(),data); + break; + case REG_PORTB: + m_portB_latch = data & ~m_ddrB; + m_portB_w(data & m_ddrB); + if(LOG) logerror("NSC810 '%s': Port B data write %02x\n",tag(),data); + break; + case REG_PORTC: + m_portC_latch = data & ~m_ddrC; + m_portC_w(data & m_ddrC); + if(LOG) logerror("NSC810 '%s': Port C data write %02x\n",tag(),data); + break; + case REG_DDRA: + m_ddrA = data; + if(LOG) logerror("NSC810 '%s': Port A direction write %02x\n",tag(),data); + break; + case REG_DDRB: + m_ddrB = data; + if(LOG) logerror("NSC810 '%s': Port B direction write %02x\n",tag(),data); + break; + case REG_DDRC: + m_ddrC = data; + if(LOG) logerror("NSC810 '%s': Port C direction write %02x\n",tag(),data); + break; + case REG_MODE_DEF: + if(LOG) logerror("NSC810 '%s': Mode Definition write %02x\n",tag(),data); + break; + case REG_PORTA_BITCLR: + if(LOG) logerror("NSC810 '%s': Port A bit-clear write %02x\n",tag(),data); + break; + case REG_PORTB_BITCLR: + if(LOG) logerror("NSC810 '%s': Port B bit-clear write %02x\n",tag(),data); + break; + case REG_PORTC_BITCLR: + if(LOG) logerror("NSC810 '%s': Port C bit-clear write %02x\n",tag(),data); + break; + case REG_PORTA_BITSET: + if(LOG) logerror("NSC810 '%s': Port A bit-set write %02x\n",tag(),data); + break; + case REG_PORTB_BITSET: + if(LOG) logerror("NSC810 '%s': Port B bit-set write %02x\n",tag(),data); + break; + case REG_PORTC_BITSET: + if(LOG) logerror("NSC810 '%s': Port C bit-set write %02x\n",tag(),data); + break; + case REG_TIMER0_LOW: + m_timer0_base = (m_timer0_base & 0xff00) | data; + m_timer0_counter = (m_timer0_counter & 0xff00) | data; + if(LOG) logerror("NSC810 '%s': Timer 0 low-byte write %02x (base=%04x)\n",tag(),data,m_timer0_base); + break; + case REG_TIMER0_HIGH: + m_timer0_base = (m_timer0_base & 0x00ff) | (data << 8); + m_timer0_counter = (m_timer0_counter & 0x00ff) | (data << 8); + if(LOG) logerror("NSC810 '%s': Timer 0 high-byte write %02x (base=%04x)\n",tag(),data,m_timer0_base); + break; + case REG_TIMER1_LOW: + m_timer1_base = (m_timer1_base & 0xff00) | data; + m_timer1_counter = (m_timer1_counter & 0xff00) | data; + if(LOG) logerror("NSC810 '%s': Timer 1 low-byte write %02x (base=%04x)\n",tag(),data,m_timer1_base); + break; + case REG_TIMER1_HIGH: + m_timer1_base = (m_timer1_base & 0x00ff) | (data << 8); + m_timer1_counter = (m_timer1_counter & 0x00ff) | (data << 8); + if(LOG) logerror("NSC810 '%s': Timer 1 high-byte write %02x (base=%04x)\n",tag(),data,m_timer1_base); + break; + case REG_TIMER0_STOP: + m_timer0_running = false; + m_timer0->reset(); + if(LOG) logerror("NSC810 '%s': Timer 0 Stop write %02x\n",tag(),data); + break; + case REG_TIMER0_START: + if((m_timer0_mode & 0x07) != 0x00 && (m_timer0_mode & 0x07) != 0x07) + { + m_timer0_running = true; + if(m_timer0_mode & 0x10) + rate = m_timer0_clock / 64; + else + if(m_timer0_mode & 0x08) + rate = m_timer0_clock / 2; + else + rate = m_timer0_clock; + m_timer0->adjust(attotime::zero,0,attotime::from_hz(rate)); + } + if(LOG) logerror("NSC810 '%s': Timer 0 Start write %02x\n",tag(),data); + break; + case REG_TIMER1_STOP: + m_timer1_running = false; + m_timer1->reset(); + if(LOG) logerror("NSC810 '%s': Timer 1 Stop write %02x\n",tag(),data); + break; + case REG_TIMER1_START: + if((m_timer1_mode & 0x07) != 0x00 && (m_timer1_mode & 0x07) != 0x07) + { + m_timer1_running = true; + // no /64 prescaler on timer 1 + if(m_timer0_mode & 0x08) + rate = m_timer0_clock / 2; + else + rate = m_timer0_clock; + m_timer1->adjust(attotime::zero,0,attotime::from_hz(rate)); + } + if(LOG) logerror("NSC810 '%s': Timer 1 Start write %02x\n",tag(),data); + break; + case REG_MODE_TIMER0: + m_timer0_mode = data; + if(LOG) logerror("NSC810 '%s': Timer 0 Mode write %02x\n",tag(),data); + break; + case REG_MODE_TIMER1: + m_timer1_mode = data; + if(LOG) logerror("NSC810 '%s': Timer 1 Mode write %02x\n",tag(),data); + break; + default: + logerror("NSC810 '%s': Unused register %02x write %02x\n",tag(),offset,data); + } + } +} + diff --git a/src/emu/machine/nsc810.h b/src/emu/machine/nsc810.h new file mode 100644 index 00000000000..81636057462 --- /dev/null +++ b/src/emu/machine/nsc810.h @@ -0,0 +1,133 @@ +/* + * nsc810.h + * + * Created on: 10/03/2014 + */ + +#ifndef NSC810_H_ +#define NSC810_H_ + +#include "emu.h" + +class nsc810_device : public device_t +{ +public: + // construction/destruction + nsc810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb2_base &set_portA_read_callback(device_t &device, _Object object) { return downcast(device).m_portA_r.set_callback(object); } + template static devcb2_base &set_portB_read_callback(device_t &device, _Object object) { return downcast(device).m_portB_r.set_callback(object); } + template static devcb2_base &set_portC_read_callback(device_t &device, _Object object) { return downcast(device).m_portC_r.set_callback(object); } + template static devcb2_base &set_portA_write_callback(device_t &device, _Object object) { return downcast(device).m_portA_w.set_callback(object); } + template static devcb2_base &set_portB_write_callback(device_t &device, _Object object) { return downcast(device).m_portB_w.set_callback(object); } + template static devcb2_base &set_portC_write_callback(device_t &device, _Object object) { return downcast(device).m_portC_w.set_callback(object); } + template static devcb2_base &set_timer0_callback(device_t &device, _Object object) { return downcast(device).m_timer0_out.set_callback(object); } + template static devcb2_base &set_timer1_callback(device_t &device, _Object object) { return downcast(device).m_timer1_out.set_callback(object); } + + void set_timer0_clock(UINT32 clk) { m_timer0_clock = clk; } + void set_timer1_clock(UINT32 clk) { m_timer1_clock = clk; } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + UINT8 m_portA_latch; + UINT8 m_portB_latch; + UINT8 m_portC_latch; + UINT8 m_ddrA; + UINT8 m_ddrB; + UINT8 m_ddrC; + UINT8 m_mode; + emu_timer* m_timer0; + emu_timer* m_timer1; + UINT8 m_timer0_mode; + UINT8 m_timer1_mode; + UINT16 m_timer0_counter; + UINT16 m_timer1_counter; + UINT16 m_timer0_base; + UINT16 m_timer1_base; + bool m_timer0_running; + bool m_timer1_running; + UINT32 m_timer0_clock; + UINT32 m_timer1_clock; + bool m_ramselect; + + devcb2_read8 m_portA_r; + devcb2_read8 m_portB_r; + devcb2_read8 m_portC_r; + devcb2_write8 m_portA_w; + devcb2_write8 m_portB_w; + devcb2_write8 m_portC_w; + devcb2_write_line m_timer0_out; + devcb2_write_line m_timer1_out; + + static const device_timer_id TIMER0_CLOCK = 0; + static const device_timer_id TIMER1_CLOCK = 1; + + enum + { + REG_PORTA = 0x00, + REG_PORTB, + REG_PORTC, + REG_DDRA = 0x04, + REG_DDRB, + REG_DDRC, + REG_MODE_DEF, + REG_PORTA_BITCLR, + REG_PORTB_BITCLR, + REG_PORTC_BITCLR, + REG_PORTA_BITSET = 0x0c, + REG_PORTB_BITSET, + REG_PORTC_BITSET, + REG_TIMER0_LOW = 0x10, + REG_TIMER0_HIGH, + REG_TIMER1_LOW, + REG_TIMER1_HIGH, + REG_TIMER0_STOP, + REG_TIMER0_START, + REG_TIMER1_STOP, + REG_TIMER1_START, + REG_MODE_TIMER0, + REG_MODE_TIMER1 + }; +}; + +#define MCFG_NSC810_ADD(_tag, _t0clk, _t1clk) \ + MCFG_DEVICE_ADD(_tag, NSC810, 0) \ + downcast(device)->set_timer0_clock(_t0clk); \ + downcast(device)->set_timer1_clock(_t1clk); + +#define MCFG_NSC810_PORTA_READ(_read) \ + devcb = &nsc810_device::set_portA_read_callback(*device, DEVCB2_##_read); + +#define MCFG_NSC810_PORTB_READ(_read) \ + devcb = &nsc810_device::set_portB_read_callback(*device, DEVCB2_##_read); + +#define MCFG_NSC810_PORTC_READ(_read) \ + devcb = &nsc810_device::set_portC_read_callback(*device, DEVCB2_##_read); + +#define MCFG_NSC810_PORTA_WRITE(_write) \ + devcb = &nsc810_device::set_portA_write_callback(*device, DEVCB2_##_write); + +#define MCFG_NSC810_PORTB_WRITE(_write) \ + devcb = &nsc810_device::set_portB_write_callback(*device, DEVCB2_##_write); + +#define MCFG_NSC810_PORTC_WRITE(_write) \ + devcb = &nsc810_device::set_portC_write_callback(*device, DEVCB2_##_write); + +#define MCFG_NSC810_TIMER0_OUT(_write) \ + devcb = &nsc810_device::set_timer0_callback(*device, DEVCB2_##_write); + +#define MCFG_NSC810_TIMER1_OUT(_write) \ + devcb = &nsc810_device::set_timer1_callback(*device, DEVCB2_##_write); + +// device type definition +extern const device_type NSC810; + + +#endif /* NSC810_H_ */ diff --git a/src/mess/drivers/hunter2.c b/src/mess/drivers/hunter2.c index 04081c220a5..86ad4ebaee0 100644 --- a/src/mess/drivers/hunter2.c +++ b/src/mess/drivers/hunter2.c @@ -29,6 +29,7 @@ #include "machine/mm58274c.h" #include "rendlay.h" #include "sound/speaker.h" +#include "machine/nsc810.h" class hunter2_state : public driver_device { @@ -40,6 +41,7 @@ public: { } DECLARE_READ8_MEMBER(port00_r); + DECLARE_READ8_MEMBER(port01_r); DECLARE_WRITE8_MEMBER(port01_w); DECLARE_READ8_MEMBER(port02_r); DECLARE_WRITE8_MEMBER(port60_w); @@ -50,6 +52,7 @@ public: TIMER_DEVICE_CALLBACK_MEMBER(a_timer); DECLARE_PALETTE_INIT(hunter2); DECLARE_DRIVER_INIT(hunter2); + DECLARE_WRITE_LINE_MEMBER(timer0_out); private: UINT8 m_keydata; @@ -70,11 +73,11 @@ ADDRESS_MAP_END static ADDRESS_MAP_START(hunter2_io, AS_IO, 8, hunter2_state) ADDRESS_MAP_UNMAP_HIGH ADDRESS_MAP_GLOBAL_MASK(0xff) - //AM_RANGE(0x00, 0x1f) AM_DEVREADWRITE("nsc810", nsc810_device, read, write) // device not yet emulated - AM_RANGE(0x00, 0x00) AM_READ(port00_r) - AM_RANGE(0x01, 0x01) AM_WRITE(port01_w) - AM_RANGE(0x02, 0x02) AM_READ(port02_r) - AM_RANGE(0x03, 0x1F) AM_WRITENOP + AM_RANGE(0x00, 0x1f) AM_DEVREADWRITE("iotimer", nsc810_device, read, write) // device not yet emulated +// AM_RANGE(0x00, 0x00) AM_READ(port00_r) +// AM_RANGE(0x01, 0x01) AM_WRITE(port01_w) +// AM_RANGE(0x02, 0x02) AM_READ(port02_r) +// AM_RANGE(0x03, 0x1F) AM_WRITENOP AM_RANGE(0x20, 0x20) AM_DEVWRITE("lcdc", hd61830_device, data_w) AM_RANGE(0x21, 0x21) AM_DEVREADWRITE("lcdc", hd61830_device, status_r, control_w) AM_RANGE(0x3e, 0x3e) AM_DEVREAD("lcdc", hd61830_device, data_r) @@ -176,14 +179,21 @@ READ8_MEMBER( hunter2_state::port00_r ) return data; } +READ8_MEMBER( hunter2_state::port01_r ) +{ + // TODO: bit 7 = RS232 DSR line + return 0x00; +} + WRITE8_MEMBER( hunter2_state::port01_w ) { m_keydata = data; + logerror("Key row select %02x\n",data); } READ8_MEMBER( hunter2_state::port02_r ) { - return 0x2c; + return 0x28; } WRITE8_MEMBER( hunter2_state::port60_w ) @@ -305,6 +315,12 @@ TIMER_DEVICE_CALLBACK_MEMBER(hunter2_state::a_timer) m_maincpu->set_input_line(NSC800_RSTA, HOLD_LINE); } +WRITE_LINE_MEMBER(hunter2_state::timer0_out) +{ + if(state == ASSERT_LINE) + m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); +} + static MACHINE_CONFIG_START( hunter2, hunter2_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", NSC800, 4000000) @@ -330,6 +346,14 @@ static MACHINE_CONFIG_START( hunter2, hunter2_state ) /* Devices */ MCFG_MM58274C_ADD("rtc", rtc_intf) //MCFG_TIMER_DRIVER_ADD_PERIODIC("hunter_a", hunter2_state, a_timer, attotime::from_hz(61)) + + MCFG_NSC810_ADD("iotimer",XTAL_4MHz,XTAL_4MHz) + MCFG_NSC810_PORTA_READ(READ8(hunter2_state,port00_r)) + MCFG_NSC810_PORTB_READ(READ8(hunter2_state,port01_r)) + MCFG_NSC810_PORTB_WRITE(WRITE8(hunter2_state,port01_w)) + MCFG_NSC810_PORTC_READ(READ8(hunter2_state,port02_r)) + MCFG_NSC810_TIMER0_OUT(WRITELINE(hunter2_state,timer0_out)) + MCFG_NSC810_TIMER1_OUT(INPUTLINE("maincpu",NSC800_RSTA)) MACHINE_CONFIG_END /* ROM definition */ diff --git a/src/mess/mess.mak b/src/mess/mess.mak index a8709f312be..f745d275857 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -486,6 +486,7 @@ MACHINES += PC_FDC MACHINES += DP8390 MACHINES += MPU401 MACHINES += AT_KEYBC +MACHINES += NSC810 #MACHINES += PROFILE #------------------------------------------------- @@ -2096,6 +2097,7 @@ $(MESSOBJ)/skeleton.a: \ $(MESS_DRIVERS)/hpz80unk.o \ $(MESS_DRIVERS)/ht68k.o \ $(MESS_DRIVERS)/hunter2.o \ + $(EMU_MACHINE)/nsc810.o \ $(MESS_DRIVERS)/ibm6580.o \ $(MESS_DRIVERS)/ie15.o \ $(MESS_DRIVERS)/if800.o \