sed1200: Modernize emulation

- Reduce bus to 4 bits (but note that an 8-bit variant exists), and add CS write handler to ensure multiple writes go to the correct nibbles. This results in considerable uglification of the mt32 driver code, but is more hardware-accurate.
- Speculatively eliminate cursor wraparound at first and last positions. This may or may not be accurate, but seems to produce neater results.
- Save state of internal variables.
This commit is contained in:
AJR 2023-06-09 21:00:50 -04:00
parent feea04e882
commit c1f4b4600a
3 changed files with 104 additions and 29 deletions

View File

@ -4,7 +4,9 @@
SED1200
A LCD controller.
A LCD controller similar to HD44780/SED1278 that drives a 20-character
display. Data input is 4 bits at a time. (SED1210 has a 40-character
display and 8-bit data input.)
The D/F variants have a packaging difference (QFP80 vs. bare chip).
@ -16,10 +18,10 @@
#include "emu.h"
#include "sed1200.h"
DEFINE_DEVICE_TYPE(SED1200D0A, sed1200d0a_device, "sed1200da", "Epson SED1200D-0A")
DEFINE_DEVICE_TYPE(SED1200F0A, sed1200f0a_device, "sed1200fa", "Epson SED1200F-0A")
DEFINE_DEVICE_TYPE(SED1200D0B, sed1200d0b_device, "sed1200db", "Epson SED1200D-0B")
DEFINE_DEVICE_TYPE(SED1200F0B, sed1200f0b_device, "sed1200fb", "Epson SED1200F-0B")
DEFINE_DEVICE_TYPE(SED1200D0A, sed1200d0a_device, "sed1200da", "Epson SED1200D-0A LCD Controller")
DEFINE_DEVICE_TYPE(SED1200F0A, sed1200f0a_device, "sed1200fa", "Epson SED1200F-0A LCD Controller")
DEFINE_DEVICE_TYPE(SED1200D0B, sed1200d0b_device, "sed1200db", "Epson SED1200D-0B LCD Controller")
DEFINE_DEVICE_TYPE(SED1200F0B, sed1200f0b_device, "sed1200fb", "Epson SED1200F-0B LCD Controller")
ROM_START( sed1200x0a )
ROM_REGION( 0x800, "cgrom", 0 )
@ -31,28 +33,40 @@ ROM_START( sed1200x0b )
ROM_LOAD( "sed1200-b.bin", 0x000, 0x800, CRC(d0741f51) SHA1(c8c856f1357286a2c8c806af81724a828345357e))
ROM_END
sed1200_device::sed1200_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock), cursor_direction(false), cursor_blinking(false), cursor_full(false), cursor_on(false), display_on(false), cursor_address(0), cgram_address(0), cgrom(nullptr)
sed1200_device::sed1200_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, cursor_direction(false)
, cursor_blinking(false)
, cursor_full(false)
, cursor_on(false)
, display_on(false)
, two_lines(false)
, cursor_address(0)
, cgram_address(0)
, cgrom(nullptr)
, chip_select(false)
, first_input(false)
, first_data(0)
{
}
sed1200d0a_device::sed1200d0a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
sed1200_device(mconfig, SED1200D0A, tag, owner, clock)
sed1200d0a_device::sed1200d0a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: sed1200_device(mconfig, SED1200D0A, tag, owner, clock)
{
}
sed1200f0a_device::sed1200f0a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
sed1200_device(mconfig, SED1200F0A, tag, owner, clock)
sed1200f0a_device::sed1200f0a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: sed1200_device(mconfig, SED1200F0A, tag, owner, clock)
{
}
sed1200d0b_device::sed1200d0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
sed1200_device(mconfig, SED1200D0B, tag, owner, clock)
sed1200d0b_device::sed1200d0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: sed1200_device(mconfig, SED1200D0B, tag, owner, clock)
{
}
sed1200f0b_device::sed1200f0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
sed1200_device(mconfig, SED1200F0B, tag, owner, clock)
sed1200f0b_device::sed1200f0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: sed1200_device(mconfig, SED1200F0B, tag, owner, clock)
{
}
@ -85,9 +99,33 @@ void sed1200_device::device_start()
else
cgrom = nullptr;
chip_select = false;
save_item(NAME(cgram));
save_item(NAME(ddram));
save_item(NAME(cursor_direction));
save_item(NAME(cursor_blinking));
save_item(NAME(cursor_full));
save_item(NAME(cursor_on));
save_item(NAME(display_on));
save_item(NAME(two_lines));
save_item(NAME(cursor_address));
save_item(NAME(cgram_address));
save_item(NAME(chip_select));
save_item(NAME(first_input));
save_item(NAME(first_data));
soft_reset();
}
void sed1200_device::cs_w(int state)
{
if (chip_select != !state) {
chip_select = !state;
first_input = true;
}
}
void sed1200_device::soft_reset()
{
cursor_direction = false;
@ -95,11 +133,23 @@ void sed1200_device::soft_reset()
cursor_full = false;
cursor_on = false;
display_on = false;
two_lines = false;
cursor_address = 0x00;
cgram_address = 0x00;
}
void sed1200_device::control_w(uint8_t data)
{
if(chip_select) {
if(first_input)
first_data = data & 0x0f;
else
control_write(first_data << 4 | (data & 0x0f));
first_input = !first_input;
}
}
void sed1200_device::control_write(uint8_t data)
{
switch(data) {
case 0x04: case 0x05:
@ -124,7 +174,8 @@ void sed1200_device::control_w(uint8_t data)
soft_reset();
break;
case 0x12: case 0x13:
break; // Number of lines selection
two_lines = data & 0x01;
break;
default:
if((data & 0xf0) == 0x20)
cgram_address = (data & 3)*8;
@ -133,19 +184,34 @@ void sed1200_device::control_w(uint8_t data)
if(cgram_address == 4*8)
cgram_address = 0;
} else if(data & 0x80) {
cursor_address = data & 0x40 ? 10 : 0;
cursor_address += (data & 0x3f) >= 10 ? 9 : data & 0x3f;
if (two_lines) {
cursor_address = data & 0x40 ? 10 : 0;
cursor_address += (data & 0x3f) >= 10 ? 9 : data & 0x3f;
} else
cursor_address = (data & 0x3f) >= 20 ? 19 : data & 0x3f;
}
break;
}
}
uint8_t sed1200_device::control_r()
uint8_t sed1200_device::busy_r()
{
// TODO: bit 3 = busy flag
return 0x00;
}
void sed1200_device::data_w(uint8_t data)
{
if(chip_select) {
if(first_input)
first_data = data & 0x0f;
else
data_write(first_data << 4 | (data & 0x0f));
first_input = !first_input;
}
}
void sed1200_device::data_write(uint8_t data)
{
ddram[cursor_address] = data;
cursor_step();
@ -154,14 +220,10 @@ void sed1200_device::data_w(uint8_t data)
void sed1200_device::cursor_step()
{
if(cursor_direction) {
if(cursor_address == 0 || cursor_address == 10)
cursor_address += 9;
else
if(cursor_address != 0 && (!two_lines || cursor_address != 10))
cursor_address --;
} else {
if(cursor_address == 9 || cursor_address == 19)
cursor_address -= 9;
else
if((!two_lines || cursor_address != 9) && cursor_address != 19)
cursor_address ++;
}
}

View File

@ -20,8 +20,9 @@
class sed1200_device : public device_t {
public:
void cs_w(int state);
void control_w(uint8_t data);
uint8_t control_r();
uint8_t busy_r();
void data_w(uint8_t data);
const uint8_t *render();
@ -35,10 +36,16 @@ private:
uint8_t cgram[4*8];
uint8_t ddram[10*2];
uint8_t render_buf[20*8];
bool cursor_direction, cursor_blinking, cursor_full, cursor_on, display_on;
bool cursor_direction, cursor_blinking, cursor_full, cursor_on, display_on, two_lines;
uint8_t cursor_address, cgram_address;
const uint8_t *cgrom;
bool chip_select, first_input;
uint8_t first_data;
void control_write(uint8_t data);
void data_write(uint8_t data);
void soft_reset();
void cursor_step();
};

View File

@ -275,15 +275,21 @@ void mt32_state::machine_reset()
void mt32_state::lcd_ctrl_w(uint8_t data)
{
lcd->cs_w(0);
lcd->control_w(data >> 4);
lcd->control_w(data);
for(int i=0; i != lcd_data_buffer_pos; i++)
for(int i=0; i != lcd_data_buffer_pos; i++) {
lcd->data_w(lcd_data_buffer[i] >> 4);
lcd->data_w(lcd_data_buffer[i]);
}
lcd->cs_w(1);
lcd_data_buffer_pos = 0;
}
uint8_t mt32_state::lcd_ctrl_r()
{
return lcd->control_r();
// Note that this does not read from the actual LCD unit (whose /RD line is pulled high)
return 0;
}
void mt32_state::lcd_data_w(uint8_t data)