--- nono/vm/romemu_x68k.cpp 2026/04/29 17:05:14 1.1 +++ nono/vm/romemu_x68k.cpp 2026/04/29 17:05:29 1.1.1.4 @@ -8,23 +8,43 @@ // X68030 の ROM30 (SCSI ROM) エミュレーション // +// IODevice +// | +// +- ROMDevice (LoadROM()、ウェイト、マスク等を持つ) +// | +- PROMDevice (LUNA* の PROM) +// | +- IPLROM1Device (X680x0 の IPLROM 後半) +// | +- IPLROM2Device (X680x0 の IPLROM 前半) +// | +- CGROMDevice (X680x0 の CGROM) +// | | +// | +- ROMEmuDevice +// | +- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分) +// | | +- Luna1PROMEmuDevice (LUNA-I の PROM エミュレーション) +// | | +- Luna88kPROMEmuDevice (LUNA-88K の PROM エミュレーション) +// | +- NewsROMEmuDevice (NEWS の ROM エミュレーション) +// | | +// | | +----------------+ +// | +-| ROM30EmuDevice | (X68030 の ROM30 エミュレーション) +// | | +----------------+ +// | | +// | +- Virt68kROMEmuDevice (virt-m68k の IPLROM 相当の何か) +// | +// +- PROM0Device (LUNA* のブートページ切り替え用プロキシ) +// +- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ) + #include "romemu_x68k.h" -#include "bus.h" +#include "mainbus.h" +#include "mainram.h" #include "memorystream.h" -#include "m68030core.h" #include "mpu680x0.h" -#include "ram.h" -#include "romimg_x68k.h" #include "scsidev.h" #include "spc.h" #include "sram.h" // コンストラクタ ROM30EmuDevice::ROM30EmuDevice() - : inherited("IPLROM2") + : inherited(OBJ_IPLROM2) { - devaddr = baseaddr; - devlen = 0x020000; + uint devlen = 0x020000; mask = devlen - 1; imagebuf.reset(new uint8 [devlen]); @@ -35,75 +55,75 @@ ROM30EmuDevice::ROM30EmuDevice() // デストラクタ ROM30EmuDevice::~ROM30EmuDevice() { - gIPLROM2 = NULL; } +// 初期化 bool ROM30EmuDevice::Init() { - // 親クラス if (inherited::Init() == false) { return false; } - cpu = gMPU680x0->GetCPU(); + mainbus = GetMainbusDevice(); + spc = GetSPCDevice(); - MemoryStreamBE ms(imagebuf.get()); + MemoryStreamBE roms(imagebuf.get()); // fc0000.L 〜 fc001c.L: SCSI ブートアドレス for (int i = 0; i < 8; i++) { - ms.Write32(0x00fc0100); + roms.Write4(0x00fc0100); } // fc0020.L: SCSI 初期化アドレス - ms.Write32(0x00fc0200); + roms.Write4(0x00fc0200); // fc0024.B: マジック - ms.Write32(('S' << 24) | ('C' << 16) | ('S' << 8) | 'I'); - ms.Write16(('I' << 8) | 'N'); - ms.Write8(0); - ms.Write8(0); + roms.Write4(('S' << 24) | ('C' << 16) | ('S' << 8) | 'I'); + roms.Write2(('I' << 8) | 'N'); + roms.Write1(0); + roms.Write1(0); // // SCSI ブート // - ms.SetOffset(0x100); //_SCSIBOOT: - ms.Write16(0x6100); // bsr $fc0200 ; SCSIIOCS 初期化 - ms.Write16(0x0200 - ms.GetOffset()); - ms.Write16(0x2039); // move.l (ROMIO_BOOT),d0 - ms.Write32(ROMIO_BOOT); - ms.Write16(0x6602); // bne _go ; 起動先があればGO + roms.SetOffset(0x100); //_SCSIBOOT: + roms.Write2(0x6100); // bsr $fc0200 ; SCSIIOCS 初期化 + roms.Write2(0x0200 - roms.GetOffset()); + roms.Write2(0x2039); // move.l (ROMIO_BOOT),d0 + roms.Write4(ROMIO_BOOT); + roms.Write2(0x6602); // bne _go ; 起動先があればGO //_bootfail: - ms.Write16(0x4e75); // rts + roms.Write2(0x4e75); // rts //_go: - ms.Write16(0x2040); // move.l d0,a0 ; ジャンプ先を a0 にセット - ms.Write16(0x4ed0); // jmp (a0) ; で、ジャンプ + roms.Write2(0x2040); // move.l d0,a0 ; ジャンプ先を a0 にセット + roms.Write2(0x4ed0); // jmp (a0) ; で、ジャンプ // // SCSIIOCS 初期化 // - ms.SetOffset(0x200); //_SCSIINIT: - ms.Write32(0x323c01f5); // move.w #$01f5,d1 - ms.Write16(0x43f9); // lea.l $00fc0300,a1 - ms.Write32(0x00fc0300); - ms.Write32(0x70804e4f); // IOCS _B_INTVCS + roms.SetOffset(0x200); //_SCSIINIT: + roms.Write4(0x323c01f5); // move.w #$01f5,d1 + roms.Write2(0x43f9); // lea.l $00fc0300,a1 + roms.Write4(0x00fc0300); + roms.Write4(0x70804e4f); // IOCS _B_INTVCS // ; 戻り値(旧アドレス)は破棄 - ms.Write16(0x4e75); // rts + roms.Write2(0x4e75); // rts // // SCSIIOCS エントリ // - ms.SetOffset(0x300); //_SCSIIOCS: - ms.Write16(0x2039); // move.l (ROMIO_SCSI),d0 - ms.Write32(ROMIO_SCSI); - ms.Write16(0x4e75); // rts + roms.SetOffset(0x300); //_SCSIIOCS: + roms.Write2(0x2039); // move.l (ROMIO_SCSI),d0 + roms.Write4(ROMIO_SCSI); + roms.Write2(0x4e75); // rts return true; } uint64 -ROM30EmuDevice::Read32(uint32 addr) +ROM30EmuDevice::ReadROMIO(busaddr addr) { // IPLROM2 領域からのロングワードアクセスでだけ謎の I/O 空間が見える。 - if ((gMPU->GetPaddr() & 0xfffe0000) == baseaddr) { - switch (addr) { + if ((mpu->GetPPC() & 0xfffe0000) == baseaddr && addr.GetSize() == 4) { + switch (addr.Addr()) { case ROMIO_SCSI: return SCSIIOCS(); @@ -115,7 +135,7 @@ ROM30EmuDevice::Read32(uint32 addr) } } - return inherited::Read32(addr); + return (uint64)-1; } // SRAM で指定された SCSI ID のデバイスからブートブロックを読み込む。 @@ -123,17 +143,23 @@ ROM30EmuDevice::Read32(uint32 addr) uint32 ROM30EmuDevice::SCSIBoot() const { + auto mainram = GetMainRAMDevice(); + auto sram = GetSRAMDevice(); + + auto mpu680x0 = GetMPU680x0Device(mpu); + m68kreg& reg = mpu680x0->reg; + // SRAM の ROM 起動アドレスから SCSI ID を取得。 - uint32 romaddr = gSRAM->GetROMAddr(); + uint32 romaddr = sram->GetROMAddr(); if ((romaddr & 0xffff00) != 0xfc0000) { return 0; } - int id = (romaddr & 0x1f) >> 2; + uint id = (romaddr & 0x1f) >> 2; // ターゲットディスク - SCSITarget *target = gSPC->GetTarget(id); + SCSITarget *target = spc->GetSCSI()->GetTarget(id); if (target == NULL) { - putlog(1, "%s: SCSI ID %d not found", __func__, id); + putlog(1, "%s: SCSI ID %u not found", __func__, id); return 0; } SCSIDisk *disk = dynamic_cast(target); @@ -153,45 +179,43 @@ ROM30EmuDevice::SCSIBoot() const } else if (sectsize == 2048) { blocksize = sectsize; } else { - putlog(1, "%s: SCSI ID %d: sectsize %d not supported", __func__, + putlog(1, "%s: SCSI ID %u: sectsize %u not supported", __func__, id, sectsize); return 0; } - putlog(2, "%s: SCSI ID %d: sectsize=%d, blocksize=%d", __func__, id, + putlog(2, "%s: SCSI ID %u: sectsize=%u, blocksize=%u", __func__, id, sectsize, blocksize); // +0 ブロック目先頭8バイトのマジックを確認 std::vector block(blocksize); if (disk->Peek(&block[0], 0, 8) == false) { - putlog(1, "%s: SCSI ID %d: Reading magic failed", __func__, id); + putlog(1, "%s: SCSI ID %u: Reading magic failed", __func__, id); return 0; } if (memcmp(&block[0], "X68SCSI1", 8) != 0) { - putlog(1, "%s: SCSI ID %d: invalid magic", __func__, id); + putlog(1, "%s: SCSI ID %u: invalid magic", __func__, id); return 0; } // +1 ブロック目から1ブロックを読んで... if (disk->Peek(&block[0], blocksize, blocksize) == false) { - putlog(1, "%s: SCSI ID %d: Reading boot block failed", __func__, id); + putlog(1, "%s: SCSI ID %u: Reading boot block failed", __func__, id); return 0; } // 先頭バイトが 0x60 (BRA.[BW] 命令の1バイト目) であること if (block[0] != 0x60) { - putlog(1, "%s: SCSI ID %d: no branch instruction", __func__, id); + putlog(1, "%s: SCSI ID %u: no branch instruction", __func__, id); return 0; } // メモリの 0x2000 番地に置く - for (int i = 0; i < blocksize; i++) { - gRAM->Write8(0x2000 + i, block[i]); - } + mainram->WriteMem(0x2000, &block[0], blocksize); // D4 にはこの時の SCSI ID が置いてある(のが見えている) - RegD(4) = id; + reg.D[4] = id; // XXX D2 は最後に _S_READ を発行した LBA を指しているようだ。 // なので +1 ブロックの LBA になる。 - RegD(2) = blocksize / sectsize; + reg.D[2] = blocksize / sectsize; // 成功したのでジャンプ先アドレスを返す putlog(1, "%s succeeded", __func__); @@ -202,8 +226,10 @@ ROM30EmuDevice::SCSIBoot() const uint32 ROM30EmuDevice::SCSIIOCS() { - uint32 scsicall = RegD(1); + auto mpu680x0 = GetMPU680x0Device(mpu); + m68kreg& reg = mpu680x0->reg; + uint32 scsicall = reg.D[1]; switch (scsicall) { case 0x20: // _S_INQUIRY return SCSI_S_INQUIRY(scsicall); @@ -228,23 +254,25 @@ ROM30EmuDevice::SCSIIOCS() } #define PRE \ - uint32 d4 = RegD(4); \ + auto mpu680x0 = GetMPU680x0Device(mpu); \ + m68kreg& reg = mpu680x0->reg; \ + uint32 d4 = reg.D[4]; \ uint32 id = d4 & 0x0000ffff; \ uint32 lun = (d4 >> 16) & 0x0000ffff; \ std::string scsiname = GetSCSICallName(scsicall); \ /* ターゲットディスク */ \ - SCSITarget *target = gSPC->GetTarget(id); \ + SCSITarget *target = spc->GetSCSI()->GetTarget(id); \ if (target == NULL) { \ - putlog(1, "%s ID%d not found", scsiname.c_str(), id); \ + putlog(1, "%s ID%u not found", scsiname.c_str(), id); \ return -1; \ } \ SCSIDisk *disk __unused = dynamic_cast(target); \ /* ログ表示用 */ \ std::string loghdr; \ if (loglevel >= 1) { \ - loghdr = string_format("%s ID%d", scsiname.c_str(), id); \ + loghdr = string_format("%s ID%u", scsiname.c_str(), id); \ if (lun != 0) { \ - loghdr + string_format(":LUN%d", lun); \ + loghdr + string_format(":LUN%u", lun); \ } \ } \ /*end*/ @@ -254,8 +282,8 @@ ROM30EmuDevice::SCSI_S_INQUIRY(uint32 sc { PRE; - uint32 a1 = RegA(1); - uint32 reqlen = RegD(3); + uint32 a1 = reg.A[1]; + uint32 reqlen = reg.D[3]; putlog(1, "%s a1=$%06x", loghdr.c_str(), a1); std::vector cmdseq(6); cmdseq[0] = SCSI::Command::Inquiry; @@ -274,8 +302,8 @@ ROM30EmuDevice::SCSI_S_INQUIRY(uint32 sc // アロケーションサイズ(reqlen)と結果(cmd->buf)の小さい方まで転送 int len = std::min((int)reqlen, (int)res.size()); for (int i = 0; i < len; i++) { - int64 r = vm_phys_write_8(a1++, res[i]); - if (r < 0) { + busdata bd = mainbus->HVWrite1(a1++, res[i]); + if (bd.IsBusErr()) { return -1; } } @@ -287,15 +315,15 @@ ROM30EmuDevice::SCSI_S_READEXT(uint32 sc { PRE; - uint32 a1 = RegA(1); - uint32 lba = RegD(2); - uint32 blkcount = RegD(3); - uint32 blkshift = RegD(5); + uint32 a1 = reg.A[1]; + uint32 lba = reg.D[2]; + uint32 blkcount = reg.D[3]; + uint32 blkshift = reg.D[5]; uint32 blkbytes = 0x100 << blkshift; uint32 bytes = blkcount * blkbytes; - putlog(1, "%s a1=$%06x lba=$%08x bytes=%d d5=%d", + putlog(1, "%s a1=$%06x lba=$%08x bytes=%u d5=%u", loghdr.c_str(), a1, lba, bytes, blkshift); std::vector cmdseq(10); cmdseq[0] = SCSI::Command::Read10; @@ -318,8 +346,8 @@ ROM30EmuDevice::SCSI_S_READEXT(uint32 sc const std::vector& res = cmd->buf; if (res.size() != bytes) { - putlog(1, "%s res.size=%d mismatch with bytes=%d", - loghdr.c_str(), (int)res.size(), bytes); + putlog(1, "%s res.size=%u mismatch with bytes=%u", + loghdr.c_str(), (uint)res.size(), bytes); // SCSIIOCS ブロックサイズとディスクのセクタサイズが不整合の // 場合、転送は DMAC か SPC のいずれかが打ち切る。 // XXX そのときも何らかのエラーが発生しているはずだが? @@ -329,8 +357,8 @@ ROM30EmuDevice::SCSI_S_READEXT(uint32 sc } for (int i = 0; i < bytes; i++) { - int64 r = vm_phys_write_8(a1++, res[i]); - if (r < 0) { + busdata bd = mainbus->HVWrite1(a1++, res[i]); + if (bd.IsBusErr()) { return -1; } } @@ -351,7 +379,7 @@ ROM30EmuDevice::SCSI_S_READCAP(uint32 sc { PRE; - uint32 a1 = RegA(1); + uint32 a1 = reg.A[1]; putlog(1, "%s a1=$%06x", loghdr.c_str(), a1); std::vector cmdseq(10); cmdseq[0] = SCSI::Command::ReadCapacity; @@ -368,8 +396,8 @@ ROM30EmuDevice::SCSI_S_READCAP(uint32 sc const std::vector& res = cmd->buf; assert(res.size() == 8); for (auto data : res) { - int64 r = vm_phys_write_8(a1++, data); - if (r < 0) { + busdata bd = mainbus->HVWrite1(a1++, data); + if (bd.IsBusErr()) { return -1; } }