--- nono/vm/lcd.cpp 2026/04/29 17:04:42 1.1.1.5 +++ nono/vm/lcd.cpp 2026/04/29 17:04:58 1.1.1.8 @@ -9,14 +9,16 @@ // #include "lcd.h" +#include "uimessage.h" std::unique_ptr gLCD; LCDDevice::LCDDevice() + : inherited("LCD") { - logname = "lcd"; - devname = "LCD(HD44780)"; - monitor_size = nnSize(67, 3); + monitor.func = (MonitorCallback_t)&LCDDevice::MonitorUpdate; + monitor.SetSize(67, 3); + monitor.Regist(ID_MONITOR_LCD); } LCDDevice::~LCDDevice() @@ -28,7 +30,7 @@ LCDDevice::PowerOff() { // XXX 電源オフは色を落としたほうがいい memset(ddram, 0x20, sizeof(ddram)); - update++; + UIMessage::Post(UIMessage::LCD); return true; } @@ -40,7 +42,9 @@ LCDDevice::ResetHard() // XXX not yet // CGRAM とか信号線とか - update++; + SetAddr(0, false); + + UIMessage::Post(UIMessage::LCD); } void @@ -51,7 +55,7 @@ LCDDevice::SetRW(bool val) } void -LCDDevice::SetRS(int val) +LCDDevice::SetRS(bool val) { rs = val; putlog(2, "RS = %d", rs); @@ -69,47 +73,115 @@ uint8 LCDDevice::Get() const { return (en ? 0x80 : 0) - | (rs >> 6) + | (rs ? 0x40 : 0) | (rw ? 0x20 : 0); } +// 現在のアドレスでデータレジスタにラッチ +void +LCDDevice::LatchData() +{ + if (addr_is_cgram) { + data_reg = cgram[addr_counter]; + } else { + data_reg = ddram[addr_counter]; + } +} + +// アドレスカウンタを設定 +void +LCDDevice::SetAddr(int addr, bool is_cgram) +{ + // アドレスカウンタをセットするとデータレジスタにラッチされる + addr_counter = addr; + addr_is_cgram = is_cgram; + LatchData(); +} + +// アドレスカウンタを次へ進める +void +LCDDevice::NextAddr() +{ + // アドレス更新について。 + // DDRAM は各行 0x27 までしか存在していないが、stride が 0x40 バイト。 + // XXX CGRAM が折り返すかどうかは分からないがそのまま DDRAM 領域に + // 行っても困ると思うのでとりあえず。 + + if (addr_is_cgram) { + if (addr_inc) { + addr_counter++; + } else { + addr_counter--; + } + addr_counter &= 0x3f; + } else { + // 2 行モードしかサポートしていない + if (addr_inc) { + addr_counter++; + if (addr_counter == 0x28) { // DDRAM 1行目 + addr_counter = 0x40; + } else if (addr_counter == 0x68) { // DDRAM 2行目 + addr_counter = 0x0; + } + } else { + if (addr_counter == 0x0) { // DDRAM 1行目 + addr_counter = 0x68; + } else if (addr_counter == 0x40) { // DDRAM 2行目 + addr_counter = 0x28; + } + addr_counter--; + } + } + LatchData(); +} + uint8 LCDDevice::Read() { if (en == false || rw == false) { - // XXX どうなるんだろ + // ハイインピーダンス return 0xff; } - if (rs == 0) { + + if (rs == false) { // ステータスレジスタの読み込み // B A A A A A A A // | +-+-+-+-+-+-+-- アドレスカウンタ // +---------------- ビジーフラグ %1=BUSY // XXX ビジーは未実装 - return (addr & 0x7f); + return addr_counter; } else { - putlog(0, "未実装データ読み込み"); + // データレジスタの読み込み + uint8 rv = data_reg; + NextAddr(); + return rv; } - return 0xff; } void LCDDevice::Write(uint8 data) { - if (en == false || rw == true) { - // どうなるんだろ + if (en == false) { + // ハイインピーダンス return; } - if (rs == 0) { + if (rw == true) { + // LCD はドライブ、PIOもドライブ。ショートが発生して燃える。 + // たまたま値が一致したときだけセーフ。 + putlog(0, "LCD will short out."); + return; + } + + if (rs == false) { // コマンド書き込み if ((data & 0x80)) { - addr = data; - putlog(1, "DDRAM アドレスセット $%02x", addr & 0x7f); + SetAddr(data & 0x7f, false); + putlog(1, "DDRAM アドレスセット $%02x", addr_counter); } else if ((data & 0x40)) { - addr = data; - putlog(1, "CGRAM アドレスセット $%02x", addr & 0x3f); + SetAddr(data & 0x3f, true); + putlog(1, "CGRAM アドレスセット $%02x", addr_counter); } else if ((data & 0x20)) { // ファンクション・セット // 0x38 (8ビットバス、2行表示、8ライン/行)モードのみサポート @@ -131,47 +203,32 @@ LCDDevice::Write(uint8 data) // XXX 表示シフトは未サポート } else if ((data & 0x02)) { // カーソルホーム - addr = 0x40; + // DDRAM アドレス 0 をセット + SetAddr(0, false); } else if ((data & 0x01)) { // 表示クリア memset(ddram, 0x20, sizeof(ddram)); - addr = 0x40; - update++; + // DDRAM アドレス 0 をセット + SetAddr(0, false); + UIMessage::Post(UIMessage::LCD); } else { // $00 が書き込まれるんだけど、データシートにはないんだよね。 // 無視していいかな。 putlog(2, "未定義書き込み $%02x", data); } } else { - if ((addr & 0x80)) { - putlog(1, "DDRAM データ書き込み X=%d Y=%d <- $%02x", - (addr & 0x7f) % 0x40, (addr & 0x7f) / 0x40, data); + // データ書き込み + if (addr_is_cgram) { + cgram[addr_counter] = data; + putlog(1, "CGRAM データ書き込み $%02x <- $%02x", + addr_counter, data); } else { - putlog(1, "CGRAM データ書き込み $%02x <- $%02x", addr & 0x3f, data); - } - ram[addr] = data; - update++; - // アドレス更新 - // DDRAM は各行 0x27 までしか存在していないが、stride が 0x40 バイト。 - // XXX CGRAM が折り返すかどうかは分からないがそのまま DDRAM 領域に - // 行っても困ると思うのでとりあえず。 - if (addr_inc) { - addr++; - if (addr == 0x80) // CGRAM (XXX) - addr = 0x40; - else if (addr == 0x80 + 0x28) // DDRAM 1行目 - addr = 0x80 + 0x40; - else if (addr == 0x80 + 0x68) // DDRAM 2行目 - addr = 0x80 + 0; - } else { - addr--; - if (addr == 0x3f) // CGRAM (XXX) - addr = 0x7f; - else if (addr == 0x7f) // DDRAM 1行目 - addr = 0x80 + 0x67; - else if (addr == 0x80 + 0x3f) // DDRAM 2行目 - addr = 0x80 + 0x27; + ddram[addr_counter] = data; + putlog(1, "DDRAM データ書き込み X=%d Y=%d <- $%02x", + addr_counter % 0x40, addr_counter / 0x40, data); } + NextAddr(); + UIMessage::Post(UIMessage::LCD); } } @@ -183,17 +240,19 @@ LCDDevice::Peek() const // XXX どうなるんだろ return 0xff; } - if (rs == 0) { - // XXX ? - return (addr & 0x7f); + if (rs == false) { + // ステータスレジスタをピークする + // XXX ビジーは未実装 + return addr_counter; } else { - // データ読み込みは未実装 + // データレジスタをピークする + return data_reg; } return 0xff; } void -LCDDevice::MonitorUpdate(TextScreen &monitor) +LCDDevice::MonitorUpdate(Monitor *, TextScreen &screen) { char buf[17]; @@ -203,20 +262,20 @@ LCDDevice::MonitorUpdate(TextScreen &mon // 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |0123456789abcdef| // 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |0123456789abcdef| - monitor.Clear(); - monitor.Print(0, 0, "RW=%c RS=%d E=%d", rw ? 'R' : 'W', rs, en); + screen.Clear(); + screen.Print(0, 0, "RW=%c RS=%d E=%d", rw ? 'R' : 'W', rs, en); for (int y = 0; y < 2; y++) { memcpy(buf, &ddram[y * 0x40], 16); buf[16] = '\0'; // 16進を表示する端から文字ダンプ用に加工していく for (int x = 0; x < 16; x++) { - monitor.Print(x * 3 + (x / 8), y + 1, "%02x", buf[x]); + screen.Print(x * 3 + (x / 8), y + 1, "%02x", buf[x]); if (buf[x] < 0x20 || buf[x] > 0x7e) { buf[x] = '.'; } } - monitor.Print(49, y + 1, "|%-16s|", buf); + screen.Print(49, y + 1, "|%-16s|", buf); } } @@ -1851,7 +1910,7 @@ LCDDevice::GetFont(int ch) const 0b000'00100, 0b000'00000, - 0b000'00000, // 0xed L=(?) + 0b000'00000, // 0xed L= (U+26c0 だろうか?) 0b000'00000, 0b000'00000, 0b000'00000,