--- nono/vm/pluto.cpp 2026/04/29 17:04:55 1.1.1.6 +++ nono/vm/pluto.cpp 2026/04/29 17:05:42 1.1.1.13 @@ -4,42 +4,40 @@ // Licensed under nono-license.txt // +// +// Pluto-X (独自の仮想ボード) +// + #include "pluto.h" -#include "aout.h" #include "mainapp.h" +#include "mainbus.h" +#include "mainram.h" #include "mpu680x0.h" -#include "ram.h" - -std::unique_ptr gPluto; +#include "sram.h" +// コンストラクタ PlutoDevice::PlutoDevice() - : inherited("Pluto") + : inherited(OBJ_PLUTO) { - devaddr = 0xeac000; - devlen = 0x2000; } +// デストラクタ PlutoDevice::~PlutoDevice() { } -void -PlutoDevice::ResetHard() -{ - // XXX not yet - m_count = 0; -} - // ROM /*static*/ const uint16 PlutoDevice::rom[] = { // ホストファイル起動 0x00ea, 0xc004, // .dc.l _start ; 起動アドレス //_start: + 0x46fc, 0x2700, // move.w #0x2700,%sr 0x2039, 0x00ea, 0xc450, // move.l (ROMIO_LOAD),%d0 - 0x6704, // beq.s _err - 0x2040, // move.l %d0,%a2 - 0x4ed0, // jmp (%a2) + 0x6b04, // bmi.s _err + 0x2040, // move.l %d0,%a0 + 0x46fc, 0x2000, // move.w #0x2000,%sr + 0x4e90, // jsr (%a0) //_err: 0x43fa, 0x000c, // lea.l (_errmsg),%a1 0x7021, 0x4e4f, // IOCS B_PRINT @@ -54,82 +52,45 @@ PlutoDevice::rom[] = { 0x2e00, // .dc.b ".",0 }; -uint64 -PlutoDevice::Read8(uint32 addr) +busdata +PlutoDevice::Read(busaddr addr) { - uint32 offset = addr - devaddr; - uint32 data; + uint32 paddr = addr.Addr(); + uint32 offset = paddr - baseaddr; + busdata data; if (offset < sizeof(rom)) { + // ROM 部はワードデバイスっぽく応答するほうが都合がいい。 data = rom[offset / 2]; - if ((offset & 1) == 0) { - return data >> 8; - } else { - return data & 0xff; - } - } + data |= BusData::Size2; - return (uint64)-1; -} - -uint64 -PlutoDevice::Read16(uint32 addr) -{ - uint32 offset = addr - devaddr; + } else if (offset == 0x450 && addr.GetSize() == 4) { + // ここはロングワード応答するほうが都合がいい。 + // 自 ROM からのアクセスなので細かいことは考えない。 + data = ROM_Load(); + data |= BusData::Size4; - if (offset < sizeof(rom)) { - return rom[offset / 2]; + } else { + data.SetBusErr(); } - return (uint64)-1; + return data; } -uint64 -PlutoDevice::Read32(uint32 addr) +busdata +PlutoDevice::Write(busaddr addr, uint32 data) { - uint32 offset = addr - devaddr; - uint32 data; + uint32 paddr = addr.Addr(); + uint32 reqsize = addr.GetSize(); - if (offset < sizeof(rom)) { - data = rom[offset / 2] << 16; - data |= rom[(offset / 2) + 1]; - return data; - } - switch (offset) { - case 0x450: // ROMIO_LOAD - return ROM_Load(); - - default: - break; - } - return (uint64)-1; -} - -uint64 -PlutoDevice::Write8(uint32 addr, uint32 data) -{ - switch (addr) { - case 0xeac403: - write_8_benchmark(addr, data); - break; - default: - break; - } - putlog(0, "未実装バイト書き込み $%06x", addr); - return 0; + putlog(0, "Write $%06x.%u (NOT IMPLEMENTED)", paddr, reqsize); + return BusData::BusErr; } -uint64 -PlutoDevice::Write16(uint32 addr, uint32 data) +busdata +PlutoDevice::Peek1(uint32 addr) { - putlog(0, "未実装ワード書き込み $%06x", addr); - return 0; -} - -uint64 -PlutoDevice::Peek8(uint32 addr) -{ - uint32 offset = addr - devaddr; + uint32 offset = addr - baseaddr; uint32 data; if (offset < sizeof(rom)) { @@ -141,159 +102,72 @@ PlutoDevice::Peek8(uint32 addr) } } - return (uint64)-1; + return BusData::BusErr; } // // ホストファイル起動 // -// -A オプションで指定されたホストファイルをロードする。 +// -X オプションで指定されたホストファイルをロードする。 // ロードできればエントリポイントを返す。 -// host_file が指定されている時に呼ぶこと。 +// exec_file が指定されている時に呼ぶこと。 uint32 PlutoDevice::ROM_Load() { - assert(gMainApp.host_file); - - // ホストファイルをロード - uint32 entry = gRAM->LoadFile(gMainApp.host_file); - - if (entry) { - // NetBSD/x68k のプライマリブートローダが /boot を読み込む時には - // いくつかレジスタ渡しのパラメータがあるので、ここで用意する。 - // 本当はターゲットが NetBSD/x68k の /boot の時に限定すべきのような - // 気もするけど、とりあえず。 - // 必要なパラメータは - // %d6 に bootdev、NetBSD/x68k の場合は - // bootdev = $MACULPTT - // ||||||++- major type - // |||||+--- パーティション番号 - // ||||+---- SCSI なら LUN、それ以外なら 0 - // |||+----- unit (SCSI なら SCSI ID、FD ならドライブ番号) - // ||+------ ctlr (spc0 なら 0 のやつ) - // |+------- adaptor (spc = 1、mha = 2) - // +-------- magic ($a) - // major type は fd=2、MemoryDisk=8、sd=4、(st=5、)、cd=7、ne=255。 - // - // %d7 に howto だが今の所使ってないようだ。 - - m68kcpu *cpu = gMPU680x0->GetCPU(); - RegD(6) = 0xa1000004; - RegD(7) = 0; - } - - return entry; -} - -// ベンチマーク開始 -void -PlutoDevice::benchmark_start(uint32 data) -{ - m_test_num = data; - - // テスト番号によってパラメータをセット - // #2,#3 は NOP による実行サイクル測定。 - // #4,#5 は movem によるデータ空間アクセス測定。 - switch (m_test_num) { - case 2: - case 3: - m_test_name = "NOP"; - m_inst_len = 2; - m_inst_cycle = 2; - break; - case 4: - case 5: - m_test_name = "MOVEM"; - m_inst_len = 8; - m_inst_cycle = 244; // XXX 見直すこと - break; - } + assert(gMainApp.exec_file); - // 測定開始時だけ表示 - if (m_count == 0) { - putlog(0, "ベンチマーク開始"); + auto mainbus = GetMainbusDevice(); + auto mainram = GetMainRAMDevice(); + auto mpu680x0 = GetMPU680x0Device(mpu); + auto sram = GetSRAMDevice(); - // 命令開始アドレス。この時点で REG_PC は次をさしている - m_start_addr = gMPU680x0->GetPPC(); - } - - // 測定開始 - gettimeofday(&m_start, NULL); -} - -// ベンチマーク終了 -void -PlutoDevice::benchmark_end() -{ - const int SECONDS = 5; // 測定秒数 [sec] - timeval end, result; - int t; - int num_of_inst; // 1ループ中の命令セット数 - double speed; - - // 測定終了 - gettimeofday(&end, NULL); - m_count++; - - // 今回1セット分の実行時間 [usec] - timersub(&end, &m_start, &result); - - // 総実行時間 - timeradd(&result, &m_total, &m_total); - - // 規定秒数に満たなければ、もう1セット繰り返し。 - // 次が jmp 命令なのでこの命令を抜けるだけでいい。 - if (m_total.tv_sec < SECONDS) { - return; - } - - // 規定秒数に達していれば、測定終了 - t = m_total.tv_sec * 1000*1000 + m_total.tv_usec; - putlog(0, "ベンチマーク#%d 終了 (%d 回, 計 %d.%03d msec)", - gMainApp.benchmark_mode, m_count, t / 1000, t % 1000); - - // 1ループ中の命令セット数を算出。REG_PPC はこの命令の開始番地 - num_of_inst = (gMPU680x0->GetPPC() - m_start_addr) / m_inst_len; - - // 68030 のクロック数 [MHz] に換算 - speed = (double)(m_count * num_of_inst) * m_inst_cycle / t; - - // 表示用にベンチマーク ROM のリビジョンを取得 - int rev; -rev = 0; -#if 0 - IPLROM1 *iplrom1 = (IPLROM1 *)vm->SearchDevice(DEVICE_IPLROM1); - ASSERT(iplrom1); - if (!iplrom1->GetBenchmarkROM(m_test_num, NULL, &rev)) { - rev = 0; - } -#endif + // ホストファイルをロード + LoadInfo info(gMainApp.exec_file); + if (BootLoader::LoadExec(mainram, &info) == false) { + return -1; + } + + // NetBSD/x68k のプライマリブートローダが /boot を読み込む時、および + // /boot がカーネルを読み込む時には、レジスタ渡しのパラメータがあるので、 + // ここで用意する。 + // 本当はターゲットが NetBSD/x68k の /boot とカーネルの時に限定すべきの + // ような気もするけど、とりあえず。必要なパラメータは + // + // %d6 に bootdev、NetBSD/x68k の場合は + // bootdev = $MACULPTT + // ||||||++- major type + // |||||+--- パーティション番号 + // ||||+---- SCSI なら LUN、それ以外なら 0 + // |||+----- unit (SCSI なら SCSI ID、FD ならドライブ番号) + // ||+------ ctlr (spc0 なら 0 のやつ) + // |+------- adaptor (spc = 1、mha = 2) + // +-------- magic ($a) + // major type は fd=2、MemoryDisk=8、sd=4、(st=5、)、cd=7、ne=255。 + // + // %d7 に howto だが今の所使ってないようだ。 + // + // 一方、/boot がカーネルを読み込む時はこれに加えてスタック渡しの + // パラメータもある。これは (取り出す順に) + // firstpa.L .. 読み込んだカーネル先頭の物理アドレス? + // physsize.L .. RAM 容量 (SRAM の $ed0008.L の値) + // esym.L .. シンボルの後ろ、なので実質読み込んだ全体のサイズ + // + // これも本当はターゲットが NetBSD/x68k のカーネルの時に限定すべきの + // ような気もするけど、とりあえず。 + + mpu680x0->reg.D[6] = 0xa1000004; + mpu680x0->reg.D[7] = 0; + + uint32 a7 = sram->GetRAMSize(); + a7 -= 4; + mainbus->HVWrite4(a7, info.end - info.start); // esym + a7 -= 4; + mainbus->HVWrite4(a7, sram->GetRAMSize()); // physsize + a7 -= 4; + mainbus->HVWrite4(a7, 0x00000000); // firstpa - // XXX NetBSD ホストでは有効桁2桁と思われる - putlog(0, "ベンチマーク#%d.%d (%s 実行速度) 68030/%3.0fMHz, %d MIPS", - m_test_num, rev, m_test_name, speed, (m_count * num_of_inst) / t); - - // 電源オフ - // XXX とりあえずね - exit(1); -} + mpu680x0->reg.A[7] = a7; -// -void -PlutoDevice::write_8_benchmark(uint32 addr, uint32 data) -{ - switch (data) { - case 0: // ベンチマーク終了 - benchmark_end(); - break; - case 2: // ベンチマーク開始 - case 3: - case 4: - case 5: - benchmark_start(data); - break; - default: - PANIC("not impl"); - } + return info.entry; }