diff options
author | 2011-03-28 20:15:05 +0000 | |
---|---|---|
committer | 2011-03-28 20:15:05 +0000 | |
commit | 399c6e8c263fa6cac758a20fe7a52349b2281f9b (patch) | |
tree | b00b464f69e3eed88621653419add5b883df0ab0 /src | |
parent | 90306a806ff3071d2ab79ad61893cc87a0242485 (diff) |
Imported some common C++ devices from MESS to emu folder.
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/emu.mak | 215 | ||||
-rw-r--r-- | src/emu/machine/cdp1871.c | 319 | ||||
-rw-r--r-- | src/emu/machine/cdp1871.h | 171 | ||||
-rw-r--r-- | src/emu/machine/e0516.c | 263 | ||||
-rw-r--r-- | src/emu/machine/e0516.h | 114 | ||||
-rw-r--r-- | src/emu/machine/i8155.c | 653 | ||||
-rw-r--r-- | src/emu/machine/i8155.h | 181 | ||||
-rw-r--r-- | src/emu/machine/i8212.c | 180 | ||||
-rw-r--r-- | src/emu/machine/i8212.h | 136 | ||||
-rw-r--r-- | src/emu/machine/i8355.c | 269 | ||||
-rw-r--r-- | src/emu/machine/i8355.h | 150 | ||||
-rw-r--r-- | src/emu/machine/nmc9306.c | 365 | ||||
-rw-r--r-- | src/emu/machine/nmc9306.h | 118 | ||||
-rw-r--r-- | src/emu/machine/z8536.c | 610 | ||||
-rw-r--r-- | src/emu/machine/z8536.h | 182 | ||||
-rw-r--r-- | src/emu/video/crt9007.c | 1017 | ||||
-rw-r--r-- | src/emu/video/crt9007.h | 233 | ||||
-rw-r--r-- | src/emu/video/crt9021.c | 269 | ||||
-rw-r--r-- | src/emu/video/crt9021.h | 144 | ||||
-rw-r--r-- | src/emu/video/crt9212.c | 269 | ||||
-rw-r--r-- | src/emu/video/crt9212.h | 148 | ||||
-rw-r--r-- | src/emu/video/hd61830.c | 600 | ||||
-rw-r--r-- | src/emu/video/hd61830.h | 156 |
23 files changed, 6660 insertions, 102 deletions
diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 8374b094439..539b3314a74 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -133,110 +133,121 @@ EMUDRIVEROBJS = \ $(EMUDRIVERS)/empty.o \ EMUMACHINEOBJS = \ - $(EMUMACHINE)/53c810.o \ - $(EMUMACHINE)/6522via.o \ - $(EMUMACHINE)/6526cia.o \ - $(EMUMACHINE)/6532riot.o \ - $(EMUMACHINE)/6821pia.o \ - $(EMUMACHINE)/6840ptm.o \ - $(EMUMACHINE)/6850acia.o \ - $(EMUMACHINE)/68681.o \ - $(EMUMACHINE)/74123.o \ - $(EMUMACHINE)/74148.o \ - $(EMUMACHINE)/74153.o \ - $(EMUMACHINE)/74181.o \ - $(EMUMACHINE)/7474.o \ - $(EMUMACHINE)/8042kbdc.o \ - $(EMUMACHINE)/8237dma.o \ - $(EMUMACHINE)/8255ppi.o \ - $(EMUMACHINE)/8257dma.o \ - $(EMUMACHINE)/adc083x.o \ - $(EMUMACHINE)/adc1038.o \ - $(EMUMACHINE)/adc1213x.o \ - $(EMUMACHINE)/am53cf96.o \ - $(EMUMACHINE)/at28c16.o \ - $(EMUMACHINE)/cdp1852.o \ - $(EMUMACHINE)/cr589.o \ - $(EMUMACHINE)/ds1302.o \ - $(EMUMACHINE)/ds2401.o \ - $(EMUMACHINE)/ds2404.o \ - $(EMUMACHINE)/eeprom.o \ - $(EMUMACHINE)/er2055.o \ - $(EMUMACHINE)/f3853.o \ - $(EMUMACHINE)/generic.o \ - $(EMUMACHINE)/i2cmem.o \ - $(EMUMACHINE)/i8243.o \ - $(EMUMACHINE)/i8255a.o \ - $(EMUMACHINE)/idectrl.o \ - $(EMUMACHINE)/ins8154.o \ - $(EMUMACHINE)/ins8250.o \ - $(EMUMACHINE)/intelfsh.o \ - $(EMUMACHINE)/k033906.o \ - $(EMUMACHINE)/k056230.o \ - $(EMUMACHINE)/latch8.o \ - $(EMUMACHINE)/ldcore.o \ - $(EMUMACHINE)/ldpr8210.o \ - $(EMUMACHINE)/ldv1000.o \ - $(EMUMACHINE)/ldvp931.o \ - $(EMUMACHINE)/mb14241.o \ - $(EMUMACHINE)/mb3773.o \ - $(EMUMACHINE)/mb87078.o \ - $(EMUMACHINE)/mc146818.o \ - $(EMUMACHINE)/mc68901.o \ - $(EMUMACHINE)/microtch.o \ - $(EMUMACHINE)/msm6242.o \ - $(EMUMACHINE)/nvram.o \ - $(EMUMACHINE)/pc16552d.o \ - $(EMUMACHINE)/pci.o \ - $(EMUMACHINE)/pd4990a.o \ - $(EMUMACHINE)/pic8259.o \ - $(EMUMACHINE)/pit8253.o \ - $(EMUMACHINE)/ram.o \ - $(EMUMACHINE)/roc10937.o \ - $(EMUMACHINE)/rp5h01.o \ - $(EMUMACHINE)/rtc65271.o \ - $(EMUMACHINE)/s3c2400.o \ - $(EMUMACHINE)/s3c2410.o \ - $(EMUMACHINE)/s3c2440.o \ - $(EMUMACHINE)/scsi.o \ - $(EMUMACHINE)/scsicd.o \ - $(EMUMACHINE)/scsidev.o \ - $(EMUMACHINE)/scsihd.o \ - $(EMUMACHINE)/secflash.o \ - $(EMUMACHINE)/smc91c9x.o \ - $(EMUMACHINE)/timekpr.o \ - $(EMUMACHINE)/tmp68301.o \ - $(EMUMACHINE)/tms6100.o \ - $(EMUMACHINE)/upd4701.o \ - $(EMUMACHINE)/wd33c93.o \ - $(EMUMACHINE)/x2212.o \ - $(EMUMACHINE)/x76f041.o \ - $(EMUMACHINE)/x76f100.o \ - $(EMUMACHINE)/z80ctc.o \ - $(EMUMACHINE)/z80dart.o \ - $(EMUMACHINE)/z80dma.o \ - $(EMUMACHINE)/z80pio.o \ - $(EMUMACHINE)/z80sio.o \ - $(EMUMACHINE)/z80sti.o \ + $(EMUMACHINE)/53c810.o \ + $(EMUMACHINE)/6522via.o \ + $(EMUMACHINE)/6526cia.o \ + $(EMUMACHINE)/6532riot.o \ + $(EMUMACHINE)/6821pia.o \ + $(EMUMACHINE)/6840ptm.o \ + $(EMUMACHINE)/6850acia.o \ + $(EMUMACHINE)/68681.o \ + $(EMUMACHINE)/74123.o \ + $(EMUMACHINE)/74148.o \ + $(EMUMACHINE)/74153.o \ + $(EMUMACHINE)/74181.o \ + $(EMUMACHINE)/7474.o \ + $(EMUMACHINE)/8042kbdc.o \ + $(EMUMACHINE)/8237dma.o \ + $(EMUMACHINE)/8255ppi.o \ + $(EMUMACHINE)/8257dma.o \ + $(EMUMACHINE)/adc083x.o \ + $(EMUMACHINE)/adc1038.o \ + $(EMUMACHINE)/adc1213x.o \ + $(EMUMACHINE)/am53cf96.o \ + $(EMUMACHINE)/at28c16.o \ + $(EMUMACHINE)/cdp1852.o \ + $(EMUMACHINE)/cdp1871.o \ + $(EMUMACHINE)/cr589.o \ + $(EMUMACHINE)/ds1302.o \ + $(EMUMACHINE)/ds2401.o \ + $(EMUMACHINE)/ds2404.o \ + $(EMUMACHINE)/e0516.o \ + $(EMUMACHINE)/eeprom.o \ + $(EMUMACHINE)/er2055.o \ + $(EMUMACHINE)/f3853.o \ + $(EMUMACHINE)/generic.o \ + $(EMUMACHINE)/i2cmem.o \ + $(EMUMACHINE)/i8155.o \ + $(EMUMACHINE)/i8212.o \ + $(EMUMACHINE)/i8243.o \ + $(EMUMACHINE)/i8255a.o \ + $(EMUMACHINE)/i8355.o \ + $(EMUMACHINE)/idectrl.o \ + $(EMUMACHINE)/ins8154.o \ + $(EMUMACHINE)/ins8250.o \ + $(EMUMACHINE)/intelfsh.o \ + $(EMUMACHINE)/k033906.o \ + $(EMUMACHINE)/k056230.o \ + $(EMUMACHINE)/latch8.o \ + $(EMUMACHINE)/ldcore.o \ + $(EMUMACHINE)/ldpr8210.o \ + $(EMUMACHINE)/ldv1000.o \ + $(EMUMACHINE)/ldvp931.o \ + $(EMUMACHINE)/mb14241.o \ + $(EMUMACHINE)/mb3773.o \ + $(EMUMACHINE)/mb87078.o \ + $(EMUMACHINE)/mc146818.o \ + $(EMUMACHINE)/mc68901.o \ + $(EMUMACHINE)/microtch.o \ + $(EMUMACHINE)/msm6242.o \ + $(EMUMACHINE)/nmc9306.o \ + $(EMUMACHINE)/nvram.o \ + $(EMUMACHINE)/pc16552d.o \ + $(EMUMACHINE)/pci.o \ + $(EMUMACHINE)/pd4990a.o \ + $(EMUMACHINE)/pic8259.o \ + $(EMUMACHINE)/pit8253.o \ + $(EMUMACHINE)/ram.o \ + $(EMUMACHINE)/roc10937.o \ + $(EMUMACHINE)/rp5h01.o \ + $(EMUMACHINE)/rtc65271.o \ + $(EMUMACHINE)/s3c2400.o \ + $(EMUMACHINE)/s3c2410.o \ + $(EMUMACHINE)/s3c2440.o \ + $(EMUMACHINE)/scsi.o \ + $(EMUMACHINE)/scsicd.o \ + $(EMUMACHINE)/scsidev.o \ + $(EMUMACHINE)/scsihd.o \ + $(EMUMACHINE)/secflash.o \ + $(EMUMACHINE)/smc91c9x.o \ + $(EMUMACHINE)/timekpr.o \ + $(EMUMACHINE)/tmp68301.o \ + $(EMUMACHINE)/tms6100.o \ + $(EMUMACHINE)/upd4701.o \ + $(EMUMACHINE)/wd33c93.o \ + $(EMUMACHINE)/x2212.o \ + $(EMUMACHINE)/x76f041.o \ + $(EMUMACHINE)/x76f100.o \ + $(EMUMACHINE)/z80ctc.o \ + $(EMUMACHINE)/z80dart.o \ + $(EMUMACHINE)/z80dma.o \ + $(EMUMACHINE)/z80pio.o \ + $(EMUMACHINE)/z80sio.o \ + $(EMUMACHINE)/z80sti.o \ + $(EMUMACHINE)/z8536.o \ EMUVIDEOOBJS = \ - $(EMUVIDEO)/generic.o \ - $(EMUVIDEO)/hd63484.o \ - $(EMUVIDEO)/mc6845.o \ - $(EMUVIDEO)/pc_vga.o \ - $(EMUVIDEO)/pc_video.o \ - $(EMUVIDEO)/poly.o \ - $(EMUVIDEO)/resnet.o \ - $(EMUVIDEO)/rgbutil.o \ - $(EMUVIDEO)/s2636.o \ - $(EMUVIDEO)/saa5050.o \ - $(EMUVIDEO)/tlc34076.o \ - $(EMUVIDEO)/tms34061.o \ - $(EMUVIDEO)/tms9927.o \ - $(EMUVIDEO)/tms9928a.o \ - $(EMUVIDEO)/v9938.o \ - $(EMUVIDEO)/vector.o \ - $(EMUVIDEO)/voodoo.o \ + $(EMUVIDEO)/crt9007.o \ + $(EMUVIDEO)/crt9021.o \ + $(EMUVIDEO)/crt9212.o \ + $(EMUVIDEO)/generic.o \ + $(EMUVIDEO)/hd61830.o \ + $(EMUVIDEO)/hd63484.o \ + $(EMUVIDEO)/mc6845.o \ + $(EMUVIDEO)/pc_vga.o \ + $(EMUVIDEO)/pc_video.o \ + $(EMUVIDEO)/poly.o \ + $(EMUVIDEO)/resnet.o \ + $(EMUVIDEO)/rgbutil.o \ + $(EMUVIDEO)/s2636.o \ + $(EMUVIDEO)/saa5050.o \ + $(EMUVIDEO)/tlc34076.o \ + $(EMUVIDEO)/tms34061.o \ + $(EMUVIDEO)/tms9927.o \ + $(EMUVIDEO)/tms9928a.o \ + $(EMUVIDEO)/v9938.o \ + $(EMUVIDEO)/vector.o \ + $(EMUVIDEO)/voodoo.o \ EMUIMAGEDEVOBJS = \ $(EMUIMAGEDEV)/bitbngr.o \ diff --git a/src/emu/machine/cdp1871.c b/src/emu/machine/cdp1871.c new file mode 100644 index 00000000000..1acacdf25da --- /dev/null +++ b/src/emu/machine/cdp1871.c @@ -0,0 +1,319 @@ +/********************************************************************** + + RCA CDP1871 Keyboard Encoder emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "cdp1871.h" +#include "cpu/mcs48/mcs48.h" +#include "machine/devhelpr.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +static const UINT8 CDP1871_KEY_CODES[4][11][8] = +{ + // normal + { + { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 }, + { 0x38, 0x39, 0x3a, 0x3b, 0x2c, 0x2d, 0x2e, 0x2f }, + { 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67 }, + { 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f }, + { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77 }, + { 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f }, + { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f }, + { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, + { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f }, + { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 }, + { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f } + }, + + // alpha + { + { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 }, + { 0x38, 0x39, 0x3a, 0x3b, 0x2c, 0x2d, 0x2e, 0x2f }, + { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 }, + { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }, + { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 }, + { 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f }, + { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f }, + { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, + { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f }, + { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 }, + { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f } + }, + + // shift + { + { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 }, + { 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x3d, 0x3e, 0x3f }, + { 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 }, + { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }, + { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 }, + { 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f }, + { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f }, + { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, + { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f }, + { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 }, + { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f } + }, + + // control + { + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, + { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }, + { 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f }, + { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, + { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f }, + { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 }, + { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f } + } +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CDP1871 = cdp1871_device_config::static_alloc_device_config; + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +GENERIC_DEVICE_CONFIG_SETUP(cdp1871, "RCA CDP1871") + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void cdp1871_device_config::device_config_complete() +{ + // inherit a copy of the static data + const cdp1871_interface *intf = reinterpret_cast<const cdp1871_interface *>(static_config()); + if (intf != NULL) + *static_cast<cdp1871_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&out_da_func, 0, sizeof(out_da_func)); + memset(&out_rpt_func, 0, sizeof(out_rpt_func)); + // m_in_d_func[] + memset(&in_shift_func, 0, sizeof(in_shift_func)); + memset(&in_control_func, 0, sizeof(in_control_func)); + memset(&in_alpha_func, 0, sizeof(in_alpha_func)); + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cdp1871_device - constructor +//------------------------------------------------- + +cdp1871_device::cdp1871_device(running_machine &_machine, const cdp1871_device_config &config) + : device_t(_machine, config), + m_inhibit(false), + m_sense(0), + m_drive(0), + m_next_da(CLEAR_LINE), + m_next_rpt(CLEAR_LINE), + m_config(config) +{ + +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdp1871_device::device_start() +{ + // resolve callbacks + devcb_resolve_write_line(&m_out_da_func, &m_config.out_da_func, this); + devcb_resolve_write_line(&m_out_rpt_func, &m_config.out_rpt_func, this); + devcb_resolve_read8(&m_in_d_func[0], &m_config.in_d1_func, this); + devcb_resolve_read8(&m_in_d_func[1], &m_config.in_d2_func, this); + devcb_resolve_read8(&m_in_d_func[2], &m_config.in_d3_func, this); + devcb_resolve_read8(&m_in_d_func[3], &m_config.in_d4_func, this); + devcb_resolve_read8(&m_in_d_func[4], &m_config.in_d5_func, this); + devcb_resolve_read8(&m_in_d_func[5], &m_config.in_d6_func, this); + devcb_resolve_read8(&m_in_d_func[6], &m_config.in_d7_func, this); + devcb_resolve_read8(&m_in_d_func[7], &m_config.in_d8_func, this); + devcb_resolve_read8(&m_in_d_func[8], &m_config.in_d9_func, this); + devcb_resolve_read8(&m_in_d_func[9], &m_config.in_d10_func, this); + devcb_resolve_read8(&m_in_d_func[10], &m_config.in_d11_func, this); + devcb_resolve_read_line(&m_in_shift_func, &m_config.in_shift_func, this); + devcb_resolve_read_line(&m_in_control_func, &m_config.in_control_func, this); + devcb_resolve_read_line(&m_in_alpha_func, &m_config.in_alpha_func, this); + + // set initial values + change_output_lines(); + + // allocate timers + m_scan_timer = timer_alloc(); + m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); + + // register for state saving + save_item(NAME(m_inhibit)); + save_item(NAME(m_sense)); + save_item(NAME(m_drive)); + save_item(NAME(m_shift)); + save_item(NAME(m_control)); + save_item(NAME(m_da)); + save_item(NAME(m_next_da)); + save_item(NAME(m_rpt)); + save_item(NAME(m_next_rpt)); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void cdp1871_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + change_output_lines(); + clock_scan_counters(); + detect_keypress(); +} + + +//------------------------------------------------- +// change_output_lines - change output lines +//------------------------------------------------- + +void cdp1871_device::change_output_lines() +{ + if (m_next_da != m_da) + { + m_da = m_next_da; + + devcb_call_write_line(&m_out_da_func, m_da); + } + + if (m_next_rpt != m_rpt) + { + m_rpt = m_next_rpt; + + devcb_call_write_line(&m_out_rpt_func, m_rpt); + } +} + + +//------------------------------------------------- +// clock_scan_counters - clock the keyboard +// scan counters +//------------------------------------------------- + +void cdp1871_device::clock_scan_counters() +{ + if (!m_inhibit) + { + m_sense++; + + if (m_sense == 8) + { + m_sense = 0; + m_drive++; + + if (m_drive == 11) + { + m_drive = 0; + } + } + } +} + + +//------------------------------------------------- +// detect_keypress - detect key press +//------------------------------------------------- + +void cdp1871_device::detect_keypress() +{ + UINT8 data = 0; + + data = devcb_call_read8(&m_in_d_func[m_drive], 0); + + if (data == (1 << m_sense)) + { + if (!m_inhibit) + { + m_shift = devcb_call_read_line(&m_in_shift_func); + m_control = devcb_call_read_line(&m_in_control_func); + m_inhibit = true; + m_next_da = ASSERT_LINE; + } + else + { + m_next_rpt = ASSERT_LINE; + } + } + else + { + m_inhibit = false; + m_next_rpt = CLEAR_LINE; + } +} + + +//------------------------------------------------- +// data_r - keyboard data read +//------------------------------------------------- + +READ8_MEMBER( cdp1871_device::data_r ) +{ + int table = 0; + int alpha = devcb_call_read_line(&m_in_alpha_func); + + if (m_control) table = 3; else if (m_shift) table = 2; else if (alpha) table = 1; + + // reset DA on next TPB + m_next_da = CLEAR_LINE; + + return CDP1871_KEY_CODES[table][m_drive][m_sense]; +} + + +//------------------------------------------------- +// da_r - data available +//------------------------------------------------- + +READ_LINE_MEMBER( cdp1871_device::da_r ) +{ + return m_da; +} + + +//------------------------------------------------- +// rpt_r - keyboard repeat +//------------------------------------------------- + +READ_LINE_MEMBER( cdp1871_device::rpt_r ) +{ + return m_rpt; +} diff --git a/src/emu/machine/cdp1871.h b/src/emu/machine/cdp1871.h new file mode 100644 index 00000000000..6d3a7fffc6d --- /dev/null +++ b/src/emu/machine/cdp1871.h @@ -0,0 +1,171 @@ +/********************************************************************** + + RCA CDP1871 Keyboard Encoder emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + D1 1 |* \_/ | 40 Vdd + D2 2 | | 39 SHIFT + D3 3 | | 38 CONTROL + D4 4 | | 37 ALPHA + D5 5 | | 36 DEBOUNCE + D6 6 | | 35 _RTP + D7 7 | | 34 TPB + D8 8 | | 33 _DA + D9 9 | | 32 BUS 7 + D10 10 | CDP1871 | 31 BUS 6 + D11 11 | | 30 BUS 5 + S1 12 | | 29 BUS 4 + S2 13 | | 28 BUS 3 + S3 14 | | 27 BUS 2 + S4 15 | | 26 BUS 1 + S5 16 | | 25 BUS 0 + S6 17 | | 24 CS4 + S7 18 | | 23 CS3 + S8 19 | | 22 CS2 + Vss 20 |_____________| 21 _CS1 + +**********************************************************************/ + +#pragma once + +#ifndef __CDP1871__ +#define __CDP1871__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CDP1871_ADD(_tag, _intrf, _clock) \ + MCFG_DEVICE_ADD(_tag, CDP1871, _clock) \ + MCFG_DEVICE_CONFIG(_intrf) + +#define CDP1871_INTERFACE(name) \ + const cdp1871_interface (name)= + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cdp1871_interface + +struct cdp1871_interface +{ + devcb_read8 in_d1_func; + devcb_read8 in_d2_func; + devcb_read8 in_d3_func; + devcb_read8 in_d4_func; + devcb_read8 in_d5_func; + devcb_read8 in_d6_func; + devcb_read8 in_d7_func; + devcb_read8 in_d8_func; + devcb_read8 in_d9_func; + devcb_read8 in_d10_func; + devcb_read8 in_d11_func; + + devcb_read_line in_shift_func; + devcb_read_line in_control_func; + devcb_read_line in_alpha_func; + + // this gets called for every change of the DA pin (pin 33) + devcb_write_line out_da_func; + + // this gets called for every change of the RPT pin (pin 35) + devcb_write_line out_rpt_func; +}; + + +// ======================> cdp1871_device_config + +class cdp1871_device_config : public device_config, + public cdp1871_interface +{ + friend class cdp1871_device; + + // construction/destruction + cdp1871_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); +}; + + +// ======================> cdp1871_device + +class cdp1871_device : public device_t +{ + friend class cdp1871_device_config; + + // construction/destruction + cdp1871_device(running_machine &_machine, const cdp1871_device_config &_config); + +public: + DECLARE_READ8_MEMBER( data_r ); + + DECLARE_READ_LINE_MEMBER( da_r ); + DECLARE_READ_LINE_MEMBER( rpt_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void change_output_lines(); + void clock_scan_counters(); + void detect_keypress(); + +private: + devcb_resolved_write_line m_out_da_func; + devcb_resolved_write_line m_out_rpt_func; + devcb_resolved_read8 m_in_d_func[11]; + devcb_resolved_read_line m_in_shift_func; + devcb_resolved_read_line m_in_control_func; + devcb_resolved_read_line m_in_alpha_func; + + bool m_inhibit; // scan counter clock inhibit + int m_sense; // sense input scan counter + int m_drive; // modifier inputs + + int m_shift; // latched shift modifier + int m_control; // latched control modifier + + int m_da; // data available flag + int m_next_da; // next value of data available flag + int m_rpt; // repeat flag + int m_next_rpt; // next value of repeat flag + + // timers + emu_timer *m_scan_timer; // keyboard scan timer + + const cdp1871_device_config &m_config; +}; + + +// device type definition +extern const device_type CDP1871; + + + +#endif diff --git a/src/emu/machine/e0516.c b/src/emu/machine/e0516.c new file mode 100644 index 00000000000..05b7df778cd --- /dev/null +++ b/src/emu/machine/e0516.c @@ -0,0 +1,263 @@ +/********************************************************************** + + E05-16 Real Time Clock emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "e0516.h" +#include "machine/devhelpr.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + + +// states +enum +{ + STATE_ADDRESS = 0, + STATE_DATA +}; + + +// registers +enum +{ + SECOND = 0, + MINUTE, + HOUR, + DAY, + MONTH, + DAY_OF_WEEK, + YEAR, + ALL +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type E0516 = e0516_device_config::static_alloc_device_config; + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +GENERIC_DEVICE_CONFIG_SETUP(e0516, "E05-16") + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// e0516_device - constructor +//------------------------------------------------- + +e0516_device::e0516_device(running_machine &_machine, const e0516_device_config &config) + : device_t(_machine, config), + m_config(config) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void e0516_device::device_start() +{ + // allocate timers + m_timer = timer_alloc(); + m_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); + + // state saving + save_item(NAME(m_cs)); + save_item(NAME(m_clk)); + save_item(NAME(m_data_latch)); + save_item(NAME(m_reg_latch)); + save_item(NAME(m_read_write)); + save_item(NAME(m_state)); + save_item(NAME(m_bits)); + save_item(NAME(m_dio)); + save_item(NAME(m_register)); +} + + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void e0516_device::device_reset() +{ +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void e0516_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_register[SECOND]++; + + if (m_register[SECOND] == 60) + { + m_register[SECOND] = 0; + m_register[MINUTE]++; + } + + if (m_register[MINUTE] == 60) + { + m_register[MINUTE] = 0; + m_register[HOUR]++; + } + + if (m_register[HOUR] == 24) + { + m_register[HOUR] = 0; + m_register[DAY]++; + m_register[DAY_OF_WEEK]++; + } + + if (m_register[DAY_OF_WEEK] == 8) + { + m_register[DAY_OF_WEEK] = 1; + } + + if (m_register[DAY] == 32) + { + m_register[DAY] = 1; + m_register[MONTH]++; + } + + if (m_register[MONTH] == 13) + { + m_register[MONTH] = 1; + m_register[YEAR]++; + } +} + + +//------------------------------------------------- +// cs_w - chip select input +//------------------------------------------------- + +WRITE_LINE_MEMBER( e0516_device::cs_w ) +{ + m_cs = state; + + if (m_cs) + { + m_data_latch = 0; + m_reg_latch = 0; + m_bits = 0; + m_state = STATE_ADDRESS; + } +} + + +//------------------------------------------------- +// clk_w - serial clock input +//------------------------------------------------- + +WRITE_LINE_MEMBER( e0516_device::clk_w ) +{ + m_clk = state; + + if (m_cs || m_clk) return; + + m_bits++; + + if (m_state == STATE_ADDRESS) + { + if (LOG) logerror("E05-16 '%s' Command Bit %u\n", tag(), m_dio); + + // command + m_reg_latch |= m_dio << 3; + m_reg_latch >>= 1; + + if (m_bits == 4) + { + m_state = STATE_DATA; + m_bits = 0; + + if (BIT(m_reg_latch, 0)) + { + // load register value to data latch + m_data_latch = m_register[m_reg_latch >> 1]; + } + } + } + else + { + // data + if (BIT(m_reg_latch, 0)) + { + // read + if (LOG) logerror("E05-16 '%s' Data Bit OUT %u\n", tag(), m_dio); + + m_dio = BIT(m_data_latch, 0); + m_data_latch >>= 1; + } + else + { + // write + if (LOG) logerror("E05-16 '%s' Data Bit IN %u\n", tag(), m_dio); + + m_data_latch |= m_dio << 7; + m_data_latch >>= 1; + } + + if (m_bits == 8) + { + m_state = STATE_ADDRESS; + m_bits = 0; + + if (!BIT(m_reg_latch, 0)) + { + // write latched data to register + m_register[m_reg_latch >> 1] = m_data_latch; + } + } + } +} + + +//------------------------------------------------- +// dio_w - serial data input +//------------------------------------------------- + +WRITE_LINE_MEMBER( e0516_device::dio_w ) +{ + m_dio = state; +} + + +//------------------------------------------------- +// do_r - serial data output +//------------------------------------------------- + +READ_LINE_MEMBER( e0516_device::dio_r ) +{ + return m_dio; +} diff --git a/src/emu/machine/e0516.h b/src/emu/machine/e0516.h new file mode 100644 index 00000000000..83c25db1582 --- /dev/null +++ b/src/emu/machine/e0516.h @@ -0,0 +1,114 @@ +/********************************************************************** + + E05-16 Real Time Clock emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + Vdd1 1 |* \_/ | 16 Vdd2 + OSC IN 2 | | 15 Clk + OSC OUT 3 | | 14 XOUT + _STOP 4 | E05-16 | 13 DI/O + _RESET 5 | E050-16 | 12 _SEC + _OUTSEL 6 | | 11 _MIN + _DAY 7 | | 10 _HRS + Vss 8 |_____________| 9 _CS + +**********************************************************************/ + +#pragma once + +#ifndef __E0516__ +#define __E0516__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_E0516_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, E0516, _clock) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> e0516_device_config + +class e0516_device_config : public device_config +{ + friend class e0516_device; + + // construction/destruction + e0516_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: +}; + + +// ======================> e0516_device + +class e0516_device : public device_t +{ + friend class e0516_device_config; + + // construction/destruction + e0516_device(running_machine &_machine, const e0516_device_config &_config); + +public: + DECLARE_WRITE_LINE_MEMBER( cs_w ); + DECLARE_WRITE_LINE_MEMBER( clk_w ); + DECLARE_WRITE_LINE_MEMBER( dio_w ); + DECLARE_READ_LINE_MEMBER( dio_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + int m_cs; // chip select + int m_clk; // clock + int m_data_latch; // data latch + int m_reg_latch; // register latch + int m_read_write; // read/write data + int m_state; // state + int m_bits; // number of bits transferred + int m_dio; // data pin + + UINT8 m_register[8]; // registers + + // timers + emu_timer *m_timer; + + const e0516_device_config &m_config; +}; + + +// device type definition +extern const device_type E0516; + + + +#endif diff --git a/src/emu/machine/i8155.c b/src/emu/machine/i8155.c new file mode 100644 index 00000000000..8b6bcfa9cfd --- /dev/null +++ b/src/emu/machine/i8155.c @@ -0,0 +1,653 @@ +/********************************************************************** + + Intel 8155 - 2048-Bit Static MOS RAM with I/O Ports and Timer emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +/* + + TODO: + + - strobed mode + +*/ + +#include "emu.h" +#include "i8155.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + +enum +{ + REGISTER_COMMAND = 0, + REGISTER_STATUS = 0, + REGISTER_PORT_A, + REGISTER_PORT_B, + REGISTER_PORT_C, + REGISTER_TIMER_LOW, + REGISTER_TIMER_HIGH +}; + +enum +{ + PORT_A = 0, + PORT_B, + PORT_C, + PORT_COUNT +}; + +enum +{ + PORT_MODE_INPUT = 0, + PORT_MODE_OUTPUT, + PORT_MODE_STROBED_PORT_A, // not supported + PORT_MODE_STROBED // not supported +}; + +enum +{ + MEMORY = 0, + IO +}; + +#define COMMAND_PA 0x01 +#define COMMAND_PB 0x02 +#define COMMAND_PC_MASK 0x0c +#define COMMAND_PC_ALT_1 0x00 +#define COMMAND_PC_ALT_2 0x0c +#define COMMAND_PC_ALT_3 0x04 // not supported +#define COMMAND_PC_ALT_4 0x08 // not supported +#define COMMAND_IEA 0x10 // not supported +#define COMMAND_IEB 0x20 // not supported +#define COMMAND_TM_MASK 0xc0 +#define COMMAND_TM_NOP 0x00 +#define COMMAND_TM_STOP 0x40 +#define COMMAND_TM_STOP_AFTER_TC 0x80 +#define COMMAND_TM_START 0xc0 + +#define STATUS_INTR_A 0x01 // not supported +#define STATUS_A_BF 0x02 // not supported +#define STATUS_INTE_A 0x04 // not supported +#define STATUS_INTR_B 0x08 // not supported +#define STATUS_B_BF 0x10 // not supported +#define STATUS_INTE_B 0x20 // not supported +#define STATUS_TIMER 0x40 + +#define TIMER_MODE_MASK 0xc0 +#define TIMER_MODE_LOW 0x00 +#define TIMER_MODE_SQUARE_WAVE 0x40 +#define TIMER_MODE_SINGLE_PULSE 0x80 +#define TIMER_MODE_AUTOMATIC_RELOAD 0xc0 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type I8155 = i8155_device_config::static_alloc_device_config; + + +// default address map +static ADDRESS_MAP_START( i8155, AS_0, 8 ) + AM_RANGE(0x00, 0xff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// i8155_device_config - constructor +//------------------------------------------------- + +i8155_device_config::i8155_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) + : device_config(mconfig, static_alloc_device_config, "Intel 8155", tag, owner, clock), + device_config_memory_interface(mconfig, *this), + m_space_config("ram", ENDIANNESS_LITTLE, 8, 8, 0, NULL, *ADDRESS_MAP_NAME(i8155)) +{ +} + + +//------------------------------------------------- +// static_alloc_device_config - allocate a new +// configuration object +//------------------------------------------------- + +device_config *i8155_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) +{ + return global_alloc(i8155_device_config(mconfig, tag, owner, clock)); +} + + +//------------------------------------------------- +// alloc_device - allocate a new device object +//------------------------------------------------- + +device_t *i8155_device_config::alloc_device(running_machine &machine) const +{ + return auto_alloc(&machine, i8155_device(machine, *this)); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *i8155_device_config::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void i8155_device_config::device_config_complete() +{ + // inherit a copy of the static data + const i8155_interface *intf = reinterpret_cast<const i8155_interface *>(static_config()); + if (intf != NULL) + *static_cast<i8155_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&in_pa_func, 0, sizeof(in_pa_func)); + memset(&out_pa_func, 0, sizeof(out_pa_func)); + memset(&in_pb_func, 0, sizeof(in_pb_func)); + memset(&out_pb_func, 0, sizeof(out_pb_func)); + memset(&in_pc_func, 0, sizeof(in_pc_func)); + memset(&out_pc_func, 0, sizeof(out_pc_func)); + memset(&out_to_func, 0, sizeof(out_to_func)); + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +inline UINT8 i8155_device::get_timer_mode() +{ + return (m_count_length >> 8) & TIMER_MODE_MASK; +} + +inline void i8155_device::timer_output() +{ + devcb_call_write_line(&m_out_to_func, m_to); + + if (LOG) logerror("8155 '%s' Timer Output: %u\n", tag(), m_to); +} + +inline void i8155_device::pulse_timer_output() +{ + m_to = 0; timer_output(); + m_to = 1; timer_output(); +} + +inline int i8155_device::get_port_mode(int port) +{ + int mode = -1; + + switch (port) + { + case PORT_A: + mode = (m_command & COMMAND_PA) ? PORT_MODE_OUTPUT : PORT_MODE_INPUT; + break; + + case PORT_B: + mode = (m_command & COMMAND_PB) ? PORT_MODE_OUTPUT : PORT_MODE_INPUT; + break; + + case PORT_C: + switch (m_command & COMMAND_PC_MASK) + { + case COMMAND_PC_ALT_1: mode = PORT_MODE_INPUT; break; + case COMMAND_PC_ALT_2: mode = PORT_MODE_OUTPUT; break; + case COMMAND_PC_ALT_3: mode = PORT_MODE_STROBED_PORT_A; break; + case COMMAND_PC_ALT_4: mode = PORT_MODE_STROBED; break; + } + break; + } + + return mode; +} + +inline UINT8 i8155_device::read_port(int port) +{ + UINT8 data = 0; + + switch (port) + { + case PORT_A: + case PORT_B: + switch (get_port_mode(port)) + { + case PORT_MODE_INPUT: + data = devcb_call_read8(&m_in_port_func[port], 0); + break; + + case PORT_MODE_OUTPUT: + data = m_output[port]; + break; + } + break; + + case PORT_C: + switch (get_port_mode(PORT_C)) + { + case PORT_MODE_INPUT: + data = devcb_call_read8(&m_in_port_func[port], 0) & 0x3f; + break; + + case PORT_MODE_OUTPUT: + data = m_output[port] & 0x3f; + break; + + default: + logerror("8155 '%s' Unsupported Port C mode!\n", tag()); + } + break; + } + + return data; +} + +inline void i8155_device::write_port(int port, UINT8 data) +{ + switch (get_port_mode(port)) + { + case PORT_MODE_OUTPUT: + m_output[port] = data; + devcb_call_write8(&m_out_port_func[port], 0, m_output[port]); + break; + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8155_device - constructor +//------------------------------------------------- + +i8155_device::i8155_device(running_machine &_machine, const i8155_device_config &config) + : device_t(_machine, config), + device_memory_interface(_machine, config, *this), + m_config(config) +{ + +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8155_device::device_start() +{ + // resolve callbacks + devcb_resolve_read8(&m_in_port_func[0], &m_config.in_pa_func, this); + devcb_resolve_read8(&m_in_port_func[1], &m_config.in_pb_func, this); + devcb_resolve_read8(&m_in_port_func[2], &m_config.in_pc_func, this); + devcb_resolve_write8(&m_out_port_func[0], &m_config.out_pa_func, this); + devcb_resolve_write8(&m_out_port_func[1], &m_config.out_pb_func, this); + devcb_resolve_write8(&m_out_port_func[2], &m_config.out_pc_func, this); + devcb_resolve_write_line(&m_out_to_func, &m_config.out_to_func, this); + + // allocate timers + m_timer = timer_alloc(); + + // register for state saving + save_item(NAME(m_io_m)); + save_item(NAME(m_ad)); + save_item(NAME(m_command)); + save_item(NAME(m_status)); + save_item(NAME(m_output)); + save_item(NAME(m_count_length)); + save_item(NAME(m_counter)); + save_item(NAME(m_to)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8155_device::device_reset() +{ + // clear output registers + m_output[PORT_A] = 0; + m_output[PORT_B] = 0; + m_output[PORT_C] = 0; + + // set ports to input mode + register_w(REGISTER_COMMAND, m_command & ~(COMMAND_PA | COMMAND_PB | COMMAND_PC_MASK)); + + // clear timer flag + m_status &= ~STATUS_TIMER; + + // stop counting + m_timer->enable(0); + + // clear timer output + m_to = 1; + timer_output(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void i8155_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // count down + m_counter--; + + if (get_timer_mode() == TIMER_MODE_LOW) + { + // pulse on every count + pulse_timer_output(); + } + + if (m_counter == 0) + { + if (LOG) logerror("8155 '%s' Timer Count Reached\n", tag()); + + switch (m_command & COMMAND_TM_MASK) + { + case COMMAND_TM_STOP_AFTER_TC: + // stop timer + m_timer->enable(0); + + if (LOG) logerror("8155 '%s' Timer Stopped\n", tag()); + break; + } + + switch (get_timer_mode()) + { + case TIMER_MODE_SQUARE_WAVE: + // toggle timer output + m_to = !m_to; + timer_output(); + break; + + case TIMER_MODE_SINGLE_PULSE: + // single pulse upon TC being reached + pulse_timer_output(); + + // clear timer mode setting + m_command &= ~COMMAND_TM_MASK; + break; + + case TIMER_MODE_AUTOMATIC_RELOAD: + // automatic reload, i.e. single pulse every time TC is reached + pulse_timer_output(); + break; + } + + // set timer flag + m_status |= STATUS_TIMER; + + // reload timer counter + m_counter = m_count_length & 0x3fff; + } +} + + +//------------------------------------------------- +// io_r - register read +//------------------------------------------------- + +READ8_MEMBER( i8155_device::io_r ) +{ + UINT8 data = 0; + + switch (offset & 0x03) + { + case REGISTER_STATUS: + data = m_status; + + // clear timer flag + m_status &= ~STATUS_TIMER; + break; + + case REGISTER_PORT_A: + data = read_port(PORT_A); + break; + + case REGISTER_PORT_B: + data = read_port(PORT_B); + break; + + case REGISTER_PORT_C: + data = read_port(PORT_C); + break; + } + + return data; +} + + +//------------------------------------------------- +// register_w - register write +//------------------------------------------------- + +void i8155_device::register_w(int offset, UINT8 data) +{ + switch (offset & 0x07) + { + case REGISTER_COMMAND: + m_command = data; + + if (LOG) logerror("8155 '%s' Port A Mode: %s\n", tag(), (data & COMMAND_PA) ? "output" : "input"); + if (LOG) logerror("8155 '%s' Port B Mode: %s\n", tag(), (data & COMMAND_PB) ? "output" : "input"); + + if (LOG) logerror("8155 '%s' Port A Interrupt: %s\n", tag(), (data & COMMAND_IEA) ? "enabled" : "disabled"); + if (LOG) logerror("8155 '%s' Port B Interrupt: %s\n", tag(), (data & COMMAND_IEB) ? "enabled" : "disabled"); + + switch (data & COMMAND_PC_MASK) + { + case COMMAND_PC_ALT_1: + if (LOG) logerror("8155 '%s' Port C Mode: Alt 1\n", tag()); + break; + + case COMMAND_PC_ALT_2: + if (LOG) logerror("8155 '%s' Port C Mode: Alt 2\n", tag()); + break; + + case COMMAND_PC_ALT_3: + if (LOG) logerror("8155 '%s' Port C Mode: Alt 3\n", tag()); + break; + + case COMMAND_PC_ALT_4: + if (LOG) logerror("8155 '%s' Port C Mode: Alt 4\n", tag()); + break; + } + + switch (data & COMMAND_TM_MASK) + { + case COMMAND_TM_NOP: + // do not affect counter operation + break; + + case COMMAND_TM_STOP: + // NOP if timer has not started, stop counting if the timer is running + if (LOG) logerror("8155 '%s' Timer Command: Stop\n", tag()); + m_timer->enable(0); + break; + + case COMMAND_TM_STOP_AFTER_TC: + // stop immediately after present TC is reached (NOP if timer has not started) + if (LOG) logerror("8155 '%s' Timer Command: Stop after TC\n", tag()); + break; + + case COMMAND_TM_START: + if (LOG) logerror("8155 '%s' Timer Command: Start\n", tag()); + + if (m_timer->enabled()) + { + // if timer is running, start the new mode and CNT length immediately after present TC is reached + } + else + { + // load mode and CNT length and start immediately after loading (if timer is not running) + m_counter = m_count_length; + m_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); + } + break; + } + break; + + case REGISTER_PORT_A: + write_port(PORT_A, data); + break; + + case REGISTER_PORT_B: + write_port(PORT_B, data); + break; + + case REGISTER_PORT_C: + write_port(PORT_C, data); + break; + + case REGISTER_TIMER_LOW: + m_count_length = (m_count_length & 0xff00) | data; + if (LOG) logerror("8155 '%s' Count Length Low: %04x\n", tag(), m_count_length); + break; + + case REGISTER_TIMER_HIGH: + m_count_length = (data << 8) | (m_count_length & 0xff); + if (LOG) logerror("8155 '%s' Count Length High: %04x\n", tag(), m_count_length); + + switch (data & TIMER_MODE_MASK) + { + case TIMER_MODE_LOW: + // puts out LOW during second half of count + if (LOG) logerror("8155 '%s' Timer Mode: LOW\n", tag()); + break; + + case TIMER_MODE_SQUARE_WAVE: + // square wave, i.e. the period of the square wave equals the count length programmed with automatic reload at terminal count + if (LOG) logerror("8155 '%s' Timer Mode: Square wave\n", tag()); + break; + + case TIMER_MODE_SINGLE_PULSE: + // single pulse upon TC being reached + if (LOG) logerror("8155 '%s' Timer Mode: Single pulse\n", tag()); + break; + + case TIMER_MODE_AUTOMATIC_RELOAD: + // automatic reload, i.e. single pulse every time TC is reached + if (LOG) logerror("8155 '%s' Timer Mode: Automatic reload\n", tag()); + break; + } + break; + } +} + +//------------------------------------------------- +// io_w - register write +//------------------------------------------------- + +WRITE8_MEMBER( i8155_device::io_w ) +{ + register_w(offset, data); +} + + +//------------------------------------------------- +// memory_r - internal RAM read +//------------------------------------------------- + +READ8_MEMBER( i8155_device::memory_r ) +{ + return this->space()->read_byte(offset); +} + + +//------------------------------------------------- +// memory_w - internal RAM write +//------------------------------------------------- + +WRITE8_MEMBER( i8155_device::memory_w ) +{ + this->space()->write_byte(offset, data); +} + + +//------------------------------------------------- +// ale_w - address latch write +//------------------------------------------------- + +WRITE8_MEMBER( i8155_device::ale_w ) +{ + // I/O / memory select + m_io_m = BIT(offset, 0); + + // address + m_ad = data; +} + + +//------------------------------------------------- +// read - memory or I/O read +//------------------------------------------------- + +READ8_MEMBER( i8155_device::read ) +{ + UINT8 data = 0; + + switch (m_io_m) + { + case MEMORY: + data = memory_r(space, m_ad); + break; + + case IO: + data = io_r(space, m_ad); + break; + } + + return data; +} + + +//------------------------------------------------- +// write - memory or I/O write +//------------------------------------------------- + +WRITE8_MEMBER( i8155_device::write ) +{ + switch (m_io_m) + { + case MEMORY: + memory_w(space, m_ad, data); + break; + + case IO: + io_w(space, m_ad, data); + break; + } +} diff --git a/src/emu/machine/i8155.h b/src/emu/machine/i8155.h new file mode 100644 index 00000000000..282791da933 --- /dev/null +++ b/src/emu/machine/i8155.h @@ -0,0 +1,181 @@ +/********************************************************************** + + Intel 8155 - 2048-Bit Static MOS RAM with I/O Ports and Timer emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + PC3 1 |* \_/ | 40 Vcc + PC4 2 | | 39 PC2 + TIMER IN 3 | | 38 PC1 + RESET 4 | | 37 PC0 + PC5 5 | | 36 PB7 + _TIMER OUT 6 | | 35 PB6 + IO/_M 7 | | 34 PB5 + CE or _CE 8 | | 33 PB4 + _RD 9 | | 32 PB3 + _WR 10 | 8155 | 31 PB2 + ALE 11 | 8156 | 30 PB1 + AD0 12 | | 29 PB0 + AD1 13 | | 28 PA7 + AD2 14 | | 27 PA6 + AD3 15 | | 26 PA5 + AD4 16 | | 25 PA4 + AD5 17 | | 24 PA3 + AD6 18 | | 23 PA2 + AD7 19 | | 22 PA1 + Vss 20 |_____________| 21 PA0 + +**********************************************************************/ + +#pragma once + +#ifndef __I8155__ +#define __I8155__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I8155_ADD(_tag, _clock, _config) \ + MCFG_DEVICE_ADD((_tag), I8155, _clock) \ + MCFG_DEVICE_CONFIG(_config) + +#define I8155_INTERFACE(name) \ + const i8155_interface (name) = + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> i8155_interface + +struct i8155_interface +{ + devcb_read8 in_pa_func; + devcb_write8 out_pa_func; + + devcb_read8 in_pb_func; + devcb_write8 out_pb_func; + + devcb_read8 in_pc_func; + devcb_write8 out_pc_func; + + // this gets called for each change of the TIMER OUT pin (pin 6) + devcb_write_line out_to_func; +}; + + + +// ======================> i8155_device_config + +class i8155_device_config : public device_config, + public device_config_memory_interface, + public i8155_interface +{ + friend class i8155_device; + + // construction/destruction + i8155_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); + + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // address space configurations + const address_space_config m_space_config; +}; + + + +// ======================> i8155_device + +class i8155_device : public device_t, + public device_memory_interface +{ + friend class i8155_device_config; + + // construction/destruction + i8155_device(running_machine &_machine, const i8155_device_config &_config); + +public: + DECLARE_READ8_MEMBER( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + DECLARE_READ8_MEMBER( memory_r ); + DECLARE_WRITE8_MEMBER( memory_w ); + + DECLARE_WRITE8_MEMBER( ale_w ); + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + inline UINT8 get_timer_mode(); + inline void timer_output(); + inline void pulse_timer_output(); + inline int get_port_mode(int port); + inline UINT8 read_port(int port); + inline void write_port(int port, UINT8 data); + + void register_w(int offset, UINT8 data); + +private: + devcb_resolved_read8 m_in_port_func[3]; + devcb_resolved_write8 m_out_port_func[3]; + devcb_resolved_write_line m_out_to_func; + + // CPU interface + int m_io_m; // I/O or memory select + UINT8 m_ad; // address + + // registers + UINT8 m_command; // command register + UINT8 m_status; // status register + UINT8 m_output[3]; // output latches + + // counter + UINT16 m_count_length; // count length register + UINT16 m_counter; // counter register + int m_to; // timer output + + // timers + emu_timer *m_timer; // counter timer + + const i8155_device_config &m_config; +}; + + +// device type definition +extern const device_type I8155; + + + +#endif diff --git a/src/emu/machine/i8212.c b/src/emu/machine/i8212.c new file mode 100644 index 00000000000..af98db9947e --- /dev/null +++ b/src/emu/machine/i8212.c @@ -0,0 +1,180 @@ +/********************************************************************** + + Intel 8212 8-Bit Input/Output Port emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "machine/devhelpr.h" +#include "i8212.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type I8212 = i8212_device_config::static_alloc_device_config; + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +GENERIC_DEVICE_CONFIG_SETUP(i8212, "Intel 8212") + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void i8212_device_config::device_config_complete() +{ + // inherit a copy of the static data + const i8212_interface *intf = reinterpret_cast<const i8212_interface *>(static_config()); + if (intf != NULL) + *static_cast<i8212_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&out_int_func, 0, sizeof(out_int_func)); + memset(&in_di_func, 0, sizeof(in_di_func)); + memset(&out_do_func, 0, sizeof(out_do_func)); + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8212_device - constructor +//------------------------------------------------- + +i8212_device::i8212_device(running_machine &_machine, const i8212_device_config &config) + : device_t(_machine, config), + m_md(I8212_MODE_INPUT), + m_stb(0), + m_config(config) +{ + +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8212_device::device_start() +{ + // resolve callbacks + devcb_resolve_write_line(&m_out_int_func, &m_config.out_int_func, this); + devcb_resolve_read8(&m_in_di_func, &m_config.in_di_func, this); + devcb_resolve_write8(&m_out_do_func, &m_config.out_do_func, this); + + // register for state saving + save_item(NAME(m_md)); + save_item(NAME(m_stb)); + save_item(NAME(m_data)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8212_device::device_reset() +{ + m_data = 0; + + if (m_md == I8212_MODE_OUTPUT) + { + // output data + devcb_call_write8(&m_out_do_func, 0, m_data); + } +} + + +//------------------------------------------------- +// data_r - data latch read +//------------------------------------------------- + +READ8_MEMBER( i8212_device::data_r ) +{ + // clear interrupt line + devcb_call_write_line(&m_out_int_func, CLEAR_LINE); + + if (LOG) logerror("I8212 '%s' INT: %u\n", tag(), CLEAR_LINE); + + return m_data; +} + + +//------------------------------------------------- +// data_w - data latch write +//------------------------------------------------- + +WRITE8_MEMBER( i8212_device::data_w ) +{ + // latch data + m_data = data; + + // output data + devcb_call_write8(&m_out_do_func, 0, m_data); +} + + +//------------------------------------------------- +// md_w - mode write +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8212_device::md_w ) +{ + if (LOG) logerror("I8212 '%s' Mode: %s\n", tag(), state ? "output" : "input"); + + m_md = state; +} + + +//------------------------------------------------- +// stb_w - data strobe write +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8212_device::stb_w ) +{ + if (LOG) logerror("I8212 '%s' STB: %u\n", tag(), state); + + if (m_md == I8212_MODE_INPUT) + { + if (m_stb && !state) + { + // input data + m_data = devcb_call_read8(&m_in_di_func, 0); + + // assert interrupt line + devcb_call_write_line(&m_out_int_func, ASSERT_LINE); + + if (LOG) logerror("I8212 '%s' INT: %u\n", tag(), ASSERT_LINE); + } + } + + m_stb = state; +} diff --git a/src/emu/machine/i8212.h b/src/emu/machine/i8212.h new file mode 100644 index 00000000000..6390a4d6f7d --- /dev/null +++ b/src/emu/machine/i8212.h @@ -0,0 +1,136 @@ +/********************************************************************** + + Intel 8212 8-Bit Input/Output Port emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + _DS1 1 |* \_/ | 24 Vcc + MD 2 | | 23 _INT + DI1 3 | | 22 DI8 + DO1 4 | | 21 DO8 + DI2 5 | | 20 DI7 + DO2 6 | 8212 | 19 DO7 + DI3 7 | | 18 DI6 + DO3 8 | | 17 DO6 + DI4 9 | | 16 DI5 + DO4 10 | | 15 DO5 + STB 11 | | 14 _CLR + GND 12 |_____________| 13 DS2 + +**********************************************************************/ + +#pragma once + +#ifndef __I8212__ +#define __I8212__ + +#include "emu.h" + + + +///************************************************************************* +// MACROS / CONSTANTS +///************************************************************************* + +enum +{ + I8212_MODE_INPUT = 0, + I8212_MODE_OUTPUT +}; + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_I8212_ADD(_tag, _config) \ + MCFG_DEVICE_ADD((_tag), I8212, 0) \ + MCFG_DEVICE_CONFIG(_config) + +#define I8212_INTERFACE(name) \ + const i8212_interface (name) = + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> i8212_interface + +struct i8212_interface +{ + devcb_write_line out_int_func; + + devcb_read8 in_di_func; + devcb_write8 out_do_func; +}; + + + +// ======================> i8212_device_config + +class i8212_device_config : public device_config, + public i8212_interface +{ + friend class i8212_device; + + // construction/destruction + i8212_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); +}; + + + +// ======================> i8212_device + +class i8212_device : public device_t +{ + friend class i8212_device_config; + + // construction/destruction + i8212_device(running_machine &_machine, const i8212_device_config &_config); + +public: + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + + DECLARE_WRITE_LINE_MEMBER( md_w ); + DECLARE_WRITE_LINE_MEMBER( stb_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_resolved_write_line m_out_int_func; + devcb_resolved_read8 m_in_di_func; + devcb_resolved_write8 m_out_do_func; + + int m_md; // mode + int m_stb; // strobe + UINT8 m_data; // data latch + + const i8212_device_config &m_config; +}; + + +// device type definition +extern const device_type I8212; + + + +#endif diff --git a/src/emu/machine/i8355.c b/src/emu/machine/i8355.c new file mode 100644 index 00000000000..6c305793710 --- /dev/null +++ b/src/emu/machine/i8355.c @@ -0,0 +1,269 @@ +/********************************************************************** + + Intel 8355 - 16,384-Bit ROM with I/O emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "i8355.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +enum +{ + REGISTER_PORT_A = 0, + REGISTER_PORT_B, + REGISTER_PORT_A_DDR, + REGISTER_PORT_B_DDR +}; + +enum +{ + PORT_A = 0, + PORT_B, + PORT_COUNT +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type I8355 = i8355_device_config::static_alloc_device_config; + + +// default address map +static ADDRESS_MAP_START( i8355, AS_0, 8 ) + AM_RANGE(0x000, 0x7ff) AM_ROM +ADDRESS_MAP_END + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// i8355_device_config - constructor +//------------------------------------------------- + +i8355_device_config::i8355_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) + : device_config(mconfig, static_alloc_device_config, "Intel 8355", tag, owner, clock), + device_config_memory_interface(mconfig, *this), + m_space_config("ram", ENDIANNESS_LITTLE, 8, 11, 0, NULL, *ADDRESS_MAP_NAME(i8355)) +{ +} + + +//------------------------------------------------- +// static_alloc_device_config - allocate a new +// configuration object +//------------------------------------------------- + +device_config *i8355_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) +{ + return global_alloc(i8355_device_config(mconfig, tag, owner, clock)); +} + + +//------------------------------------------------- +// alloc_device - allocate a new device object +//------------------------------------------------- + +device_t *i8355_device_config::alloc_device(running_machine &machine) const +{ + return auto_alloc(&machine, i8355_device(machine, *this)); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *i8355_device_config::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void i8355_device_config::device_config_complete() +{ + // inherit a copy of the static data + const i8355_interface *intf = reinterpret_cast<const i8355_interface *>(static_config()); + if (intf != NULL) + *static_cast<i8355_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&in_pa_func, 0, sizeof(in_pa_func)); + memset(&out_pa_func, 0, sizeof(out_pa_func)); + memset(&in_pb_func, 0, sizeof(in_pb_func)); + memset(&out_pb_func, 0, sizeof(out_pb_func)); + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_port - read from input port +//------------------------------------------------- + +inline UINT8 i8355_device::read_port(int port) +{ + UINT8 data = m_output[port] & m_ddr[port]; + + if (m_ddr[port] != 0xff) + { + data |= devcb_call_read8(&m_in_port_func[port], 0) & ~m_ddr[port]; + } + + return data; +} + + +//------------------------------------------------- +// write_port - write to output port +//------------------------------------------------- + +inline void i8355_device::write_port(int port, UINT8 data) +{ + m_output[port] = data; + + devcb_call_write8(&m_out_port_func[port], 0, m_output[port] & m_ddr[port]); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8355_device - constructor +//------------------------------------------------- + +i8355_device::i8355_device(running_machine &_machine, const i8355_device_config &config) + : device_t(_machine, config), + device_memory_interface(_machine, config, *this), + m_config(config) +{ + +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8355_device::device_start() +{ + // resolve callbacks + devcb_resolve_read8(&m_in_port_func[0], &m_config.in_pa_func, this); + devcb_resolve_read8(&m_in_port_func[1], &m_config.in_pb_func, this); + devcb_resolve_write8(&m_out_port_func[0], &m_config.out_pa_func, this); + devcb_resolve_write8(&m_out_port_func[1], &m_config.out_pb_func, this); + + // register for state saving + save_item(NAME(m_output)); + save_item(NAME(m_ddr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8355_device::device_reset() +{ + // set ports to input mode + m_ddr[PORT_A] = 0; + m_ddr[PORT_B] = 0; +} + + +//------------------------------------------------- +// io_r - register read +//------------------------------------------------- + +READ8_MEMBER( i8355_device::io_r ) +{ + int port = offset & 0x01; + + UINT8 data = 0; + + switch (offset & 0x03) + { + case REGISTER_PORT_A: + case REGISTER_PORT_B: + data = read_port(port); + break; + + case REGISTER_PORT_A_DDR: + case REGISTER_PORT_B_DDR: + // write only + break; + } + + return data; +} + + +//------------------------------------------------- +// io_w - register write +//------------------------------------------------- + +WRITE8_MEMBER( i8355_device::io_w ) +{ + int port = offset & 0x01; + + switch (offset & 0x03) + { + case REGISTER_PORT_A: + case REGISTER_PORT_B: + if (LOG) logerror("I8355 '%s' Port %c Write %02x\n", tag(), 'A' + port, data); + + write_port(port, data); + break; + + case REGISTER_PORT_A_DDR: + case REGISTER_PORT_B_DDR: + if (LOG) logerror("I8355 '%s' Port %c DDR: %02x\n", tag(), 'A' + port, data); + + m_ddr[port] = data; + write_port(port, data); + break; + } +} + + +//------------------------------------------------- +// memory_r - internal ROM read +//------------------------------------------------- + +READ8_MEMBER( i8355_device::memory_r ) +{ + return this->space()->read_byte(offset); +} diff --git a/src/emu/machine/i8355.h b/src/emu/machine/i8355.h new file mode 100644 index 00000000000..a332d4fa264 --- /dev/null +++ b/src/emu/machine/i8355.h @@ -0,0 +1,150 @@ +/********************************************************************** + + Intel 8355 - 16,384-Bit ROM with I/O emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + _CE1 1 |* \_/ | 40 Vcc + CE2 2 | | 39 PB7 + CLK 3 | | 38 PB6 + RESET 4 | | 37 PB5 + N.C. 5 | | 36 PB4 + READY 6 | | 35 PB3 + IO/_M 7 | | 34 PB2 + _IOR 8 | | 33 PB1 + _RD 9 | | 32 PB0 + _IOW 10 | 8355 | 31 PA7 + ALE 11 | 8355-2 | 30 PA6 + AD0 12 | | 29 PA5 + AD1 13 | | 28 PA4 + AD2 14 | | 27 PA3 + AD3 15 | | 26 PA2 + AD4 16 | | 25 PA1 + AD5 17 | | 24 PA0 + AD6 18 | | 23 A10 + AD7 19 | | 22 A9 + Vss 20 |_____________| 21 A8 + +**********************************************************************/ + +#pragma once + +#ifndef __I8355__ +#define __I8355__ + +#include "emu.h" + + + +///************************************************************************* +// MACROS / CONSTANTS +///************************************************************************* + + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_I8355_ADD(_tag, _clock, _config) \ + MCFG_DEVICE_ADD((_tag), I8355, _clock) \ + MCFG_DEVICE_CONFIG(_config) + +#define I8355_INTERFACE(name) \ + const i8355_interface (name) = + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> i8355_interface + +struct i8355_interface +{ + devcb_read8 in_pa_func; + devcb_write8 out_pa_func; + + devcb_read8 in_pb_func; + devcb_write8 out_pb_func; +}; + + + +// ======================> i8355_device_config + +class i8355_device_config : public device_config, + public device_config_memory_interface, + public i8355_interface +{ + friend class i8355_device; + + // construction/destruction + i8355_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); + + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // address space configurations + const address_space_config m_space_config; +}; + + + +// ======================> i8355_device + +class i8355_device : public device_t, + public device_memory_interface +{ + friend class i8355_device_config; + + // construction/destruction + i8355_device(running_machine &_machine, const i8355_device_config &_config); + +public: + DECLARE_READ8_MEMBER( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + DECLARE_READ8_MEMBER( memory_r ); + DECLARE_WRITE8_MEMBER( memory_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + inline UINT8 read_port(int port); + inline void write_port(int port, UINT8 data); + +private: + devcb_resolved_read8 m_in_port_func[2]; + devcb_resolved_write8 m_out_port_func[2]; + + // registers + UINT8 m_output[2]; // output latches + UINT8 m_ddr[2]; // DDR latches + + const i8355_device_config &m_config; +}; + + +// device type definition +extern const device_type I8355; + + + +#endif diff --git a/src/emu/machine/nmc9306.c b/src/emu/machine/nmc9306.c new file mode 100644 index 00000000000..2ea9c963365 --- /dev/null +++ b/src/emu/machine/nmc9306.c @@ -0,0 +1,365 @@ +/********************************************************************** + + National Semiconductor NMC9306 256-Bit Serial EEPROM emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "nmc9306.h" +#include "machine/devhelpr.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + +#define RAM_SIZE 32 + + +// instructions +enum +{ + OTHER = 0, + WRITE, // write register A3A2A1A0 + READ, // read register A3A2A1A0 + ERASE // erase register A3A2A1A0 +}; + +// other instructions +enum +{ + EWDS = 0, // erase/write disable + WRAL, // write all registers + ERAL, // erase all registers + EWEN, // erase/write enable +}; + +// states +enum +{ + STATE_IDLE = 0, + STATE_COMMAND, + STATE_ADDRESS, + STATE_DATA_IN, + STATE_DATA_OUT, + STATE_ERASE +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NMC9306 = nmc9306_device_config::static_alloc_device_config; + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// nmc9306_device_config - constructor +//------------------------------------------------- + +nmc9306_device_config::nmc9306_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) + : device_config(mconfig, static_alloc_device_config, "NMC9306", tag, owner, clock), + device_config_nvram_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// static_alloc_device_config - allocate a new +// configuration object +//------------------------------------------------- + +device_config *nmc9306_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) +{ + return global_alloc(nmc9306_device_config(mconfig, tag, owner, clock)); +} + + +//------------------------------------------------- +// alloc_device - allocate a new device object +//------------------------------------------------- + +device_t *nmc9306_device_config::alloc_device(running_machine &machine) const +{ + return auto_alloc(&machine, nmc9306_device(machine, *this)); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// nmc9306_device - constructor +//------------------------------------------------- + +inline UINT16 nmc9306_device::read(offs_t offset) +{ + return m_register[offset]; +} + + +//------------------------------------------------- +// nmc9306_device - constructor +//------------------------------------------------- + +inline void nmc9306_device::write(offs_t offset, UINT16 data) +{ + if (m_ewen) + { + m_register[offset] &= data; + } +} + + +//------------------------------------------------- +// nmc9306_device - constructor +//------------------------------------------------- + +inline void nmc9306_device::erase(offs_t offset) +{ + if (m_ewen) + { + m_register[offset] = 0xffff; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nmc9306_device - constructor +//------------------------------------------------- + +nmc9306_device::nmc9306_device(running_machine &_machine, const nmc9306_device_config &config) + : device_t(_machine, config), + device_nvram_interface(_machine, config, *this), + m_state(STATE_IDLE), + m_ewen(false), + m_config(config) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nmc9306_device::device_start() +{ + // state saving + save_item(NAME(m_bits)); + save_item(NAME(m_state)); + save_item(NAME(m_command)); + save_item(NAME(m_address)); + save_item(NAME(m_data)); + save_item(NAME(m_ewen)); + save_item(NAME(m_cs)); + save_item(NAME(m_sk)); + save_item(NAME(m_do)); + save_item(NAME(m_di)); +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void nmc9306_device::nvram_default() +{ +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void nmc9306_device::nvram_read(emu_file &file) +{ + file.read(m_register, RAM_SIZE); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void nmc9306_device::nvram_write(emu_file &file) +{ + file.write(m_register, RAM_SIZE); +} + + +//------------------------------------------------- +// cs_w - chip select input +//------------------------------------------------- + +WRITE_LINE_MEMBER( nmc9306_device::cs_w ) +{ + m_cs = state; +} + + +//------------------------------------------------- +// ck_w - serial clock input +//------------------------------------------------- + +WRITE_LINE_MEMBER( nmc9306_device::sk_w ) +{ + m_sk = state; + + if (!m_cs || !m_sk) return; + + switch (m_state) + { + case STATE_IDLE: + if (LOG) logerror("NMC9306 '%s' Idle %u\n", tag(), m_di); + + if (m_di) + { + // start bit received + m_state = STATE_COMMAND; + m_bits = 0; + } + break; + + case STATE_COMMAND: + if (LOG) logerror("NMC9306 '%s' Command Bit %u\n", tag(), m_di); + + m_command <<= 1; + m_command |= m_di; + m_bits++; + + if (m_bits == 4) + { + m_state = STATE_ADDRESS; + m_bits = 0; + } + break; + + case STATE_ADDRESS: + if (LOG) logerror("NMC9306 '%s' Address Bit %u\n", tag(), m_di); + + m_address <<= 1; + m_address |= m_di; + m_bits++; + + if (m_bits == 4) + { + switch ((m_command >> 2) & 0x03) + { + case OTHER: + switch (m_command & 0x03) + { + case EWDS: + if (LOG) logerror("NMC9306 '%s' EWDS\n", tag()); + m_ewen = false; + m_state = STATE_IDLE; + break; + + case WRAL: + if (LOG) logerror("NMC9306 '%s' WRAL\n", tag()); + break; + + case ERAL: + if (LOG) logerror("NMC9306 '%s' ERAL\n", tag()); + break; + + case EWEN: + if (LOG) logerror("NMC9306 '%s' EWEN\n", tag()); + m_ewen = true; + m_state = STATE_IDLE; + break; + } + break; + + case WRITE: + if (LOG) logerror("NMC9306 '%s' WRITE %u\n", tag(), m_address & 0x0f); + m_state = STATE_DATA_IN; + break; + + case READ: + if (LOG) logerror("NMC9306 '%s' READ %u\n", tag(), m_address & 0x0f); + m_data = read(m_address & 0x0f); + m_state = STATE_DATA_OUT; + break; + + case ERASE: + if (LOG) logerror("NMC9306 '%s' ERASE %u\n", tag(), m_address & 0x0f); + erase(m_address & 0x0f); + m_state = STATE_ERASE; + break; + } + + m_bits = 0; + } + break; + + case STATE_DATA_IN: + if (LOG) logerror("NMC9306 '%s' Data Bit IN %u\n", tag(), m_di); + + m_data <<= 1; + m_data |= m_di; + m_bits++; + + if (m_bits == 16) + { + write(m_address & 0x0f, m_data); + + m_state = STATE_IDLE; + } + break; + + case STATE_DATA_OUT: + if (LOG) logerror("NMC9306 '%s' Data Bit OUT %u\n", tag(), m_di); + + m_do = BIT(m_data, 15); + m_data <<= 1; + m_bits++; + + if (m_bits == 16) + { + m_state = STATE_IDLE; + } + break; + } +} + + +//------------------------------------------------- +// di_w - serial data input +//------------------------------------------------- + +WRITE_LINE_MEMBER( nmc9306_device::di_w ) +{ + m_di = state; +} + + +//------------------------------------------------- +// do_r - serial data output +//------------------------------------------------- + +READ_LINE_MEMBER( nmc9306_device::do_r ) +{ + return m_do; +} diff --git a/src/emu/machine/nmc9306.h b/src/emu/machine/nmc9306.h new file mode 100644 index 00000000000..aa9dfb20593 --- /dev/null +++ b/src/emu/machine/nmc9306.h @@ -0,0 +1,118 @@ +/********************************************************************** + + National Semiconductor NMC9306 256-Bit Serial EEPROM emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + CS 1 |* \_/ | 8 Vcc + SK 2 | | 7 NC + DI 3 | | 6 NC + DO 4 |_____________| 5 GND + +**********************************************************************/ + +#pragma once + +#ifndef __NMC9306__ +#define __NMC9306__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_NMC9306_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, NMC9306, 0) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> nmc9306_device_config + +class nmc9306_device_config : public device_config, + public device_config_nvram_interface +{ + friend class nmc9306_device; + + // construction/destruction + nmc9306_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: +}; + + +// ======================> nmc9306_device + +class nmc9306_device : public device_t, + public device_nvram_interface +{ + friend class nmc9306_device_config; + + // construction/destruction + nmc9306_device(running_machine &_machine, const nmc9306_device_config &_config); + +public: + DECLARE_WRITE_LINE_MEMBER( cs_w ); + DECLARE_WRITE_LINE_MEMBER( sk_w ); + DECLARE_WRITE_LINE_MEMBER( di_w ); + DECLARE_READ_LINE_MEMBER( do_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + inline UINT16 read(offs_t offset); + inline void write(offs_t offset, UINT16 data); + inline void erase(offs_t offset); + + UINT16 m_register[16]; + + int m_bits; + int m_state; + UINT8 m_command; + UINT8 m_address; + UINT16 m_data; + bool m_ewen; + int m_cs; + int m_sk; + int m_do; + int m_di; + + const nmc9306_device_config &m_config; +}; + + +// device type definition +extern const device_type NMC9306; + + + +#endif diff --git a/src/emu/machine/z8536.c b/src/emu/machine/z8536.c new file mode 100644 index 00000000000..e9d2d277b83 --- /dev/null +++ b/src/emu/machine/z8536.c @@ -0,0 +1,610 @@ +/********************************************************************** + + Zilog Z8536 Counter/Timer and Parallel I/O emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "z8536.h" +#include "machine/devhelpr.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +// states +enum +{ + STATE_RESET = -1, + STATE_0, + STATE_1 +}; + + +// ports +enum +{ + PORT_C = 0, + PORT_B, + PORT_A, + CONTROL +}; + + +// registers +enum +{ + MASTER_INTERRUPT_CONTROL = 0, + MASTER_CONFIGURATION_CONTROL, + PORT_A_INTERRUPT_VECTOR, + PORT_B_INTERRUPT_VECTOR, + COUNTER_TIMER_INTERRUPT_VECTOR, + PORT_C_DATA_PATH_POLARITY, + PORT_C_DATA_DIRECTION, + PORT_C_SPECIAL_IO_CONTROL, + PORT_A_COMMAND_AND_STATUS, + PORT_B_COMMAND_AND_STATUS, + COUNTER_TIMER_1_COMMAND_AND_STATUS, + COUNTER_TIMER_2_COMMAND_AND_STATUS, + COUNTER_TIMER_3_COMMAND_AND_STATUS, + PORT_A_DATA, + PORT_B_DATA, + PORT_C_DATA, + COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE, + COUNTER_TIMER_1_CURRENT_COUNT_LS_BYTE, + COUNTER_TIMER_2_CURRENT_COUNT_MS_BYTE, + COUNTER_TIMER_2_CURRENT_COUNT_LS_BYTE, + COUNTER_TIMER_3_CURRENT_COUNT_MS_BYTE, + COUNTER_TIMER_3_CURRENT_COUNT_LS_BYTE, + COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE, + COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE, + COUNTER_TIMER_2_TIME_CONSTANT_MS_BYTE, + COUNTER_TIMER_2_TIME_CONSTANT_LS_BYTE, + COUNTER_TIMER_3_TIME_CONSTANT_MS_BYTE, + COUNTER_TIMER_3_TIME_CONSTANT_LS_BYTE, + COUNTER_TIMER_1_MODE_SPECIFICATION, + COUNTER_TIMER_2_MODE_SPECIFICATION, + COUNTER_TIMER_3_MODE_SPECIFICATION, + CURRENT_VECTOR, + PORT_A_MODE_SPECIFICATION, + PORT_A_HANDSHAKE_SPECIFICATION, + PORT_A_DATA_PATH_POLARITY, + PORT_A_DATA_DIRECTION, + PORT_A_SPECIAL_IO_CONTROL, + PORT_A_PATTERN_POLARITY, + PORT_A_PATTERN_TRANSITION, + PORT_A_PATTERN_MASK, + PORT_B_MODE_SPECIFICATION, + PORT_B_HANDSHAKE_SPECIFICATION, + PORT_B_DATA_PATH_POLARITY, + PORT_B_DATA_DIRECTION, + PORT_B_SPECIAL_IO_CONTROL, + PORT_B_PATTERN_POLARITY, + PORT_B_PATTERN_TRANSITION, + PORT_B_PATTERN_MASK +}; + + +// counter/timer link control +enum +{ + LC_INDEPENDENT = 0, + LC_CT1_GATES_CT2, + LC_CT1_TRIGGERS_CT2, + LC_CT1_COUNTS_CT2 +}; + + +// port type select +enum +{ + PTS_BIT = 0, + PTS_INPUT, + PTS_OUTPUT, + PTS_BIDIRECTIONAL +}; + + +// pattern mode specification +enum +{ + PMS_DISABLE = 0, + PMS_AND, + PMS_OR, + PMS_VECTOR +}; + + +// handshake specification +enum +{ + HTS_INTERLOCKED = 0, + HTS_STROBED, + HTS_PULSED, + HTS_3_WIRE +}; + + +// request/wait specification +enum +{ + RWS_DISABLED = 0, + RWS_OUTPUT_WAIT, + RWS_INPUT_WAIT = 3, + RWS_SPECIAL_REQUEST, + RWS_OUTPUT_REQUEST, + RWS_INPUT_REQUEST = 7 +}; + + +// pattern specification +enum +{ + BIT_MASKED_OFF = 0, + ANY_TRANSITION, + ZERO = 4, + ONE, + ONE_TO_ZERO, + ZERO_TO_ONE +}; + + +// output duty cycle +enum +{ + DCS_PULSE, + DCS_ONE_SHOT, + DCS_SQUARE_WAVE, + DCS_DO_NOT_USE +}; + + +// master interrupt control register +#define MICR_RESET 0x01 // reset +#define MICR_RJA 0x02 // right justified address +#define MICR_CT_VIS 0x04 // counter/timer vector includes status +#define MICR_PB_VIS 0x08 // port B vector includes status +#define MICR_PA_VIS 0x10 // port A vector includes status +#define MICR_NV 0x20 // no vector +#define MICR_DLC 0x40 // disable lower chain +#define MICR_MIE 0x80 // master interrupt enable + + +// master configuration control register +#define MCCR_LC_MASK 0x03 // counter/timer link controls +#define MCCR_PAE 0x04 // port A enable +#define MCCR_PLC 0x08 // port link control +#define MCCR_PCE_CT3E 0x10 // port C and counter/timer 3 enable +#define MCCR_CT2E 0x20 // counter/timer 2 enable +#define MCCR_CT1E 0x40 // counter/timer 1 enable +#define MCCR_PBE 0x80 // port B enable + + +// port mode specification registers +#define PMS_LPM 0x01 // latch on pattern match +#define PMS_PMS_MASK 0x06 // pattern mode specification +#define PMS_IMO 0x08 // interrupt on match only +#define PMS_SB 0x10 // single buffer +#define PMS_ITB 0x20 // interrupt on two bytes +#define PMS_PTS_MASK 0xc0 // port type select + + +// port handshake specification registers +#define PHS_DTS_MASK 0x07 // deskew time specification +#define PHS_RWS_MASK 0x38 // request/wait specification +#define PHS_HTS_MASK 0xc0 // handshake type specification + + +// port command and status registers +#define PCS_IOE 0x01 // interrupt on error +#define PCS_PMF 0x02 // pattern match flag (read only) +#define PCS_IRF 0x04 // input register full (read only) +#define PCS_ORE 0x08 // output register empty (read only) +#define PCS_ERR 0x10 // interrupt error (read only) +#define PCS_IP 0x20 // interrupt pending +#define PCS_IE 0x40 // interrupt enable +#define PCS_IUS 0x80 // interrupt under service + + +// counter/timer mode specification registers +#define CTMS_DCS_MASK 0x03 // output duty cycle +#define CTMS_REB 0x04 // retrigger enable bit +#define CTMS_EDE 0x08 // external gate enable +#define CTMS_ETE 0x10 // external trigger enable +#define CTMS_ECE 0x20 // external count enable +#define CTMS_EOE 0x40 // external output enable +#define CTMS_CSC 0x80 // continuous single cycle + + +// counter/timer command and status registers +#define CTCS_CIP 0x01 // count in progress (read only) +#define CTCS_TCB 0x02 // trigger command bit (write only - read returns 0) +#define CTCS_GCB 0x04 // gate command bit +#define CTCS_RCC 0x08 // read counter control (read/set only - cleared by reading CCR LSB) +#define CTCS_ERR 0x10 // interrupt error (read only) +#define CTCS_IP 0x20 // interrupt pending +#define CTCS_IE 0x40 // interrupt enable +#define CTCS_IUS 0x80 // interrupt under service + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type Z8536 = z8536_device_config::static_alloc_device_config; + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +GENERIC_DEVICE_CONFIG_SETUP(z8536, "Zilog Z8536") + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void z8536_device_config::device_config_complete() +{ + // inherit a copy of the static data + const z8536_interface *intf = reinterpret_cast<const z8536_interface *>(static_config()); + if (intf != NULL) + *static_cast<z8536_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&m_out_int_func, 0, sizeof(m_out_int_func)); + memset(&m_in_pa_func, 0, sizeof(m_in_pa_func)); + memset(&m_out_pa_func, 0, sizeof(m_out_pa_func)); + memset(&m_in_pb_func, 0, sizeof(m_in_pb_func)); + memset(&m_out_pb_func, 0, sizeof(m_out_pb_func)); + memset(&m_in_pc_func, 0, sizeof(m_in_pc_func)); + memset(&m_out_pc_func, 0, sizeof(m_out_pc_func)); + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_register - read from register +//------------------------------------------------- + +inline UINT8 z8536_device::read_register(offs_t offset) +{ + UINT8 data = 0; + + data = m_register[offset]; // HACK + + switch (offset) + { + case PORT_A_DATA: + data = devcb_call_read8(&m_in_pa_func, 0); + break; + + case PORT_B_DATA: + data = devcb_call_read8(&m_in_pb_func, 0); + break; + + case PORT_C_DATA: + data = 0xf0 | (devcb_call_read8(&m_in_pc_func, 0) & 0x0f); + break; + + default: + logerror("Z8536 '%s' Unimplemented read from register %u\n", tag(), offset); + } + + return data; +} + + +//------------------------------------------------- +// read_register - masked read from register +//------------------------------------------------- + +inline UINT8 z8536_device::read_register(offs_t offset, UINT8 mask) +{ + return read_register(offset) & mask; +} + + +//------------------------------------------------- +// write_register - write to register +//------------------------------------------------- + +inline void z8536_device::write_register(offs_t offset, UINT8 data) +{ + switch (offset) + { + case MASTER_INTERRUPT_CONTROL: + if (data & MICR_RESET) + { + device_reset(); + } + else if (m_state == STATE_RESET) + { + m_state = STATE_0; + } + break; + + case PORT_A_DATA: + devcb_call_write8(&m_out_pa_func, 0, data); + break; + + case PORT_B_DATA: + devcb_call_write8(&m_out_pb_func, 0, data); + break; + + case PORT_C_DATA: + { + UINT8 mask = (data & 0xf0) | (data >> 4); + + m_output[PORT_C] = (m_output[PORT_C] & mask) | ((data & 0x0f) & (mask ^ 0xff)); + + devcb_call_write8(&m_out_pc_func, 0, m_output[PORT_C]); + } + break; + + default: + logerror("Z8536 '%s' Unimplemented write %02x to register %u\n", tag(), data, offset); + } + + m_register[offset] = data; // HACK +} + + +//------------------------------------------------- +// write_register - masked write to register +//------------------------------------------------- + +inline void z8536_device::write_register(offs_t offset, UINT8 data, UINT8 mask) +{ + UINT8 combined_data = (data & mask) | (m_register[offset] & (mask ^ 0xff)); + + write_register(offset, combined_data); +} + + +//------------------------------------------------- +// count - +//------------------------------------------------- + +inline void z8536_device::count(device_timer_id id) +{ +} + + +//------------------------------------------------- +// trigger - +//------------------------------------------------- + +inline void z8536_device::trigger(device_timer_id id) +{ +} + + +//------------------------------------------------- +// gate - +//------------------------------------------------- + +inline void z8536_device::gate(device_timer_id id) +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z8536_device - constructor +//------------------------------------------------- + +z8536_device::z8536_device(running_machine &_machine, const z8536_device_config &config) + : device_t(_machine, config), + m_config(config) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z8536_device::device_start() +{ + // allocate timers + m_timer[TIMER_1] = timer_alloc(TIMER_1); + m_timer[TIMER_2] = timer_alloc(TIMER_2); + m_timer[TIMER_3] = timer_alloc(TIMER_3); + + // resolve callbacks + devcb_resolve_write_line(&m_out_int_func, &m_config.m_out_int_func, this); + devcb_resolve_read8(&m_in_pa_func, &m_config.m_in_pa_func, this); + devcb_resolve_write8(&m_out_pa_func, &m_config.m_out_pa_func, this); + devcb_resolve_read8(&m_in_pb_func, &m_config.m_in_pb_func, this); + devcb_resolve_write8(&m_out_pb_func, &m_config.m_out_pb_func, this); + devcb_resolve_read8(&m_in_pc_func, &m_config.m_in_pc_func, this); + devcb_resolve_write8(&m_out_pc_func, &m_config.m_out_pc_func, this); +} + + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void z8536_device::device_reset() +{ + m_state = STATE_RESET; + + for (int i = 0; i < 48; i++) + { + m_register[i] = 0; + } + + m_register[MASTER_INTERRUPT_CONTROL] = MICR_RESET; + m_pointer = 0; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void z8536_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_1: + count(TIMER_1); + break; + + case TIMER_2: + count(TIMER_2); + break; + + case TIMER_3: + count(TIMER_3); + break; + } +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( z8536_device::read ) +{ + UINT8 data = 0; + + if (m_state == STATE_RESET) + { + // read RESET bit + data = read_register(m_pointer, 0x01); + } + else + { + switch (offset & 0x03) + { + case PORT_C: + data = read_register(PORT_C_DATA); + break; + + case PORT_B: + data = read_register(PORT_B_DATA); + break; + + case PORT_A: + data = read_register(PORT_A_DATA); + break; + + case CONTROL: + switch (m_state) + { + case STATE_1: + m_state = STATE_0; + // fallthru + case STATE_0: + data = read_register(m_pointer); + break; + } + break; + } + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( z8536_device::write ) +{ + if (m_state == STATE_RESET) + { + // write RESET bit + write_register(m_pointer, data, 0x01); + } + else + { + switch (offset & 0x03) + { + case PORT_C: + write_register(PORT_C_DATA, data); + break; + + case PORT_B: + write_register(PORT_B_DATA, data); + break; + + case PORT_A: + write_register(PORT_A_DATA, data); + break; + + case CONTROL: + switch (m_state) + { + case STATE_0: + m_pointer = data; + m_state = STATE_1; + break; + + case STATE_1: + write_register(m_pointer, data); + m_state = STATE_0; + } + break; + } + } +} + + +//------------------------------------------------- +// intack_w - interrupt acknowledge +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::intack_w ) +{ +} + + +//------------------------------------------------- +// pb*_w - port B bits 0-7 write +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::pb0_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb1_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb2_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb3_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb4_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb5_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb6_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb7_w ) { } + + +//------------------------------------------------- +// pc*_w - port C bits 0-3 write +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::pc0_w ) { } +WRITE_LINE_MEMBER( z8536_device::pc1_w ) { } +WRITE_LINE_MEMBER( z8536_device::pc2_w ) { } +WRITE_LINE_MEMBER( z8536_device::pc3_w ) { } diff --git a/src/emu/machine/z8536.h b/src/emu/machine/z8536.h new file mode 100644 index 00000000000..75f82f12988 --- /dev/null +++ b/src/emu/machine/z8536.h @@ -0,0 +1,182 @@ +/********************************************************************** + + Zilog Z8536 Counter/Timer and Parallel I/O emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + D4 1 |* \_/ | 40 D3 + D5 2 | | 39 D2 + D6 3 | | 38 D1 + D7 4 | | 37 D0 + _RD 5 | | 36 _CE + _WR 6 | | 35 A1 + GND 7 | | 34 A0 + PB0 8 | | 33 PA0 + PB1 9 | | 32 PA1 + PB2 10 | Z8536 | 31 PA2 + PB3 11 | | 30 PA3 + PB4 12 | | 29 PA4 + PB5 13 | | 28 PA5 + PB6 14 | | 27 PA6 + PB7 15 | | 26 PA7 + PCLK 16 | | 25 _INTACK + IEI 17 | | 24 _INT + IEO 18 | | 23 +5 V + PC0 19 | | 22 PC3 + PC1 20 |_____________| 21 PC2 + +**********************************************************************/ + +#pragma once + +#ifndef __Z8536__ +#define __Z8536__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_Z8536_ADD(_tag, _clock, _intrf) \ + MCFG_DEVICE_ADD(_tag, Z8536, _clock) \ + MCFG_DEVICE_CONFIG(_intrf) + +#define Z8536_INTERFACE(name) \ + const z8536_interface (name)= + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> z8536_interface + +struct z8536_interface +{ + devcb_write_line m_out_int_func; + + devcb_read8 m_in_pa_func; + devcb_write8 m_out_pa_func; + + devcb_read8 m_in_pb_func; + devcb_write8 m_out_pb_func; + + devcb_read8 m_in_pc_func; + devcb_write8 m_out_pc_func; +}; + + +// ======================> z8536_device_config + +class z8536_device_config : public device_config, + public z8536_interface +{ + friend class z8536_device; + + // construction/destruction + z8536_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); +}; + + +// ======================> z8536_device + +class z8536_device : public device_t +{ + friend class z8536_device_config; + + // construction/destruction + z8536_device(running_machine &_machine, const z8536_device_config &_config); + +public: + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( intack_w ); + + DECLARE_WRITE_LINE_MEMBER( pb0_w ); + DECLARE_WRITE_LINE_MEMBER( pb1_w ); + DECLARE_WRITE_LINE_MEMBER( pb2_w ); + DECLARE_WRITE_LINE_MEMBER( pb3_w ); + DECLARE_WRITE_LINE_MEMBER( pb4_w ); + DECLARE_WRITE_LINE_MEMBER( pb5_w ); + DECLARE_WRITE_LINE_MEMBER( pb6_w ); + DECLARE_WRITE_LINE_MEMBER( pb7_w ); + DECLARE_WRITE_LINE_MEMBER( pc0_w ); + DECLARE_WRITE_LINE_MEMBER( pc1_w ); + DECLARE_WRITE_LINE_MEMBER( pc2_w ); + DECLARE_WRITE_LINE_MEMBER( pc3_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + static const device_timer_id TIMER_1 = 0; + static const device_timer_id TIMER_2 = 1; + static const device_timer_id TIMER_3 = 2; + + inline UINT8 read_register(offs_t offset); + inline UINT8 read_register(offs_t offset, UINT8 mask); + inline void write_register(offs_t offset, UINT8 data); + inline void write_register(offs_t offset, UINT8 data, UINT8 mask); + + inline void count(device_timer_id id); + inline void trigger(device_timer_id id); + inline void gate(device_timer_id id); + + devcb_resolved_write_line m_out_int_func; + + devcb_resolved_read8 m_in_pa_func; + devcb_resolved_write8 m_out_pa_func; + + devcb_resolved_read8 m_in_pb_func; + devcb_resolved_write8 m_out_pb_func; + + devcb_resolved_read8 m_in_pc_func; + devcb_resolved_write8 m_out_pc_func; + + int m_state; + UINT8 m_register[48]; + UINT8 m_pointer; + UINT8 m_input[3]; + UINT8 m_output[3]; + UINT8 m_buffer[3]; + + // timers + emu_timer *m_timer[3]; + + const z8536_device_config &m_config; +}; + + +// device type definition +extern const device_type Z8536; + + + +#endif diff --git a/src/emu/video/crt9007.c b/src/emu/video/crt9007.c new file mode 100644 index 00000000000..f048f8929f2 --- /dev/null +++ b/src/emu/video/crt9007.c @@ -0,0 +1,1017 @@ +/********************************************************************** + + SMC CRT9007 CRT Video Processor and Controller (VPAC) emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +/* + + TODO: + + - cursor timer + - interrupts + - light pen + - frame timer + - non-DMA mode + - DMA mode + - cursor/blank skew + - sequential breaks + - interlaced mode + - smooth scroll + - page blank + - double height cursor + - row attributes + - pin configuration + - operation modes 0,4,7 + - address modes 1,2,3 + - light pen + - state saving + +*/ + +#include "emu.h" +#include "crt9007.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + +#define HAS_VALID_PARAMETERS \ + (m_reg[0x00] && m_reg[0x01] && m_reg[0x07] && m_reg[0x08] && m_reg[0x09]) + +#define CHARACTERS_PER_HORIZONTAL_PERIOD \ + m_reg[0x00] + +#define CHARACTERS_PER_DATA_ROW \ + (m_reg[0x01] + 1) + +#define HORIZONTAL_DELAY \ + m_reg[0x02] + +#define HORIZONTAL_SYNC_WIDTH \ + m_reg[0x03] + +#define VERTICAL_SYNC_WIDTH \ + m_reg[0x04] + +#define VERTICAL_DELAY \ + (m_reg[0x05] - 1) + +#define PIN_CONFIGURATION \ + (m_reg[0x06] >> 6) + +#define CURSOR_SKEW \ + ((m_reg[0x06] >> 3) & 0x07) + +#define BLANK_SKEW \ + (m_reg[0x06] & 0x07) + +#define VISIBLE_DATA_ROWS_PER_FRAME \ + (m_reg[0x07] + 1) + +#define SCAN_LINES_PER_DATA_ROW \ + ((m_reg[0x08] & 0x1f) + 1) + +#define SCAN_LINES_PER_FRAME \ + (((m_reg[0x08] << 3) & 0x0700) | m_reg[0x09]) + +#define DMA_BURST_COUNT \ + ((m_reg[0x0a] & 0x0f) + 1) + +#define DMA_BURST_DELAY \ + ((((m_reg[0x0a] >> 4) & 0x07) + 1) % 8) + +#define DMA_DISABLE \ + BIT(m_reg[0x0a], 7) + +#define SINGLE_HEIGHT_CURSOR \ + BIT(m_reg[0x0b], 0) + +#define OPERATION_MODE \ + ((m_reg[0x0b] >> 1) & 0x07) + +#define INTERLACE_MODE \ + ((m_reg[0x0b] >> 4) & 0x03) + +#define PAGE_BLANK \ + BIT(m_reg[0x0b], 6) + +#define TABLE_START \ + (((m_reg[0x0d] << 8) & 0x3f00) | m_reg[0x0c]) + +#define ADDRESS_MODE \ + ((m_reg[0x0d] >> 6) & 0x03) + +#define AUXILIARY_ADDRESS_1 \ + (((m_reg[0x0f] << 8) & 0x3f00) | m_reg[0x0e]) + +#define ROW_ATTRIBUTES_1 \ + ((m_reg[0x0f] >> 6) & 0x03) + +#define SEQUENTIAL_BREAK_1 \ + m_reg[0x10] + +#define SEQUENTIAL_BREAK_2 \ + m_reg[0x12] + +#define DATA_ROW_START \ + m_reg[0x11] + +#define DATA_ROW_END \ + m_reg[0x12] + +#define AUXILIARY_ADDRESS_2 \ + (((m_reg[0x14] << 8) & 0x3f00) | m_reg[0x13]) + +#define ROW_ATTRIBUTES_2 \ + ((m_reg[0x14] >> 6) & 0x03) + +#define SMOOTH_SCROLL_OFFSET \ + ((m_reg[0x17] >> 1) & 0x3f) + +#define SMOOTH_SCROLL_OFFSET_OVERFLOW \ + BIT(m_reg[0x17], 7) + +#define VERTICAL_CURSOR \ + m_reg[0x18] + +#define HORIZONTAL_CURSOR \ + m_reg[0x19] + +#define INTERRUPT_ENABLE \ + m_reg[0x1a] + +#define FRAME_TIMER \ + BIT(m_reg[0x1a], 0) + +#define LIGHT_PEN_INTERRUPT \ + BIT(m_reg[0x1a], 5) + +#define VERTICAL_RETRACE_INTERRUPT \ + BIT(m_reg[0x1a], 6) + +#define VERTICAL_LIGHT_PEN \ + m_reg[0x3b] + +#define HORIZONTAL_LIGHT_PEN \ + m_reg[0x3c] + + +// interlace +enum +{ + NON_INTERLACED = 0, + ENHANCED_VIDEO_INTERFACE, + NORMAL_VIDEO_INTERFACE, +}; + + +// operation modes +enum +{ + OPERATION_MODE_REPETITIVE_MEMORY_ADDRESSING = 0, // not implemented + OPERATION_MODE_DOUBLE_ROW_BUFFER = 1, + OPERATION_MODE_SINGLE_ROW_BUFFER = 4, // not implemented + OPERATION_MODE_ATTRIBUTE_ASSEMBLE = 7 // not implemented +}; + + +// addressing modes +enum +{ + ADDRESS_MODE_SEQUENTIAL_ADDRESSING = 0, + ADDRESS_MODE_SEQUENTIAL_ROLL_ADDRESSING, // not implemented + ADDRESS_MODE_CONTIGUOUS_ROW_TABLE, // not implemented + ADDRESS_MODE_LINKED_LIST_ROW_TABLE // not implemented +}; + + +// interrupt enable register bits +const int IE_VERTICAL_RETRACE = 0x40; +const int IE_LIGHT_PEN = 0x20; +const int IE_FRAME_TIMER = 0x01; + +// status register bits +const int STATUS_INTERRUPT_PENDING = 0x80; +const int STATUS_VERTICAL_RETRACE = 0x40; +const int STATUS_LIGHT_PEN_UPDATE = 0x20; +const int STATUS_ODD_EVEN = 0x04; +const int STATUS_FRAME_TIMER_OCCURRED = 0x01; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type CRT9007 = crt9007_device_config::static_alloc_device_config; + + +// default address map +static ADDRESS_MAP_START( crt9007, AS_0, 8 ) + AM_RANGE(0x0000, 0x3fff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// crt9007_device_config - constructor +//------------------------------------------------- + +crt9007_device_config::crt9007_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) + : device_config(mconfig, static_alloc_device_config, "SMC CRT9007", tag, owner, clock), + device_config_memory_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(crt9007)) +{ +} + + +//------------------------------------------------- +// static_alloc_device_config - allocate a new +// configuration object +//------------------------------------------------- + +device_config *crt9007_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) +{ + return global_alloc(crt9007_device_config(mconfig, tag, owner, clock)); +} + + +//------------------------------------------------- +// alloc_device - allocate a new device object +//------------------------------------------------- + +device_t *crt9007_device_config::alloc_device(running_machine &machine) const +{ + return auto_alloc(&machine, crt9007_device(machine, *this)); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *crt9007_device_config::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void crt9007_device_config::device_config_complete() +{ + // inherit a copy of the static data + const crt9007_interface *intf = reinterpret_cast<const crt9007_interface *>(static_config()); + if (intf != NULL) + *static_cast<crt9007_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&out_int_func, 0, sizeof(out_int_func)); + memset(&out_dmar_func, 0, sizeof(out_dmar_func)); + memset(&out_vs_func, 0, sizeof(out_vs_func)); + memset(&out_hs_func, 0, sizeof(out_hs_func)); + memset(&out_vlt_func, 0, sizeof(out_vlt_func)); + memset(&out_curs_func, 0, sizeof(out_curs_func)); + memset(&out_drb_func, 0, sizeof(out_drb_func)); + memset(&out_cblank_func, 0, sizeof(out_cblank_func)); + memset(&out_slg_func, 0, sizeof(out_slg_func)); + memset(&out_sld_func, 0, sizeof(out_sld_func)); + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 crt9007_device::readbyte(offs_t address) +{ + return space()->read_byte(address); +} + + +//------------------------------------------------- +// trigger_interrupt - +//------------------------------------------------- + +inline void crt9007_device::trigger_interrupt(int line) +{ + if (INTERRUPT_ENABLE & line) + { + int status = m_status; + + m_status |= STATUS_INTERRUPT_PENDING | line; + + if (!(status & STATUS_INTERRUPT_PENDING)) + { + if (LOG) logerror("CRT9007 '%s' INT 1\n", tag()); + devcb_call_write_line(&m_out_int_func, ASSERT_LINE); + } + } +} + + +//------------------------------------------------- +// update_cblank_line - +//------------------------------------------------- + +inline void crt9007_device::update_cblank_line() +{ + int x = m_screen->hpos(); + int y = m_screen->vpos(); + + // composite blank + int cblank = !(m_hs & m_vs); + + if (m_cblank != cblank) + { + m_cblank = cblank; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : CBLANK %u\n", tag(), y, x, m_cblank); + + devcb_call_write_line(&m_out_cblank_func, m_cblank); + } +} + + +//------------------------------------------------- +// update_hsync_timer - +//------------------------------------------------- + +inline void crt9007_device::update_hsync_timer(int state) +{ + int y = m_screen->vpos(); + + int next_x = state ? m_hsync_start : m_hsync_end; + int next_y = state ? (y + 1) % SCAN_LINES_PER_FRAME : y; + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_hsync_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_vsync_timer - +//------------------------------------------------- + +inline void crt9007_device::update_vsync_timer(int state) +{ + int next_y = state ? m_vsync_start : m_vsync_end; + + attotime duration = m_screen->time_until_pos(next_y, 0); + + m_vsync_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_vlt_timer - +//------------------------------------------------- + +inline void crt9007_device::update_vlt_timer(int state) +{ + // this signal is active during all visible scan lines and during the horizontal trace at vertical retrace + int y = m_screen->vpos(); + + int next_x = state ? m_vlt_end : m_vlt_start; + int next_y = state ? y : ((y == m_vlt_bottom) ? 0 : (y + 1)); + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_vlt_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_curs_timer - +//------------------------------------------------- + +inline void crt9007_device::update_curs_timer(int state) +{ + // this signal is active for 1 character time for all scanlines within the data row + // TODO +} + + +//------------------------------------------------- +// update_drb_timer - +//------------------------------------------------- + +inline void crt9007_device::update_drb_timer(int state) +{ + // this signal is active for 1 full scan line (VLT edge to edge) at the top scan line of each new row + // there is 1 extra DRB signal during the 1st scanline of the vertical retrace interval + int y = m_screen->vpos(); + + int next_x = m_vlt_end; + int next_y = y ? y + 1 : y; + + if (state) + { + if (y == 0) + { + next_y = VERTICAL_DELAY - 1; + } + else if (y == m_drb_bottom) + { + next_x = 0; + next_y = 0; + } + else + { + next_y = y + SCAN_LINES_PER_DATA_ROW - 1; + } + } + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_drb_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_dma_timer - +//------------------------------------------------- + +inline void crt9007_device::update_dma_timer() +{ + // TODO +} + + +//------------------------------------------------- +// recompute_parameters - +//------------------------------------------------- + +inline void crt9007_device::recompute_parameters() +{ + // check that necessary registers have been loaded + if (!HAS_VALID_PARAMETERS) return; + + // screen dimensions + int horiz_pix_total = CHARACTERS_PER_HORIZONTAL_PERIOD * m_hpixels_per_column; + int vert_pix_total = SCAN_LINES_PER_FRAME; + + // refresh rate + attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock()) * horiz_pix_total * vert_pix_total; + + // horizontal sync + m_hsync_start = 0; + m_hsync_end = HORIZONTAL_SYNC_WIDTH * m_hpixels_per_column; + + // visible line time + m_vlt_start = HORIZONTAL_DELAY * m_hpixels_per_column; + m_vlt_end = (HORIZONTAL_DELAY + CHARACTERS_PER_DATA_ROW) * m_hpixels_per_column; + m_vlt_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - 1; + + // data row boundary + m_drb_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - SCAN_LINES_PER_DATA_ROW; + + // vertical sync + m_vsync_start = 0; + m_vsync_end = VERTICAL_SYNC_WIDTH; + + // visible area + rectangle visarea; + + visarea.min_x = m_hsync_end; + visarea.max_x = horiz_pix_total - 1; + + visarea.min_y = m_vsync_end; + visarea.max_y = vert_pix_total - 1; + + if (LOG) + { + logerror("CRT9007 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh)); + logerror("CRT9007 '%s' Visible Area: (%u, %u) - (%u, %u)\n", tag(), visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y); + } + + m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); + + m_hsync_timer->adjust(m_screen->time_until_pos(0, 0)); + m_vsync_timer->adjust(m_screen->time_until_pos(0, 0)); + m_vlt_timer->adjust(m_screen->time_until_pos(0, m_vlt_start), 1); + m_drb_timer->adjust(m_screen->time_until_pos(0, 0)); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// crt9007_device - constructor +//------------------------------------------------- + +crt9007_device::crt9007_device(running_machine &_machine, const crt9007_device_config &config) + : device_t(_machine, config), + device_memory_interface(_machine, config, *this), + m_config(config) +{ + for (int i = 0; i < 0x3d; i++) + m_reg[i] = 0; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void crt9007_device::device_start() +{ + // allocate timers + m_hsync_timer = timer_alloc(TIMER_HSYNC); + m_vsync_timer = timer_alloc(TIMER_VSYNC); + m_vlt_timer = timer_alloc(TIMER_VLT); + m_curs_timer = timer_alloc(TIMER_CURS); + m_drb_timer = timer_alloc(TIMER_DRB); + m_dma_timer = timer_alloc(TIMER_DMA); + + // resolve callbacks + devcb_resolve_write_line(&m_out_int_func, &m_config.out_int_func, this); + devcb_resolve_write_line(&m_out_dmar_func, &m_config.out_dmar_func, this); + devcb_resolve_write_line(&m_out_hs_func, &m_config.out_hs_func, this); + devcb_resolve_write_line(&m_out_vs_func, &m_config.out_vs_func, this); + devcb_resolve_write_line(&m_out_vlt_func, &m_config.out_vlt_func, this); + devcb_resolve_write_line(&m_out_curs_func, &m_config.out_curs_func, this); + devcb_resolve_write_line(&m_out_drb_func, &m_config.out_drb_func, this); + devcb_resolve_write_line(&m_out_cblank_func, &m_config.out_cblank_func, this); + devcb_resolve_write_line(&m_out_slg_func, &m_config.out_slg_func, this); + devcb_resolve_write_line(&m_out_sld_func, &m_config.out_sld_func, this); + + // get the screen device + m_screen = machine->device<screen_device>(m_config.screen_tag); + assert(m_screen != NULL); + + // set horizontal pixels per column + m_hpixels_per_column = m_config.hpixels_per_column; + + // register for state saving +// state_save_register_device_item(this, 0, ); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void crt9007_device::device_reset() +{ + m_disp = 0; + + // HS = 1 + devcb_call_write_line(&m_out_hs_func, 1); + + // VS = 1 + devcb_call_write_line(&m_out_vs_func, 1); + + // CBLANK = 1 + devcb_call_write_line(&m_out_cblank_func, 0); + + // CURS = 0 + devcb_call_write_line(&m_out_curs_func, 0); + + // VLT = 0 + devcb_call_write_line(&m_out_vlt_func, 0); + + // DRB = 1 + devcb_call_write_line(&m_out_drb_func, 1); + + // INT = 0 + devcb_call_write_line(&m_out_int_func, CLEAR_LINE); + + // 28 (DMAR) = 0 + devcb_call_write_line(&m_out_dmar_func, CLEAR_LINE); + + // 29 (WBEN) = 0 + + // 30 (SLG) = 0 + devcb_call_write_line(&m_out_slg_func, 0); + + // 31 (SLD) = 0 + devcb_call_write_line(&m_out_sld_func, 0); + + // 32 (LPSTB) = 0 +} + + +//------------------------------------------------- +// device_clock_changed - handle clock change +//------------------------------------------------- + +void crt9007_device::device_clock_changed() +{ + recompute_parameters(); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void crt9007_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int x = m_screen->hpos(); + int y = m_screen->vpos(); + + switch (id) + { + case TIMER_HSYNC: + m_hs = param; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : HS %u\n", tag(), y, x, m_hs); + + devcb_call_write_line(&m_out_hs_func, m_hs); + + update_cblank_line(); + + update_hsync_timer(param); + break; + + case TIMER_VSYNC: + m_vs = param; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : VS %u\n", tag(), y, x, m_vs); + + devcb_call_write_line(&m_out_vs_func, param); + + if (m_vs) + { + // reset all other bits except Light Pen Update to logic 0 + m_status &= STATUS_LIGHT_PEN_UPDATE; + } + else + { + trigger_interrupt(IE_VERTICAL_RETRACE); + + update_cblank_line(); + } + + update_vsync_timer(param); + break; + + case TIMER_VLT: + m_vlt = param; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : VLT %u\n", tag(), y, x, m_vlt); + + devcb_call_write_line(&m_out_vlt_func, param); + + update_vlt_timer(param); + break; + + case TIMER_CURS: + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : CURS %u\n", tag(), y, x, param); + + devcb_call_write_line(&m_out_curs_func, param); + + update_curs_timer(param); + break; + + case TIMER_DRB: + m_drb = param; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : DRB %u\n", tag(), y, x, m_drb); + + devcb_call_write_line(&m_out_drb_func, param); + + if (!m_drb && !DMA_DISABLE) + { + // start DMA burst sequence + m_dma_count = CHARACTERS_PER_DATA_ROW; + m_dma_burst = DMA_BURST_COUNT ? (DMA_BURST_COUNT * 4) : CHARACTERS_PER_DATA_ROW; + m_dma_delay = DMA_BURST_DELAY; + m_dmar = 1; + + if (LOG) logerror("CRT9007 '%s' DMAR 1\n", tag()); + devcb_call_write_line(&m_out_dmar_func, ASSERT_LINE); + } + + update_drb_timer(param); + break; + + case TIMER_DMA: + readbyte(AUXILIARY_ADDRESS_2); + + update_dma_timer(); + break; + } +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( crt9007_device::read ) +{ + UINT8 data = 0; + + switch (offset) + { + case 0x15: + if (LOG) logerror("CRT9007 '%s' Start\n", tag()); + m_disp = 1; + break; + + case 0x16: + if (LOG) logerror("CRT9007 '%s' Reset\n", tag()); + device_reset(); + break; + + case 0x38: + data = VERTICAL_CURSOR; + break; + + case 0x39: + data = HORIZONTAL_CURSOR; + break; + + case 0x3a: + data = m_status; + + // reset interrupt pending bit + m_status &= ~STATUS_INTERRUPT_PENDING; + if (LOG) logerror("CRT9007 '%s' INT 0\n", tag()); + devcb_call_write_line(&m_out_int_func, CLEAR_LINE); + break; + + case 0x3b: + data = VERTICAL_LIGHT_PEN; + break; + + case 0x3c: + data = HORIZONTAL_LIGHT_PEN; + + // reset light pen update bit + m_status &= ~STATUS_LIGHT_PEN_UPDATE; + break; + + default: + logerror("CRT9007 '%s' Read from Invalid Register: %02x!\n", tag(), offset); + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( crt9007_device::write ) +{ + m_reg[offset] = data; + + switch (offset) + { + case 0x00: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Characters per Horizontal Period: %u\n", tag(), CHARACTERS_PER_HORIZONTAL_PERIOD); + break; + + case 0x01: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Characters per Data Row: %u\n", tag(), CHARACTERS_PER_DATA_ROW); + break; + + case 0x02: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Horizontal Delay: %u\n", tag(), HORIZONTAL_DELAY); + break; + + case 0x03: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Horizontal Sync Width: %u\n", tag(), HORIZONTAL_SYNC_WIDTH); + break; + + case 0x04: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Vertical Sync Width: %u\n", tag(), VERTICAL_SYNC_WIDTH); + break; + + case 0x05: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Vertical Delay: %u\n", tag(), VERTICAL_DELAY); + break; + + case 0x06: + recompute_parameters(); + if (LOG) + { + logerror("CRT9007 '%s' Pin Configuration: %u\n", tag(), PIN_CONFIGURATION); + logerror("CRT9007 '%s' Cursor Skew: %u\n", tag(), CURSOR_SKEW); + logerror("CRT9007 '%s' Blank Skew: %u\n", tag(), BLANK_SKEW); + } + break; + + case 0x07: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Visible Data Rows per Frame: %u\n", tag(), VISIBLE_DATA_ROWS_PER_FRAME); + break; + + case 0x08: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Scan Lines per Data Row: %u\n", tag(), SCAN_LINES_PER_DATA_ROW); + break; + + case 0x09: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Scan Lines per Frame: %u\n", tag(), SCAN_LINES_PER_FRAME); + break; + + case 0x0a: + if (LOG) + { + logerror("CRT9007 '%s' DMA Burst Count: %u\n", tag(), DMA_BURST_COUNT); + logerror("CRT9007 '%s' DMA Burst Delay: %u\n", tag(), DMA_BURST_DELAY); + logerror("CRT9007 '%s' DMA Disable: %u\n", tag(), DMA_DISABLE); + } + break; + + case 0x0b: + if (LOG) + { + logerror("CRT9007 '%s' %s Height Cursor\n", tag(), SINGLE_HEIGHT_CURSOR ? "Single" : "Double"); + logerror("CRT9007 '%s' Operation Mode: %u\n", tag(), OPERATION_MODE); + logerror("CRT9007 '%s' Interlace Mode: %u\n", tag(), INTERLACE_MODE); + logerror("CRT9007 '%s' %s Mechanism\n", tag(), PAGE_BLANK ? "Page Blank" : "Smooth Scroll"); + } + break; + + case 0x0c: + break; + + case 0x0d: + if (LOG) + { + logerror("CRT9007 '%s' Table Start Register: %04x\n", tag(), TABLE_START); + logerror("CRT9007 '%s' Address Mode: %u\n", tag(), ADDRESS_MODE); + } + break; + + case 0x0e: + break; + + case 0x0f: + if (LOG) + { + logerror("CRT9007 '%s' Auxialiary Address Register 1: %04x\n", tag(), AUXILIARY_ADDRESS_1); + logerror("CRT9007 '%s' Row Attributes: %u\n", tag(), ROW_ATTRIBUTES_1); + } + break; + + case 0x10: + if (LOG) logerror("CRT9007 '%s' Sequential Break Register 1: %u\n", tag(), SEQUENTIAL_BREAK_1); + break; + + case 0x11: + if (LOG) logerror("CRT9007 '%s' Data Row Start Register: %u\n", tag(), DATA_ROW_START); + break; + + case 0x12: + if (LOG) logerror("CRT9007 '%s' Data Row End/Sequential Break Register 2: %u\n", tag(), SEQUENTIAL_BREAK_2); + break; + + case 0x13: + break; + + case 0x14: + if (LOG) + { + logerror("CRT9007 '%s' Auxiliary Address Register 2: %04x\n", tag(), AUXILIARY_ADDRESS_2); + logerror("CRT9007 '%s' Row Attributes: %u\n", tag(), ROW_ATTRIBUTES_2); + } + break; + + case 0x15: + if (LOG) logerror("CRT9007 '%s' Start\n", tag()); + m_disp = 1; + break; + + case 0x16: + if (LOG) logerror("CRT9007 '%s' Reset\n", tag()); + device_reset(); + break; + + case 0x17: + if (LOG) + { + logerror("CRT9007 '%s' Smooth Scroll Offset: %u\n", tag(), SMOOTH_SCROLL_OFFSET); + logerror("CRT9007 '%s' Smooth Scroll Offset Overflow: %u\n", tag(), SMOOTH_SCROLL_OFFSET_OVERFLOW); + } + break; + + case 0x18: + if (LOG) logerror("CRT9007 '%s' Vertical Cursor Register: %u\n", tag(), VERTICAL_CURSOR); + break; + + case 0x19: + if (LOG) logerror("CRT9007 '%s' Horizontal Cursor Register: %u\n", tag(), HORIZONTAL_CURSOR); + break; + + case 0x1a: + if (LOG) + { + logerror("CRT9007 '%s' Frame Timer: %u\n", tag(), FRAME_TIMER); + logerror("CRT9007 '%s' Light Pen Interrupt: %u\n", tag(), LIGHT_PEN_INTERRUPT); + logerror("CRT9007 '%s' Vertical Retrace Interrupt: %u\n", tag(), VERTICAL_RETRACE_INTERRUPT); + } + break; + + default: + logerror("CRT9007 '%s' Write to Invalid Register: %02x!\n", tag(), offset); + } +} + + +//------------------------------------------------- +// ack_w - DMA acknowledge +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9007_device::ack_w ) +{ + if (LOG) logerror("CRT9007 '%s' ACK: %u\n", tag(), state); + + if (m_dmar && !m_ack && state) + { + // start DMA transfer + m_dma_timer->adjust(attotime::from_hz(clock())); + } + + m_ack = state; +} + + +//------------------------------------------------- +// lpstb_w - light pen strobe +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9007_device::lpstb_w ) +{ + if (LOG) logerror("CRT9007 '%s' LPSTB: %u\n", tag(), state); + + if (!m_lpstb && state) + { + // TODO latch current row/column position + } + + m_lpstb = state; +} + + +//------------------------------------------------- +// vlt_r - +//------------------------------------------------- + +READ_LINE_MEMBER( crt9007_device::vlt_r ) +{ + return m_vlt; +} + + +//------------------------------------------------- +// wben_r - +//------------------------------------------------- + +READ_LINE_MEMBER( crt9007_device::wben_r ) +{ + return m_wben; +} + + +//------------------------------------------------- +// set_hpixels_per_column - +//------------------------------------------------- + +void crt9007_device::set_hpixels_per_column(int hpixels_per_column) +{ + m_hpixels_per_column = hpixels_per_column; + recompute_parameters(); +} diff --git a/src/emu/video/crt9007.h b/src/emu/video/crt9007.h new file mode 100644 index 00000000000..36aefa043cb --- /dev/null +++ b/src/emu/video/crt9007.h @@ -0,0 +1,233 @@ +/********************************************************************** + + SMC CRT9007 CRT Video Processor and Controller (VPAC) emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + VA2 1 |* \_/ | 40 GND + VA10 2 | | 39 VA9 + VA3 3 | | 38 VA1 + VA11 4 | | 37 VA8 + VA12 5 | | 36 VA0 + VA4 6 | | 35 CBLANK + VA13 7 | | 34 CURS + VA5 8 | | 33 ACK/_TSC + VA6 9 | | 32 _CSYNC/LPSTB + VA7 10 | CRT9007 | 31 SLD/SL0 + VLT 11 | | 30 _SLG/SL1 + _VS 12 | | 29 WBEN/SL2/_CSYNC + _HS 13 | | 28 DMAR/SL3/VBLANK + _CCLK 14 | | 27 INT + _DRB 15 | | 26 _RST + VD7 16 | | 25 _CS + VD6 17 | | 24 VD0 + VD5 18 | | 23 VD1 + VD4 19 | | 22 VD2 + VD3 20 |_____________| 21 +5V + +**********************************************************************/ + +#pragma once + +#ifndef __CRT9007__ +#define __CRT9007__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CRT9007_ADD(_tag, _clock, _config, _map) \ + MCFG_DEVICE_ADD(_tag, CRT9007, _clock) \ + MCFG_DEVICE_CONFIG(_config) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) + + +#define CRT9007_INTERFACE(name) \ + const crt9007_interface (name) = + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> crt9007_interface + +struct crt9007_interface +{ + const char *screen_tag; /* screen we are acting on */ + int hpixels_per_column; /* number of pixels per video memory address */ + + devcb_write_line out_int_func; + devcb_write_line out_dmar_func; + + devcb_write_line out_vs_func; + devcb_write_line out_hs_func; + + devcb_write_line out_vlt_func; + devcb_write_line out_curs_func; + devcb_write_line out_drb_func; + devcb_write_line out_cblank_func; + + devcb_write_line out_slg_func; + devcb_write_line out_sld_func; +}; + + + +// ======================> crt9007_device_config + +class crt9007_device_config : public device_config, + public device_config_memory_interface, + public crt9007_interface +{ + friend class crt9007_device; + + // construction/destruction + crt9007_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); + + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // address space configurations + const address_space_config m_space_config; +}; + + + +// ======================> crt9007_device + +class crt9007_device : public device_t, + public device_memory_interface +{ + friend class crt9007_device_config; + + // construction/destruction + crt9007_device(running_machine &_machine, const crt9007_device_config &_config); + +public: + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( ack_w ); + DECLARE_WRITE_LINE_MEMBER( lpstb_w ); + DECLARE_READ_LINE_MEMBER( vlt_r ); + DECLARE_READ_LINE_MEMBER( wben_r ); + + void set_hpixels_per_column(int hpixels_per_column); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_clock_changed(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + static const device_timer_id TIMER_HSYNC = 0; + static const device_timer_id TIMER_VSYNC = 1; + static const device_timer_id TIMER_VLT = 2; + static const device_timer_id TIMER_CURS = 3; + static const device_timer_id TIMER_DRB = 4; + static const device_timer_id TIMER_DMA = 5; + + inline UINT8 readbyte(offs_t address); + + inline void trigger_interrupt(int line); + inline void update_cblank_line(); + inline void update_hsync_timer(int state); + inline void update_vsync_timer(int state); + inline void update_vlt_timer(int state); + inline void update_curs_timer(int state); + inline void update_drb_timer(int state); + inline void update_dma_timer(); + + inline void recompute_parameters(); + + devcb_resolved_write_line m_out_int_func; + devcb_resolved_write_line m_out_dmar_func; + devcb_resolved_write_line m_out_hs_func; + devcb_resolved_write_line m_out_vs_func; + devcb_resolved_write_line m_out_vlt_func; + devcb_resolved_write_line m_out_curs_func; + devcb_resolved_write_line m_out_drb_func; + devcb_resolved_write_line m_out_cblank_func; + devcb_resolved_write_line m_out_slg_func; + devcb_resolved_write_line m_out_sld_func; + + screen_device *m_screen; + + // registers + UINT8 m_reg[0x3d]; + UINT8 m_status; + + int m_disp; + int m_hpixels_per_column; + + // runtime variables, do not state save + int m_vsync_start; + int m_vsync_end; + int m_hsync_start; + int m_hsync_end; + int m_vlt_start; + int m_vlt_end; + int m_vlt_bottom; + int m_drb_bottom; + int m_hs; + int m_vs; + int m_cblank; + int m_vlt; + int m_drb; + int m_wben; + int m_slg; + int m_sld; + int m_lpstb; + + // DMA + int m_dmar; + int m_ack; + int m_dma_count; + int m_dma_burst; + int m_dma_delay; + + // timers + emu_timer *m_vsync_timer; + emu_timer *m_hsync_timer; + emu_timer *m_vlt_timer; + emu_timer *m_curs_timer; + emu_timer *m_drb_timer; + emu_timer *m_dma_timer; + + const crt9007_device_config &m_config; +}; + + +// device type definition +extern const device_type CRT9007; + + + +#endif diff --git a/src/emu/video/crt9021.c b/src/emu/video/crt9021.c new file mode 100644 index 00000000000..13844f4808f --- /dev/null +++ b/src/emu/video/crt9021.c @@ -0,0 +1,269 @@ +/********************************************************************** + + SMC CRT9021 Video Attributes Controller (VAC) emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +/* + + TODO: + + - attributes + - reverse video + - character blank + - character blink + - underline + - full/half intensity + - operation modes + - wide graphics + - thin graphics + - character mode w/o underline + - character mode w/underline + - double height characters + - double width characters + - parallel scan line + - serial scan line + - cursor + - underline + - blinking underline + - reverse video + - blinking reverse video + - programmable character blink rate (75/25 duty) + - programmable cursor blink rate (50/50 duty) + - data/attribute latches + +*/ + +#include "emu.h" +#include "crt9021.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + + +// attributes +enum +{ + ATTRIBUTE_REVID = 0x80, + ATTRIBUTE_INT = 0x40, + ATTRIBUTE_BLINK = 0x20, + ATTRIBUTE_MS1 = 0x10, + ATTRIBUTE_MS0 = 0x08, + ATTRIBUTE_CHABL = 0x04, + ATTRIBUTE_BKC = 0x02, + ATTRIBUTE_BLC = 0x01 +}; + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type CRT9021 = crt9021_device_config::static_alloc_device_config; + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// crt9021_device_config - constructor +//------------------------------------------------- + +crt9021_device_config::crt9021_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) + : device_config(mconfig, static_alloc_device_config, "SMC CRT9021", tag, owner, clock) +{ +} + + +//------------------------------------------------- +// static_alloc_device_config - allocate a new +// configuration object +//------------------------------------------------- + +device_config *crt9021_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) +{ + return global_alloc(crt9021_device_config(mconfig, tag, owner, clock)); +} + + +//------------------------------------------------- +// alloc_device - allocate a new device object +//------------------------------------------------- + +device_t *crt9021_device_config::alloc_device(running_machine &machine) const +{ + return auto_alloc(&machine, crt9021_device(machine, *this)); +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void crt9021_device_config::device_config_complete() +{ + // inherit a copy of the static data + const crt9021_interface *intf = reinterpret_cast<const crt9021_interface *>(static_config()); + if (intf != NULL) + *static_cast<crt9021_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&in_data_func, 0, sizeof(in_data_func)); + memset(&in_attr_func, 0, sizeof(in_attr_func)); + memset(&in_atten_func, 0, sizeof(in_atten_func)); + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// crt9021_device - constructor +//------------------------------------------------- + +crt9021_device::crt9021_device(running_machine &_machine, const crt9021_device_config &config) + : device_t(_machine, config), + m_config(config) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void crt9021_device::device_start() +{ + // allocate timers + + // resolve callbacks + devcb_resolve_read8(&m_in_data_func, &m_config.in_data_func, this); + devcb_resolve_read8(&m_in_attr_func, &m_config.in_attr_func, this); + devcb_resolve_read_line(&m_in_atten_func, &m_config.in_atten_func, this); + + // get the screen device + m_screen = machine->device<screen_device>(m_config.screen_tag); + assert(m_screen != NULL); + + // register for state saving + save_item(NAME(m_slg)); + save_item(NAME(m_sld)); + save_item(NAME(m_cursor)); + save_item(NAME(m_retbl)); + save_item(NAME(m_vsync)); +} + + +//------------------------------------------------- +// device_clock_changed - handle clock change +//------------------------------------------------- + +void crt9021_device::device_clock_changed() +{ +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void crt9021_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ +} + + +//------------------------------------------------- +// slg_w - scan line gate +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9021_device::slg_w ) +{ + if (LOG) logerror("CRT9021 '%s' SLG: %u\n", tag(), state); + + m_slg = state; +} + + +//------------------------------------------------- +// sld_w - scan line data +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9021_device::sld_w ) +{ + if (LOG) logerror("CRT9021 '%s' SLG: %u\n", tag(), state); + + if (!m_slg) + { + m_sld <<= 1; + m_sld |= state; + } +} + + +//------------------------------------------------- +// cursor_w - cursor +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9021_device::cursor_w ) +{ + if (LOG) logerror("CRT9021 '%s' CURSOR: %u\n", tag(), state); + + m_cursor = state; +} + + +//------------------------------------------------- +// retbl_w - retrace blank +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9021_device::retbl_w ) +{ + if (LOG) logerror("CRT9021 '%s' RETBL: %u\n", tag(), state); + + m_retbl = state; +} + + +//------------------------------------------------- +// vsync_w - vertical sync +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9021_device::vsync_w ) +{ + if (LOG) logerror("CRT9021 '%s' VSYNC: %u\n", tag(), state); + + m_vsync = state; +} + + +//------------------------------------------------- +// update_screen - update screen +//------------------------------------------------- + +void crt9021_device::update_screen(bitmap_t *bitmap, const rectangle *cliprect) +{ +} diff --git a/src/emu/video/crt9021.h b/src/emu/video/crt9021.h new file mode 100644 index 00000000000..20ff301f914 --- /dev/null +++ b/src/emu/video/crt9021.h @@ -0,0 +1,144 @@ +/********************************************************************** + + SMC CRT9021 Video Attributes Controller (VAC) emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + D0 1 |* \_/ | 28 D1 + MS0 2 | | 27 D2 + MS1 3 | | 26 D3 + REVID 4 | | 25 D4 + CHABL 5 | | 24 D5 + BLINK 6 | | 23 D6 + INTIN 7 | CRT9021 | 22 D7 + +5V 8 | | 21 _VSYNC + ATTEN 9 | | 20 GND + INTOUT 10 | | 19 SL0/SLD + CURSOR 11 | | 18 SL1/_SLG + RETBL 12 | | 17 SL2/BLC + _LD/SH 13 | | 16 SL3/BKC + VIDEO 14 |_____________| 15 VDC + +**********************************************************************/ + +#pragma once + +#ifndef __CRT9021__ +#define __CRT9021__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CRT9021_ADD(_tag, _clock, _config) \ + MCFG_DEVICE_ADD(_tag, CRT9021, _clock) \ + MCFG_DEVICE_CONFIG(_config) + + +#define CRT9021_INTERFACE(name) \ + const crt9021_interface (name) = + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> crt9021_interface + +struct crt9021_interface +{ + const char *screen_tag; /* screen we are acting on */ + + devcb_read8 in_data_func; + devcb_read8 in_attr_func; + + devcb_read_line in_atten_func; +}; + + + +// ======================> crt9021_device_config + +class crt9021_device_config : public device_config, + public crt9021_interface +{ + friend class crt9021_device; + + // construction/destruction + crt9021_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); +}; + + + +// ======================> crt9021_device + +class crt9021_device : public device_t +{ + friend class crt9021_device_config; + + // construction/destruction + crt9021_device(running_machine &_machine, const crt9021_device_config &_config); + +public: + DECLARE_WRITE_LINE_MEMBER( slg_w ); + DECLARE_WRITE_LINE_MEMBER( sld_w ); + DECLARE_WRITE_LINE_MEMBER( cursor_w ); + DECLARE_WRITE_LINE_MEMBER( retbl_w ); + DECLARE_WRITE_LINE_MEMBER( vsync_w ); + + void update_screen(bitmap_t *bitmap, const rectangle *cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_clock_changed(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + devcb_resolved_read8 m_in_data_func; + devcb_resolved_read8 m_in_attr_func; + devcb_resolved_read_line m_in_atten_func; + + screen_device *m_screen; + + int m_slg; + int m_sld; + int m_cursor; + int m_retbl; + int m_vsync; + + const crt9021_device_config &m_config; +}; + + +// device type definition +extern const device_type CRT9021; + + + +#endif diff --git a/src/emu/video/crt9212.c b/src/emu/video/crt9212.c new file mode 100644 index 00000000000..0a91fc8948a --- /dev/null +++ b/src/emu/video/crt9212.c @@ -0,0 +1,269 @@ +/********************************************************************** + + SMC CRT9212 Double Row Buffer (DRB) emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "crt9212.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + + +#define REN \ + devcb_call_read_line(&m_in_ren_func) + +#define WEN \ + devcb_call_read_line(&m_in_wen_func) + +#define WEN2 \ + devcb_call_read_line(&m_in_wen2_func) + +#define ROF(_state) \ + devcb_call_write_line(&m_out_rof_func, _state); + +#define WOF(_state) \ + devcb_call_write_line(&m_out_wof_func, _state); + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type CRT9212 = crt9212_device_config::static_alloc_device_config; + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// crt9212_device_config - constructor +//------------------------------------------------- + +crt9212_device_config::crt9212_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) + : device_config(mconfig, static_alloc_device_config, "SMC CRT9212", tag, owner, clock) +{ +} + + +//------------------------------------------------- +// static_alloc_device_config - allocate a new +// configuration object +//------------------------------------------------- + +device_config *crt9212_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) +{ + return global_alloc(crt9212_device_config(mconfig, tag, owner, clock)); +} + + +//------------------------------------------------- +// alloc_device - allocate a new device object +//------------------------------------------------- + +device_t *crt9212_device_config::alloc_device(running_machine &machine) const +{ + return auto_alloc(&machine, crt9212_device(machine, *this)); +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void crt9212_device_config::device_config_complete() +{ + // inherit a copy of the static data + const crt9212_interface *intf = reinterpret_cast<const crt9212_interface *>(static_config()); + if (intf != NULL) + *static_cast<crt9212_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&out_rof_func, 0, sizeof(out_rof_func)); + memset(&out_wof_func, 0, sizeof(out_wof_func)); + memset(&in_ren_func, 0, sizeof(in_ren_func)); + memset(&in_wen_func, 0, sizeof(in_wen_func)); + memset(&in_wen2_func, 0, sizeof(in_wen2_func)); + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// crt9212_device - constructor +//------------------------------------------------- + +crt9212_device::crt9212_device(running_machine &_machine, const crt9212_device_config &config) + : device_t(_machine, config), + m_config(config) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void crt9212_device::device_start() +{ + // resolve callbacks + devcb_resolve_write_line(&m_out_rof_func, &m_config.out_rof_func, this); + devcb_resolve_write_line(&m_out_wof_func, &m_config.out_wof_func, this); + devcb_resolve_read_line(&m_in_ren_func, &m_config.in_ren_func, this); + devcb_resolve_read_line(&m_in_wen_func, &m_config.in_wen_func, this); + devcb_resolve_read_line(&m_in_wen2_func, &m_config.in_wen2_func, this); + + // register for state saving + save_item(NAME(m_input)); + save_item(NAME(m_output)); + save_item(NAME(m_buffer)); + save_item(NAME(m_rac)); + save_item(NAME(m_wac)); + save_item(NAME(m_tog)); + save_item(NAME(m_clrcnt)); + save_item(NAME(m_rclk)); + save_item(NAME(m_wclk)); +} + + +//------------------------------------------------- +// read - buffer read +//------------------------------------------------- + +READ8_MEMBER( crt9212_device::read ) +{ + return m_output; +} + + +//------------------------------------------------- +// write - buffer write +//------------------------------------------------- + +WRITE8_MEMBER( crt9212_device::write ) +{ + m_input = data; +} + + +//------------------------------------------------- +// clrcnt_w - clear address counters +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9212_device::clrcnt_w ) +{ + m_clrcnt = state; +} + + +//------------------------------------------------- +// tog_w - toggle buffer +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9212_device::tog_w ) +{ + m_tog = state; +} + + +//------------------------------------------------- +// rclk_w - read clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9212_device::rclk_w ) +{ + if (m_rclk && !state) + { + if (!m_clrcnt) + { + if (!m_tog) + { + // switch buffer + m_buffer = !m_buffer; + + // clear write address counter + m_wac = 0; + WOF(0); + } + else + { + // clear read address counter + m_rac = 0; + ROF(0); + } + } + else + { + if (REN && (m_rac < CRT9212_RAM_SIZE)) + { + // + m_output = m_ram[m_rac][!m_buffer]; + + // increment read address counter + m_rac++; + + if (m_rac == CRT9212_RAM_SIZE) + { + // set read overflow + ROF(1); + } + } + } + } + + m_rclk = state; +} + + +//------------------------------------------------- +// wclk_w - write clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9212_device::wclk_w ) +{ + if (!m_rclk && state) + { + if (WEN && WEN2 && (m_wac < CRT9212_RAM_SIZE)) + { + // + m_ram[m_rac][m_buffer] = m_input; + + // increment read address counter + m_wac++; + + if (m_wac == CRT9212_RAM_SIZE) + { + // set write overflow + WOF(1); + } + } + } + + m_wclk = state; +} diff --git a/src/emu/video/crt9212.h b/src/emu/video/crt9212.h new file mode 100644 index 00000000000..e89432176ae --- /dev/null +++ b/src/emu/video/crt9212.h @@ -0,0 +1,148 @@ +/********************************************************************** + + SMC CRT9212 Double Row Buffer (DRB) emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + DIN2 1 |* \_/ | 28 DIN3 + DIN1 2 | | 27 _WCLK + DIN0 3 | | 26 _OE + DOUT7 4 | | 25 WEN2 + DOUT6 5 | | 24 WEN1 + DOUT5 6 | | 23 GND + DOUT4 7 | CRT9212 | 22 ROF + Vcc 8 | | 21 WOF + DOUT3 9 | | 20 REN + DOUT2 10 | | 19 _CLRCNT + DOUT1 11 | | 18 _TOG + DOUT0 12 | | 17 _RCLK + DIN7 13 | | 16 DIN4 + DIN6 14 |_____________| 15 DIN5 + +**********************************************************************/ + +#pragma once + +#ifndef __CRT9212__ +#define __CRT9212__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +const int CRT9212_RAM_SIZE = 135; + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CRT9212_ADD(_tag, _config) \ + MCFG_DEVICE_ADD(_tag, CRT9212, 0) \ + MCFG_DEVICE_CONFIG(_config) + + +#define CRT9212_INTERFACE(name) \ + const crt9212_interface (name) = + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> crt9212_interface + +struct crt9212_interface +{ + devcb_write_line out_rof_func; + devcb_write_line out_wof_func; + devcb_read_line in_ren_func; + devcb_read_line in_wen_func; + devcb_read_line in_wen2_func; +}; + + + +// ======================> crt9212_device_config + +class crt9212_device_config : public device_config, + public crt9212_interface +{ + friend class crt9212_device; + + // construction/destruction + crt9212_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); +}; + + + +// ======================> crt9212_device + +class crt9212_device : public device_t +{ + friend class crt9212_device_config; + + // construction/destruction + crt9212_device(running_machine &_machine, const crt9212_device_config &_config); + +public: + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( clrcnt_w ); + DECLARE_WRITE_LINE_MEMBER( tog_w ); + DECLARE_WRITE_LINE_MEMBER( rclk_w ); + DECLARE_WRITE_LINE_MEMBER( wclk_w ); + +protected: + // device-level overrides + virtual void device_start(); + +private: + devcb_resolved_write_line m_out_rof_func; + devcb_resolved_write_line m_out_wof_func; + devcb_resolved_read_line m_in_ren_func; + devcb_resolved_read_line m_in_wen_func; + devcb_resolved_read_line m_in_wen2_func; + + UINT8 m_ram[CRT9212_RAM_SIZE][2]; + + UINT8 m_input; + UINT8 m_output; + + int m_buffer; + int m_rac; + int m_wac; + int m_tog; + int m_clrcnt; + int m_rclk; + int m_wclk; + + const crt9212_device_config &m_config; +}; + + +// device type definition +extern const device_type CRT9212; + + + +#endif diff --git a/src/emu/video/hd61830.c b/src/emu/video/hd61830.c new file mode 100644 index 00000000000..6fceb8014cb --- /dev/null +++ b/src/emu/video/hd61830.c @@ -0,0 +1,600 @@ +/********************************************************************** + + HD61830 LCD Timing Controller emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "hd61830.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +enum +{ + INSTRUCTION_MODE_CONTROL = 0, + INSTRUCTION_CHARACTER_PITCH, + INSTRUCTION_NUMBER_OF_CHARACTERS, + INSTRUCTION_NUMBER_OF_TIME_DIVISIONS, + INSTRUCTION_CURSOR_POSITION, + INSTRUCTION_DISPLAY_START_LOW = 8, + INSTRUCTION_DISPLAY_START_HIGH, + INSTRUCTION_CURSOR_ADDRESS_LOW, + INSTRUCTION_CURSOR_ADDRESS_HIGH, + INSTRUCTION_DISPLAY_DATA_WRITE, + INSTRUCTION_DISPLAY_DATA_READ, + INSTRUCTION_CLEAR_BIT, + INSTRUCTION_SET_BIT +}; + +static const int CYCLES[] = +{ + 4, 4, 4, 4, 4, -1, -1, -1, 4, 4, 4, 4, 6, 6, 36, 36 +}; + +const int MODE_EXTERNAL_CG = 0x01; +const int MODE_GRAPHIC = 0x02; +const int MODE_CURSOR = 0x04; +const int MODE_BLINK = 0x08; +const int MODE_MASTER = 0x10; +const int MODE_DISPLAY_ON = 0x20; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type HD61830 = hd61830_device_config::static_alloc_device_config; + + +// default address map +static ADDRESS_MAP_START( hd61830, AS_0, 8 ) + AM_RANGE(0x0000, 0xffff) AM_RAM +ADDRESS_MAP_END + + +// internal character generator ROM +ROM_START( hd61830 ) + ROM_REGION( 0x5c0, "hd61830", ROMREGION_LOADBYNAME ) // internal 7360-bit chargen ROM + ROM_LOAD( "hd61830.bin", 0x000, 0x5c0, BAD_DUMP CRC(06a934da) SHA1(bf3f074db5dc92e6f530cb18d6c013563099a87d) ) // typed in from manual +ROM_END + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// hd61830_device_config - constructor +//------------------------------------------------- + +hd61830_device_config::hd61830_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) + : device_config(mconfig, static_alloc_device_config, "Hitachi HD61830", tag, owner, clock), + device_config_memory_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(hd61830)) +{ + m_shortname = "hd61830"; +} + + +//------------------------------------------------- +// static_alloc_device_config - allocate a new +// configuration object +//------------------------------------------------- + +device_config *hd61830_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) +{ + return global_alloc(hd61830_device_config(mconfig, tag, owner, clock)); +} + + +//------------------------------------------------- +// alloc_device - allocate a new device object +//------------------------------------------------- + +device_t *hd61830_device_config::alloc_device(running_machine &machine) const +{ + return auto_alloc(&machine, hd61830_device(machine, *this)); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *hd61830_device_config::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *hd61830_device_config::rom_region() const +{ + return ROM_NAME(hd61830); +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void hd61830_device_config::device_config_complete() +{ + // inherit a copy of the static data + const hd61830_interface *intf = reinterpret_cast<const hd61830_interface *>(static_config()); + if (intf != NULL) + *static_cast<hd61830_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&m_in_rd_func, 0, sizeof(m_in_rd_func)); + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 hd61830_device::readbyte(offs_t address) +{ + return space()->read_byte(address); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void hd61830_device::writebyte(offs_t address, UINT8 data) +{ + space()->write_byte(address, data); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// hd61830_device - constructor +//------------------------------------------------- + +hd61830_device::hd61830_device(running_machine &_machine, const hd61830_device_config &config) + : device_t(_machine, config), + device_memory_interface(_machine, config, *this), + m_bf(false), + m_blink(0), + m_config(config) +{ + +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd61830_device::device_start() +{ + // allocate timers + m_busy_timer = timer_alloc(); + + // resolve callbacks + devcb_resolve_read8(&m_in_rd_func, &m_config.m_in_rd_func, this); + + m_screen = machine->device<screen_device>(m_config.screen_tag); + + // register for state saving + save_item(NAME(m_bf)); + save_item(NAME(m_ir)); + save_item(NAME(m_mcr)); + save_item(NAME(m_dor)); + save_item(NAME(m_cac)); + save_item(NAME(m_dsa)); + save_item(NAME(m_vp)); + save_item(NAME(m_hp)); + save_item(NAME(m_hn)); + save_item(NAME(m_nx)); + save_item(NAME(m_cp)); + save_item(NAME(m_blink)); + save_item(NAME(m_cursor)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hd61830_device::device_reset() +{ + // display off, slave mode + m_mcr &= ~(MODE_MASTER | MODE_DISPLAY_ON); + + // default horizontal pitch + m_hp = 6; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void hd61830_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // clear busy flag + m_bf = false; +} + + +/*------------------------------------------------- + set_busy_flag - set busy flag and arm timer + to clear it later +-------------------------------------------------*/ + +void hd61830_device::set_busy_flag() +{ + // set busy flag + m_bf = true; + + // adjust busy timer + m_busy_timer->adjust(attotime::from_usec(CYCLES[m_ir])); +} + + +//------------------------------------------------- +// status_r - status register read +//------------------------------------------------- + +READ8_MEMBER( hd61830_device::status_r ) +{ + if (LOG) logerror("HD61830 '%s' Status Read: %s\n", tag(), m_bf ? "busy" : "ready"); + + return m_bf ? 0x80 : 0; +} + + +//------------------------------------------------- +// control_w - instruction register write +//------------------------------------------------- + +WRITE8_MEMBER( hd61830_device::control_w ) +{ + m_ir = data; +} + + +//------------------------------------------------- +// data_r - data register read +//------------------------------------------------- + +READ8_MEMBER( hd61830_device::data_r ) +{ + UINT8 data = m_dor; + + if (LOG) logerror("HD61830 '%s' Display Data Read %02x\n", tag(), m_dor); + + m_dor = readbyte(m_cac); + + m_cac++; + + return data; +} + + +//------------------------------------------------- +// data_w - data register write +//------------------------------------------------- + +WRITE8_MEMBER( hd61830_device::data_w ) +{ + if (m_bf) + { + logerror("HD61830 '%s' Ignoring data write %02x due to business\n", tag(), data); + return; + } + + switch (m_ir) + { + case INSTRUCTION_MODE_CONTROL: + m_mcr = data; + + if (LOG) + { + logerror("HD61830 '%s' %s CG\n", tag(), (data & MODE_EXTERNAL_CG) ? "External" : "Internal"); + logerror("HD61830 '%s' %s Display Mode\n", tag(), (data & MODE_GRAPHIC) ? "Graphic" : "Character"); + logerror("HD61830 '%s' %s Mode\n", tag(), (data & MODE_MASTER) ? "Master" : "Slave"); + logerror("HD61830 '%s' Cursor %s\n", tag(), (data & MODE_CURSOR) ? "On" : "Off"); + logerror("HD61830 '%s' Blink %s\n", tag(), (data & MODE_BLINK) ? "On" : "Off"); + logerror("HD61830 '%s' Display %s\n", tag(), (data & MODE_DISPLAY_ON) ? "On" : "Off"); + } + break; + + case INSTRUCTION_CHARACTER_PITCH: + m_hp = (data & 0x07) + 1; + m_vp = (data >> 4) + 1; + + if (LOG) logerror("HD61830 '%s' Horizontal Character Pitch: %u\n", tag(), m_hp); + if (LOG) logerror("HD61830 '%s' Vertical Character Pitch: %u\n", tag(), m_vp); + break; + + case INSTRUCTION_NUMBER_OF_CHARACTERS: + m_hn = (data & 0x7f) + 1; + + if (LOG) logerror("HD61830 '%s' Number of Characters: %u\n", tag(), m_hn); + break; + + case INSTRUCTION_NUMBER_OF_TIME_DIVISIONS: + m_nx = (data & 0x7f) + 1; + + if (LOG) logerror("HD61830 '%s' Number of Time Divisions: %u\n", tag(), m_nx); + break; + + case INSTRUCTION_CURSOR_POSITION: + m_cp = (data & 0x7f) + 1; + + if (LOG) logerror("HD61830 '%s' Cursor Position: %u\n", tag(), m_cp); + break; + + case INSTRUCTION_DISPLAY_START_LOW: + m_dsa = (m_dsa & 0xff00) | data; + + if (LOG) logerror("HD61830 '%s' Display Start Address Low %04x\n", tag(), m_dsa); + break; + + case INSTRUCTION_DISPLAY_START_HIGH: + m_dsa = (data << 8) | (m_dsa & 0xff); + + if (LOG) logerror("HD61830 '%s' Display Start Address High %04x\n", tag(), m_dsa); + break; + + case INSTRUCTION_CURSOR_ADDRESS_LOW: + if (BIT(m_cac, 7) && !BIT(data, 7)) + { + m_cac = (((m_cac >> 8) + 1) << 8) | data; + } + else + { + m_cac = (m_cac & 0xff00) | data; + } + + if (LOG) logerror("HD61830 '%s' Cursor Address Low %02x: %04x\n", tag(), data, m_cac); + break; + + case INSTRUCTION_CURSOR_ADDRESS_HIGH: + m_cac = (data << 8) | (m_cac & 0xff); + + if (LOG) logerror("HD61830 '%s' Cursor Address High %02x: %04x\n", tag(), data, m_cac); + break; + + case INSTRUCTION_DISPLAY_DATA_WRITE: + writebyte(m_cac, data); + + if (LOG) logerror("HD61830 '%s' Display Data Write %02x -> %04x row %u col %u\n", tag(), data, m_cac, m_cac / 40, m_cac % 40); + + m_cac++; + break; + + case INSTRUCTION_CLEAR_BIT: + { + int bit = data & 0x07; + UINT8 md = readbyte(m_cac); + + md &= ~(1 << bit); + + if (LOG) logerror("HD61830 '%s' Clear Bit %u at %04x\n", tag(), bit + 1, m_cac); + + writebyte(m_cac, md); + + m_cac++; + } + break; + + case INSTRUCTION_SET_BIT: + { + int bit = data & 0x07; + UINT8 md = readbyte(m_cac); + + md |= 1 << bit; + + if (LOG) logerror("HD61830 '%s' Set Bit %u at %04x\n", tag(), bit + 1, m_cac); + + writebyte(m_cac, md); + + m_cac++; + } + break; + + default: + logerror("HD61830 '%s' Illegal Instruction %02x!\n", tag(), m_ir); + return; + } + + // burn cycles + set_busy_flag(); +} + + +//------------------------------------------------- +// draw_scanline - draw one graphics scanline +//------------------------------------------------- + +void hd61830_device::draw_scanline(bitmap_t *bitmap, const rectangle *cliprect, int y, UINT16 ra) +{ + for (int sx = 0; sx < m_hn; sx++) + { + UINT8 data = readbyte(ra++); + + for (int x = 0; x < m_hp; x++) + { + *BITMAP_ADDR16(bitmap, y, (sx * m_hp) + x) = BIT(data, x); + } + } +} + + +//------------------------------------------------- +// update_graphics - draw graphics mode screen +//------------------------------------------------- + +void hd61830_device::update_graphics(bitmap_t *bitmap, const rectangle *cliprect) +{ + for (int y = 0; y < m_nx; y++) + { + UINT16 rac1 = m_dsa + (y * m_hn); + UINT16 rac2 = rac1 + (m_nx * m_hn); + + /* draw upper half scanline */ + draw_scanline(bitmap, cliprect, y, rac1); + + /* draw lower half scanline */ + draw_scanline(bitmap, cliprect, y + m_nx, rac2); + } +} + + +//------------------------------------------------- +// draw_char - draw a char +//------------------------------------------------- + +void hd61830_device::draw_char(bitmap_t *bitmap, const rectangle *cliprect, UINT16 ma, int x, int y, UINT8 md) +{ + for (int cl = 0; cl < m_vp; cl++) + { + for (int cr = 0; cr < m_hp; cr++) + { + int sy = y * m_vp + cl; + int sx = x * m_hp + cr; + UINT8 data = 0; + + if (m_mcr & MODE_EXTERNAL_CG) + { + data = devcb_call_read8(&m_in_rd_func, (cl << 12) | md); + } + else + { + UINT16 addr = 0; + + if (md >= 0x20 && md < 0x80 && cl < 7) + { + // 5x7 characters 0x20..0x7f + addr = (md - 0x20) * 7 + cl; + } + else if (md >= 0xa0 && md < 0xe0 && cl < 7) + { + // 5x7 characters 0xa0..0xdf + addr = 96*7 + (md - 0xa0) * 7 + cl; + } + else if (md >= 0xe0 && cl < 11) + { + // 5x11 characters 0xe0..0xff + addr = 160*7 + (md - 0xe0) * 11 + cl; + } + + data = subregion("hd61830")->u8(addr); + } + + int cursor = m_mcr & MODE_CURSOR; + int blink = m_mcr & MODE_BLINK; + + // cursor off + int pixel = BIT(data, cr); + + if (blink && (ma == m_cac)) + { + // cursor off, character blink + if (!cursor) + pixel = m_cursor ? pixel : 0; + + // cursor blink + if (cursor && (cl == m_cp)) + pixel = m_cursor ? 1 : 0; + } + else + { + // cursor on + if (cursor && (cl == m_cp)) + pixel = m_cursor ? 1 : 0; + } + + if (sy < m_screen->height() && sx < m_screen->width()) + *BITMAP_ADDR16(bitmap, sy, sx) = pixel; + } + } +} + + +//------------------------------------------------- +// update_text - draw text mode screen +//------------------------------------------------- + +void hd61830_device::update_text(bitmap_t *bitmap, const rectangle *cliprect) +{ + for (int y = 0; y < (m_nx / m_vp); y++) + { + for (int x = 0; x < m_hn; x++) + { + UINT16 ma = y * m_hn + x; + UINT8 md = readbyte(ma); + + draw_char(bitmap, cliprect, ma, x, y, md); + } + } +} + + +//------------------------------------------------- +// update_screen - update screen +//------------------------------------------------- + +void hd61830_device::update_screen(bitmap_t *bitmap, const rectangle *cliprect) +{ + if (m_mcr & MODE_DISPLAY_ON) + { + if (m_mcr & MODE_GRAPHIC) + { + update_graphics(bitmap, cliprect); + } + else + { + update_text(bitmap, cliprect); + } + } + else + { + bitmap_fill(bitmap, cliprect, 0); + } + + m_blink++; + + if (m_blink == 0x20) + { + m_blink = 0; + m_cursor = !m_cursor; + } +} diff --git a/src/emu/video/hd61830.h b/src/emu/video/hd61830.h new file mode 100644 index 00000000000..12c793af5b1 --- /dev/null +++ b/src/emu/video/hd61830.h @@ -0,0 +1,156 @@ +/********************************************************************** + + HD61830 LCD Timing Controller emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#pragma once + +#ifndef __HD61830__ +#define __HD61830__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_HD61830_ADD(_tag, _clock, _config) \ + MCFG_DEVICE_ADD(_tag, HD61830, _clock) \ + MCFG_DEVICE_CONFIG(_config) + + +#define HD61830_INTERFACE(name) \ + const hd61830_interface (name) = + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> hd61830_interface + +struct hd61830_interface +{ + const char *screen_tag; + + devcb_read8 m_in_rd_func; +}; + + + +// ======================> hd61830_device_config + +class hd61830_device_config : public device_config, + public device_config_memory_interface, + public hd61830_interface +{ + friend class hd61830_device; + + // construction/destruction + hd61830_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + + // optional information overrides + virtual const rom_entry *rom_region() const; + +protected: + // device_config overrides + virtual void device_config_complete(); + + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // address space configurations + const address_space_config m_space_config; +}; + + + +// ======================> hd61830_device + +class hd61830_device : public device_t, + public device_memory_interface +{ + friend class hd61830_device_config; + + // construction/destruction + hd61830_device(running_machine &_machine, const hd61830_device_config &_config); + +public: + DECLARE_READ8_MEMBER( status_r ); + DECLARE_WRITE8_MEMBER( control_w ); + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + + void update_screen(bitmap_t *bitmap, const rectangle *cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + inline UINT8 readbyte(offs_t address); + inline void writebyte(offs_t address, UINT8 data); + +private: + void set_busy_flag(); + + void draw_scanline(bitmap_t *bitmap, const rectangle *cliprect, int y, UINT16 ra); + void update_graphics(bitmap_t *bitmap, const rectangle *cliprect); + void draw_char(bitmap_t *bitmap, const rectangle *cliprect, UINT16 ma, int x, int y, UINT8 md); + void update_text(bitmap_t *bitmap, const rectangle *cliprect); + + devcb_resolved_read8 m_in_rd_func; + + screen_device *m_screen; + emu_timer *m_busy_timer; + address_space *m_data; + + bool m_bf; // busy flag + + UINT8 m_ir; // instruction register + UINT8 m_mcr; // mode control register + UINT8 m_dor; // data output register + + UINT16 m_dsa; // display start address + UINT16 m_cac; // cursor address counter + + int m_vp; // vertical character pitch + int m_hp; // horizontal character pitch + int m_hn; // horizontal number of characters + int m_nx; // number of time divisions + int m_cp; // cursor position + + int m_blink; // blink counter + int m_cursor; // cursor visible + + const hd61830_device_config &m_config; +}; + + +// device type definition +extern const device_type HD61830; + + + +#endif |