--- nono/vm/pio.cpp 2026/04/29 17:05:18 1.1.1.12 +++ nono/vm/pio.cpp 2026/04/29 17:05:29 1.1.1.14 @@ -32,7 +32,6 @@ #include "interrupt.h" #include "lcd.h" #include "mainapp.h" -#include "mpu.h" #include "mpu64180.h" #include "power.h" #include "scheduler.h" @@ -42,7 +41,7 @@ // // コンストラクタ -i8255Device::i8255Device(int objid_) +i8255Device::i8255Device(uint objid_) : inherited(objid_) { } @@ -72,7 +71,7 @@ i8255Device::WriteCtrl(uint32 data) ctrl = data; if (__predict_false(loglevel >= 1)) { if (loglevel >= 2) { - putlogn("Ctrl <- $%02x: GrA/Bmode=%d/%d PA=%s PB=%s PC=%s:%s", + putlogn("Ctrl <- $%02x: GrA/Bmode=%u/%u PA=%s PB=%s PC=%s:%s", data, GetGroupAMode(), GetGroupBMode(), PortADir() == DIR_IN ? "IN" : "OUT", @@ -95,13 +94,19 @@ i8255Device::WriteCtrl(uint32 data) // | | | +-- 書き込むビットデータ // +--+--+----- 書き込むビット位置 - int pc = (data >> 1) & 7; - int val = data & 1; - putlog(2, "Ctrl <- $%02x: SetPC%d=%d", data, pc, val); + uint pc = (data >> 1) & 7; + uint val = data & 1; + putlog(2, "Ctrl <- $%02x: SetPC%u=%u", data, pc, val); SetPC(pc, val); } } +bool +i8255Device::PokePort(uint32 offset, uint32 data) +{ + return false; +} + // 共通部分を表示。 // 戻り値は表示を終えた次の行。 int @@ -120,10 +125,10 @@ i8255Device::MonitorUpdateCommon(TextScr "BiDirection", }; const int x = 16; - screen.Print(x, y++, "GroupA (PortA,PortCH) Mode: %d(%s)", + screen.Print(x, y++, "GroupA (PortA,PortCH) Mode: %u(%s)", GetGroupAMode(), modestr[GetGroupAMode()]); - screen.Print(x, y++, "GroupB (PortB,PortCL) Mode: %d(%s)", + screen.Print(x, y++, "GroupB (PortB,PortCL) Mode: %u(%s)", GetGroupBMode(), modestr[GetGroupBMode()]); static const char *inoutstr[] = { @@ -143,6 +148,9 @@ i8255Device::MonitorUpdateCommon(TextScr // X68k PPI // +// InsideOut p.135 +static const busdata ppi_wait = busdata::Wait(19 * 40_nsec); + // コンストラクタ PPIDevice::PPIDevice() : inherited(OBJ_PPI) @@ -154,31 +162,36 @@ PPIDevice::~PPIDevice() { } -uint64 -PPIDevice::Read(uint32 offset) +busdata +PPIDevice::ReadPort(uint32 offset) { - mpu->AddCycle(19); // InsideOut p.135 + busdata data; switch (offset) { case 0: case 1: - return 0xff; + data = 0xff; + break; case 2: putlog(0, "Read $e9a005 PortC (NOT IMPLEMENTED)"); - return 0xff; + data = 0xff; + break; case 3: putlog(0, "Read $e9a007 Ctrl (NOT IMPLEMENTED)"); - return 0xff; + data = 0xff; + break; default: - VMPANIC("corrupted offset=%d", offset); + VMPANIC("corrupted offset=%u", offset); } + + data |= ppi_wait; + data |= BusData::Size1; + return data; } -uint64 -PPIDevice::Write(uint32 offset, uint32 data) +busdata +PPIDevice::WritePort(uint32 offset, uint32 data) { - mpu->AddCycle(19); // InsideOut p.135 - switch (offset) { case 0: case 1: @@ -193,13 +206,15 @@ PPIDevice::Write(uint32 offset, uint32 d WriteCtrl(data); break; default: - VMPANIC("corrupted offset=%d", offset); + VMPANIC("corrupted offset=%u", offset); } - return 0; + busdata r = ppi_wait; + r |= BusData::Size1; + return r; } -uint64 -PPIDevice::Peek(uint32 offset) +busdata +PPIDevice::PeekPort(uint32 offset) { // XXX return 0xff; @@ -207,30 +222,30 @@ PPIDevice::Peek(uint32 offset) // PortC 書き込み void -PPIDevice::SetPC(int pc, int val) +PPIDevice::SetPC(uint pc, uint val) { switch (pc) { case 0: // ADPCM PAN Left Off pan_left = !val; - break; + return; case 1: // ADPCM PAN Right Off pan_right = !val; - break; + return; case 2: // ADPCM サンプリングレート adpcm_rate = (adpcm_rate & 2) | val; - break; + return; case 3: // ADPCM サンプリングレート adpcm_rate = (val << 1) | (adpcm_rate & 1); - break; + return; case 4: // ジョイスティック #1 コントロール case 5: // ジョイスティック #2 コントロール case 6: // ジョイスティック #1 ボタン A case 7: // ジョイスティック #1 ボタン B - putlog(1, "SetPC(%d) <- %d (NOT IMPLEMENTED)", pc, val); - break; + putlog(1, "SetPC(%u) <- %u (NOT IMPLEMENTED)", pc, val); + return; default: - VMPANIC("corrupted pc=%d", pc); + VMPANIC("corrupted pc=%u", pc); } } @@ -359,10 +374,10 @@ PIO0Device::ResetHard(bool poweron) } } -uint64 -PIO0Device::Read(uint32 offset) +busdata +PIO0Device::ReadPort(uint32 offset) { - uint32 data; + busdata data; switch (offset) { case 0: @@ -373,8 +388,8 @@ PIO0Device::Read(uint32 offset) intreq[INT_H] = false; ChangeInterrupt(); - putlog(1, "DIP-SW1 -> $%02x", data); - return data; + putlog(1, "DIP-SW1 -> $%02x", data.Data()); + break; case 1: // PortB @@ -384,51 +399,59 @@ PIO0Device::Read(uint32 offset) intreq[INT_L] = false; ChangeInterrupt(); - putlog(1, "DIP-SW2 -> $%02x", data); - return data; + putlog(1, "DIP-SW2 -> $%02x", data.Data()); + break; case 2: // PortC data = GetPC(); - putlog(1, "PortC -> $%02x", data); - return data; + putlog(1, "PortC -> $%02x", data.Data()); + break; case 3: data = ReadCtrl(); - putlog(1, "Ctrl -> $%02x", data); - return data; + putlog(1, "Ctrl -> $%02x", data.Data()); + break; default: - VMPANIC("corrupted offset=%d", offset); + VMPANIC("corrupted offset=%u", offset); } + + // XXX wait? + data |= BusData::Size1; + return data; } -uint64 -PIO0Device::Write(uint32 offset, uint32 data) +busdata +PIO0Device::WritePort(uint32 offset, uint32 data) { switch (offset) { case 0: // PIO0 PortA: DIPSW1 (入力のみ) case 1: // PIO0 PortB: DIPSW2 (入力のみ) - return 0; + break; case 2: // PIO0 PortC: ホスト割り込み制御 for (int i = 0; i < 8; i++) { SetPC(i, data & 1); data >>= 1; } - return 0; + break; case 3: // コントロール WriteCtrl(data); - return 0; + break; default: - VMPANIC("corrupted offset=%d", offset); + VMPANIC("corrupted offset=%u", offset); } + + // XXX wait? + busdata r = BusData::Size1; + return r; } -uint64 -PIO0Device::Peek(uint32 offset) +busdata +PIO0Device::PeekPort(uint32 offset) { switch (offset) { case 0: @@ -474,8 +497,8 @@ PIO0Device::MonitorUpdate(Monitor *, Tex bool d1 = (pa & (1U << bitpos)); bool d2 = (pb & (1U << bitpos)); - screen.Print(21 + i * 7, y, TA::OnOff(d1), "DIP1-%d", label); - screen.Print(21 + i * 7, y + 1, TA::OnOff(d2), "DIP2-%d", label); + screen.Print(21 + i * 7, y, TA::OnOff(d1), "DIP1-%u", label); + screen.Print(21 + i * 7, y + 1, TA::OnOff(d2), "DIP2-%u", label); } y += 2; @@ -541,7 +564,7 @@ PIO0Device::GetPC() const // PortC 書き込み void -PIO0Device::SetPC(int pc, int val) +PIO0Device::SetPC(uint pc, uint val) { switch (pc) { case 0: @@ -573,13 +596,14 @@ PIO0Device::SetPC(int pc, int val) // XP リセット if ((val ^ xp_reset)) { xp_reset = val; - putlog(1, "XP Reset %d", xp_reset); + putlog(1, "XP Reset %u", xp_reset); auto mpu64180 = GetMPU64180Device(); mpu64180->ChangeRESET(xp_reset); } return; + default: + VMPANIC("corrupted pc=%u", pc); } - VMPANIC("invalid pc=%d", pc); } // とりあえず、XP からここまではエッジトリガーで、 @@ -657,26 +681,32 @@ PIO1Device::ResetHard(bool poweron) { inherited::ResetHard(poweron); - // デフォルトで PIO 出力は「1msec 後に電源オフ」という状態なので、 - // 電源オンから 1msec 以内にソフトウェアがこれをキャンセルしないと - // いけないらしい。どうしてこうなった…。 - power = false; - powerdev->SetSystemPowerOn(false); + // 電源ユニットは POWF* 信号が 'L' になると 1msec 後に電源オフになる。 + // 正確には「1msec 以内に 'H' にすれば回避できる」なので、実際に電源が + // オフになるのはそれよりもっと十分長いとは思われる。 + // 8255 リセット時、ポート C の各ピンは入力モードになっているので、 + // ハイインピーダンス。たぶん電源的にも 'H' になってると想像する。 + // なので電源オンで POWF* がハイインピーダンスなだけでは電源オフ + // タイマーは動作しないんじゃないかな。 + power = true; + powerdev->SetSystemPowerOn(power); } -uint64 -PIO1Device::Read(uint32 offset) +busdata +PIO1Device::ReadPort(uint32 offset) { - uint32 data; + busdata data; switch (offset) { case 0: // PIO1 PortA: LCD データ - return lcd->Read(); + data = lcd->Read(); + break; case 1: // PIO1 PortB: 無効 - return 0xff; + data = 0xff; + break; case 2: // PortC @@ -684,51 +714,59 @@ PIO1Device::Read(uint32 offset) data |= xp_intreq ? 0 : 0x02; // 残りのビットは %1 だろうか? data |= 0x0d; - putlog(1, "PortC -> $%02x", data); - return data; + putlog(1, "PortC -> $%02x", data.Data()); + break; case 3: data = ReadCtrl(); - putlog(1, "Ctrl -> $%02x", data); - return data; + putlog(1, "Ctrl -> $%02x", data.Data()); + break; default: - VMPANIC("corrupted offset=%d", offset); + VMPANIC("corrupted offset=%u", offset); } + + // XXX wait? + data |= BusData::Size1; + return data; } -uint64 -PIO1Device::Write(uint32 offset, uint32 data) +busdata +PIO1Device::WritePort(uint32 offset, uint32 data) { switch (offset) { case 0: // PIO1 PortA: LCD データ lcd->Write(data); - return 0; + break; case 1: // PIO1 PortB: XP の INT0 をアサート // データ不問でアサートする。 putlog(1, "Assert XP INT0"); mpu64180->AssertINT0(); - return 0; + break; case 2: // PIO1 PortC: LCD/パワーオフ制御 for (int i = 0; i < 8; i++) { SetPC(i, data & 1); data >>= 1; } - return 0; + break; case 3: // コントロール WriteCtrl(data); - return 0; + break; default: - VMPANIC("corrupted offset=%d", offset); + VMPANIC("corrupted offset=%u", offset); } + + // XXX wait? + busdata r = BusData::Size1; + return r; } -uint64 -PIO1Device::Peek(uint32 offset) +busdata +PIO1Device::PeekPort(uint32 offset) { switch (offset) { case 0: // PIO1 PortA LCD データ @@ -786,7 +824,7 @@ PIO1Device::GetPC() const } void -PIO1Device::SetPC(int pc, int val) +PIO1Device::SetPC(uint pc, uint val) { switch (pc) { case 0: @@ -798,6 +836,10 @@ PIO1Device::SetPC(int pc, int val) return; case 4: + // 8255 はモード変更 (WriteCtrl) をするとポート C を 'L' にするが、 + // PC4 (POWF*) が 'L' だと電源オフ指示なので、1msec 以内に + // ソフトウェアでこれをキャンセルしないといけない。 + // どうしてこうなった…。 power = val; if (power) { // 電源オフ取り消し @@ -820,7 +862,6 @@ PIO1Device::SetPC(int pc, int val) return; default: - break; + VMPANIC("corrupted pc=%u", pc); } - VMPANIC("PC%d 未実装", pc); }