From f2407286b14d2fad789a207045cba2a0e20c94dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Corr=C3=AAa=20da=20Silva=20Sanches?= Date: Tue, 22 Aug 2017 22:53:00 -0300 Subject: new drivers for "Control ID x628" fingerprint-reader and for the NT7534 LCD controller (#2583) * initial skelethon: ControlID X628 fingerprint reader * first draft of an implementation of the NT7534 device (LCD controller) * fix emulation of ControlID x628 + NT7534 LCD controller * cidx628: fix LCD color palette on Control ID x628 driver * Adding a header with details of the hardware. This is the first MAME driver with an LCD controlled by a NT7534 chip, so I wrote an initial implementation of that new device. --- scripts/src/video.lua | 12 ++ scripts/target/mame/mess.lua | 2 + src/devices/video/nt7534.cpp | 355 +++++++++++++++++++++++++++++++++++++++++ src/devices/video/nt7534.h | 93 +++++++++++ src/mame/drivers/controlid.cpp | 136 ++++++++++++++++ src/mame/mame.lst | 3 + 6 files changed, 601 insertions(+) create mode 100644 src/devices/video/nt7534.cpp create mode 100644 src/devices/video/nt7534.h create mode 100644 src/mame/drivers/controlid.cpp diff --git a/scripts/src/video.lua b/scripts/src/video.lua index 5bf85c6650d..f883a45f592 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -268,6 +268,18 @@ if (VIDEOS["MGA2064W"]~=null) then } end +-------------------------------------------------- +-- +--@src/devices/video/nt7534.h,VIDEOS["NT7534"] = true +-------------------------------------------------- + +if (VIDEOS["NT7534"]~=null) then + files { + MAME_DIR .. "src/devices/video/nt7534.cpp", + MAME_DIR .. "src/devices/video/nt7534.h", + } +end + -------------------------------------------------- -- --@src/devices/video/hd44102.h,VIDEOS["HD44102"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index e985419a17e..be5ab241ff1 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -294,6 +294,7 @@ VIDEOS["EF9365"] = true VIDEOS["GF4500"] = true --VIDEOS+= EPIC12"] = true --VIDEOS+= FIXFREQ"] = true +VIDEOS["NT7534"] = true VIDEOS["HD44102"] = true VIDEOS["HD44352"] = true VIDEOS["HD44780"] = true @@ -3411,6 +3412,7 @@ files { MAME_DIR .. "src/mame/drivers/cd2650.cpp", MAME_DIR .. "src/mame/drivers/cdc721.cpp", MAME_DIR .. "src/mame/drivers/codata.cpp", + MAME_DIR .. "src/mame/drivers/controlid.cpp", MAME_DIR .. "src/mame/drivers/cortex.cpp", MAME_DIR .. "src/mame/drivers/cosmicos.cpp", MAME_DIR .. "src/mame/includes/cosmicos.h", diff --git a/src/devices/video/nt7534.cpp b/src/devices/video/nt7534.cpp new file mode 100644 index 00000000000..543115f8fe8 --- /dev/null +++ b/src/devices/video/nt7534.cpp @@ -0,0 +1,355 @@ +// license:BSD-3-Clause +// copyright-holders:Felipe Sanches, Sandro Ronco +/*************************************************************************** + + NT7534 LCD controller + + TODO: + - determine video timings and busy flag duration + +***************************************************************************/ + +#include "emu.h" +#include "video/nt7534.h" + +#define VERBOSE 1 +#include "logmacro.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(NT7534, nt7534_device, "nt7534", "NT7534 LCD Controller") + + +//------------------------------------------------- +// nt7534_device - constructor +//------------------------------------------------- + +nt7534_device::nt7534_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : nt7534_device(mconfig, NT7534, tag, owner, clock) +{ +} + +nt7534_device::nt7534_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nt7534_device::device_start() +{ + m_busy_timer = timer_alloc(TIMER_BUSY); + + // state saving + save_item(NAME(m_busy_flag)); + save_item(NAME(m_page)); + save_item(NAME(m_column)); + save_item(NAME(m_dr)); + save_item(NAME(m_ir)); + save_item(NAME(m_display_on)); + save_item(NAME(m_display_start_line)); + save_item(NAME(m_direction)); + save_item(NAME(m_data_len)); + save_item(NAME(m_ddram)); + save_item(NAME(m_nibble)); + save_item(NAME(m_rs_state)); + save_item(NAME(m_rw_state)); + save_item(NAME(m_backup_column)); + save_item(NAME(m_read_modify_write)); + save_item(NAME(m_adc)); + save_item(NAME(m_reverse)); + save_item(NAME(m_entire_display_on)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nt7534_device::device_reset() +{ + memset(m_ddram, 0x00, sizeof(m_ddram)); + + m_page = 0; + m_column = 0; + m_dr = 0; + m_ir = 0; + m_display_on = false; + m_entire_display_on = false; + m_direction = 1; + m_adc = true; + m_read_modify_write = false; + m_reverse = false; + m_data_len = 8; + m_nibble = false; + m_rs_state = 0; + m_rw_state = 0; + + set_busy_flag(1520); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nt7534_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_BUSY: + m_busy_flag = false; + break; + } +} + + +//************************************************************************** +// HELPERS +//************************************************************************** + +void nt7534_device::set_busy_flag(uint16_t usec) +{ + m_busy_flag = true; + m_busy_timer->adjust( attotime::from_usec( usec ) ); +} + +void nt7534_device::update_nibble(int rs, int rw) +{ + if (m_rs_state != rs || m_rw_state != rw) + { + m_rs_state = rs; + m_rw_state = rw; + m_nibble = false; + } + + m_nibble = !m_nibble; +} + +//************************************************************************** +// device interface +//************************************************************************** + +uint32_t nt7534_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + bitmap.fill(0, cliprect); + + for (uint16_t x = 0; x < 132; x++) + { + uint16_t px = m_adc ? x : 131 - x; + for (uint8_t y = 0; y < 65; y++) + { + uint8_t py = (y + m_display_start_line - 32) % 65; + uint8_t page = py/8; + bitmap.pix16(y, x) = BIT(m_ddram[page*132 + px], py%8); + } + } + + return 0; +} + +READ8_MEMBER(nt7534_device::read) +{ + switch (offset & 0x01) + { + case 0: return control_read(space, 0); + case 1: return data_read(space, 0); + } + + return 0; +} + +WRITE8_MEMBER(nt7534_device::write) +{ + switch (offset & 0x01) + { + case 0: control_write(space, 0, data); break; + case 1: data_write(space, 0, data); break; + } +} + +WRITE8_MEMBER(nt7534_device::control_write) +{ + if (m_data_len == 4) + { + update_nibble(0, 0); + + if (m_nibble) + { + m_ir = data & 0xF0; + return; + } + else + { + m_ir |= ((data >> 4) & 0x0F); + } + } + else + { + m_ir = data; + } + + if (m_ir == 0xE2) + { + // Reset + memset(m_ddram, 0x00, sizeof(m_ddram)); + m_page = 0; + m_column = 0; + LOG("NT7534: Reset \n"); + return; + } + else if ((m_ir & 0xFE) == 0xAE) + { + // Display ON/OFF + m_display_on = m_ir & 1; + LOG("NT7534: Display %s\n", m_display_on ? "ON" : "OFF"); + return; + } + else if ((m_ir & 0xC0) == 0x40) + { + // Display Start Line Set + m_display_start_line = m_ir & 0x3F; + LOG("NT7534: Display Start Line: %d\n", m_display_start_line); + return; + } + else if ((m_ir & 0xF0) == 0xB0) + { + // set Page Address + m_page = m_ir & 0x0F; + + LOG("NT7534: set Page address %x\n", m_page); + return; + } + else if ((m_ir & 0xF0) == 0x10) + { + // Set column address MSB + m_column = (m_column & 0x0F) | ((m_ir & 0x0F) << 4); + + LOG("NT7534: set column address MSB %x\n", (m_column >> 4) & 0x0F); + return; + } + else if ((m_ir & 0xF0) == 0x00) + { + // Set column address LSB + m_column = (m_column & 0xF0) | (m_ir & 0x0F); + + LOG("NT7534: set column address LSB %x\n", m_column & 0x0F); + return; + } + else if ((m_ir & 0xFE) == 0xA0) + { + // ADC Select + m_adc = m_ir & 1; + LOG("NT7534: ADC: %d\n", m_adc); + return; + } + else if ((m_ir & 0xFE) == 0xA6) + { + // Normal/Reverse Display + m_reverse = m_ir & 1; + LOG("NT7534: Display Reverse ? %s\n", m_reverse ? "Yes" : "No"); + return; + } + else if ((m_ir & 0xFE) == 0xA4) + { + // Entire display ON + m_entire_display_on = m_ir & 1; + LOG("NT7534: Entire Display ON ? %s\n", m_entire_display_on ? "Yes" : "No"); + return; + } + else if (m_ir == 0xE0) + { + // Enable Read-Modify-Write + m_read_modify_write = true; + m_backup_column = m_column; + LOG("NT7534: Enable Read-Modify-Write. Backup column: %d\n", m_backup_column); + return; + } + else if (m_ir == 0xEE) + { + // Disable Read-Modify-Write + m_read_modify_write = false; + m_column = m_backup_column; // restore column value + LOG("NT7534: Disable Read-Modify-Write.\n"); + return; + } +} + +READ8_MEMBER(nt7534_device::control_read) +{ + if (m_data_len == 4) + { + if (!machine().side_effect_disabled()) + update_nibble(0, 1); + + if (m_nibble) + return (m_busy_flag ? 0x80 : 0); + else + return 0; //TODO: review this. + } + else + { + return (m_busy_flag ? 0x80 : 0); + } +} + +WRITE8_MEMBER(nt7534_device::data_write) +{ +// if (m_busy_flag) +// { +// logerror("NT7534: Ignoring data write %02x due to busy flag\n", data); +// return; +// } + + if (m_data_len == 4) + { + update_nibble(1, 0); + + if (m_nibble) + { + m_dr = data & 0xF0; + return; + } + else + { + m_dr |= ((data >> 4) & 0x0F); + } + } + else + { + m_dr = data; + } + + LOG("NT7534: RAM write %x %x '%c'\n", m_page*132 + m_column, m_dr, isprint(m_dr) ? m_dr : '.'); + + m_ddram[m_page*132 + m_column] = m_dr; + + if (m_column < 131) + m_column++; + + set_busy_flag(41); +} + +READ8_MEMBER(nt7534_device::data_read) +{ + uint8_t data = m_ddram[m_page*132 + m_column]; + if (m_read_modify_write == false && m_column < 131) + m_column++; + + if (m_data_len == 4) + { + if (!machine().side_effect_disabled()) + update_nibble(1, 1); + + if (m_nibble) + return data & 0xF0; + else + data = (data << 4) & 0xF0; + } + + return data; +} diff --git a/src/devices/video/nt7534.h b/src/devices/video/nt7534.h new file mode 100644 index 00000000000..198e6291157 --- /dev/null +++ b/src/devices/video/nt7534.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Felipe Sanches, Sandro Ronco +/*************************************************************************** + + NT7534 LCD controller + +***************************************************************************/ + +#ifndef MAME_VIDEO_NT7534_H +#define MAME_VIDEO_NT7534_H + +#pragma once + + +#define MCFG_NT7534_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, NT7534, 0 ) + +#define MCFG_NT7534_PIXEL_UPDATE_CB(_class, _method) \ + nt7534_device::static_set_pixel_update_cb(*device, nt7534_device::pixel_update_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +#define NT7534_PIXEL_UPDATE(name) void name(bitmap_ind16 &bitmap, uint8_t line, uint8_t pos, uint8_t y, uint8_t x, int state) + + +// ======================> nt7534_device + +class nt7534_device : public device_t +{ +public: + typedef device_delegate pixel_update_delegate; + + // construction/destruction + nt7534_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + static void static_set_pixel_update_cb(device_t &device, pixel_update_delegate &&cb) { downcast(device).m_pixel_update_cb = std::move(cb); } + + // device interface + virtual DECLARE_WRITE8_MEMBER(write); + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(control_write); + virtual DECLARE_READ8_MEMBER(control_read); + virtual DECLARE_WRITE8_MEMBER(data_write); + virtual DECLARE_READ8_MEMBER(data_read); + + const uint8_t *render(); + virtual uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + nt7534_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; +private: + // internal helper + void set_busy_flag(uint16_t usec); + void update_nibble(int rs, int rw); + + // internal state + static constexpr device_timer_id TIMER_BUSY = 0; + + emu_timer * m_busy_timer; + + pixel_update_delegate m_pixel_update_cb; // pixel update callback + + bool m_busy_flag; + uint8_t m_ddram[9*132]; // internal display data RAM + uint8_t m_page; // page address + uint16_t m_column; // column address + uint16_t m_backup_column; // column address + uint8_t m_display_start_line; + uint8_t m_dr; // data register + uint8_t m_ir; // instruction register + bool m_display_on; // display on/off + bool m_entire_display_on; + bool m_reverse; // Reverse display + bool m_read_modify_write; + bool m_adc; + int m_direction; // auto increment/decrement (-1 or +1) + uint8_t m_data_len; // interface data length 4 or 8 bit + int m_rs_state; + int m_rw_state; + bool m_nibble; +}; + +// device type definition +DECLARE_DEVICE_TYPE(NT7534, nt7534_device) + +#endif // MAME_VIDEO_NT7534_H diff --git a/src/mame/drivers/controlid.cpp b/src/mame/drivers/controlid.cpp new file mode 100644 index 00000000000..835488230cd --- /dev/null +++ b/src/mame/drivers/controlid.cpp @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holder:FelipeSanches +// +// Control ID x628 +// +// This is a fingerprint reader device +// +// TODO: Emulate the other CPU board (supposedly runs the Linux kernel on +// a dedicated SoC targeting image-processing typically used on +// fingerprint readers). The SoC is labelled ZKSoftware ZK6001 +// and someone online suggested it may be a rebranded device from +// Ingenic, so likely a MIPS32 or MIPS64. +// +// It has a 32Mb flash-rom and an ethernet controller +// (model is Realtek RTL8201BL) +// +// While the 8051 board has a tiny buzzer (and a battery-backed RAM) +// the other PCB interfaces with an audio speaker. +// +// There's also an RJ45 connector (ethernet port) as well as a +// DB9 connector which seems to be used for a serial interface. +// +// Finally, there are 2 LEDs, a 128x64 LCD with blueish backlight +// and a keypad with the following layout: +// +// 1 2 3 ESC +// 4 5 6 MENU +// 7 8 9 UP-ARROW +// . 0 OK DOWN-ARROW + +#include "emu.h" +#include "cpu/mcs51/mcs51.h" +#include "video/nt7534.h" +#include "screen.h" + +class controlidx628_state : public driver_device +{ +public: + controlidx628_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_lcdc(*this, "nt7534") { } + DECLARE_WRITE8_MEMBER( p0_w ); + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_PALETTE_INIT( controlidx628 ); + + required_device m_lcdc; +private: + uint8_t p0_data; + uint8_t p1_data; +}; + + +/************************* +* Memory map information * +*************************/ + +static ADDRESS_MAP_START( prog_map, AS_PROGRAM, 8, controlidx628_state ) + AM_RANGE(0x0000, 0x1fff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( io_map, AS_IO, 8, controlidx628_state ) + AM_RANGE(0x8000, 0xffff) AM_RAM + +// /* Ports start here */ + AM_RANGE(MCS51_PORT_P0, MCS51_PORT_P0) AM_WRITE(p0_w) + AM_RANGE(MCS51_PORT_P1, MCS51_PORT_P1) AM_WRITE(p1_w) +// AM_RANGE(MCS51_PORT_P2, MCS51_PORT_P2) AM_RAM +// AM_RANGE(MCS51_PORT_P3, MCS51_PORT_P3) AM_RAM +ADDRESS_MAP_END + + +WRITE8_MEMBER( controlidx628_state::p0_w ) +{ + p0_data = data; +} + +WRITE8_MEMBER( controlidx628_state::p1_w ) +{ + if ((BIT(p1_data, 6) == 0) && (BIT(data, 6) == 1)) // on raising-edge of bit 6 + { + m_lcdc->write(space, BIT(data, 7), p0_data); + } + p1_data = data; +} + +/************************* +* Input ports * +*************************/ + +//static INPUT_PORTS_START( controlidx628 ) +//INPUT_PORTS_END + +PALETTE_INIT_MEMBER(controlidx628_state, controlidx628) +{ + // These colors were selected from a photo of the display + // using the color-picker in Inkscape: + palette.set_pen_color(0, rgb_t(0x06, 0x61, 0xEE)); + palette.set_pen_color(1, rgb_t(0x00, 0x23, 0x84)); +} + +/************************* +* Machine Driver * +*************************/ + +static MACHINE_CONFIG_START( controlidx628 ) + // basic machine hardware + MCFG_CPU_ADD("maincpu", I80C32, XTAL_11_0592MHz) /* Actually the board has an Atmel AT89S52 mcu. */ + MCFG_CPU_PROGRAM_MAP(prog_map) + MCFG_CPU_IO_MAP(io_map) + + /* video hardware */ + MCFG_SCREEN_ADD("screen", LCD) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ + MCFG_SCREEN_SIZE(132, 65) + MCFG_SCREEN_VISIBLE_AREA(3, 130, 0, 63) + MCFG_SCREEN_UPDATE_DEVICE("nt7534", nt7534_device, screen_update) + MCFG_SCREEN_PALETTE("palette") + + MCFG_PALETTE_ADD("palette", 2) + MCFG_PALETTE_INIT_OWNER(controlidx628_state, controlidx628) + + MCFG_NT7534_ADD("nt7534") +MACHINE_CONFIG_END + + +/************************* +* Rom Load * +*************************/ + +ROM_START( cidx628 ) + ROM_REGION( 0x2000, "maincpu", 0 ) + ROM_LOAD( "controlid_x628.u1", 0x0000, 0x2000, CRC(500d79b4) SHA1(5522115f2da622db389e067fcdd4bccb7aa8561a) ) +ROM_END + +COMP(200?, cidx628, 0, 0, controlidx628, 0, controlidx628_state, 0, "ControlID", "X628", MACHINE_NOT_WORKING|MACHINE_NO_SOUND) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index e52a59a3bb6..201c680f451 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -32017,6 +32017,9 @@ qtsbc // @source:quakeat.cpp quake // (c) 19?? Lazer-Tron / iD Software +@source:controlid.cpp +cidx628 // 200? Control ID X628 + @source:quantum.cpp quantum // 136016 (c) 1982 // made by Gencomp quantum1 // 136016 (c) 1982 // made by Gencomp -- cgit v1.2.3