--- nono/vm/vm_luna.cpp 2026/04/29 17:04:32 1.1 +++ nono/vm/vm_luna.cpp 2026/04/29 17:04:53 1.1.1.6 @@ -1,6 +1,7 @@ // // nono -// Copyright (C) 2020 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // #include "vm_luna.h" @@ -8,27 +9,173 @@ #include "bitmap.h" #include "bt454.h" #include "busio.h" +#include "cmmu.h" +#include "config.h" #include "crtc2.h" #include "ethernet.h" #include "fuserom.h" +#include "interrupt.h" #include "lance.h" #include "lcd.h" #include "lunakbd.h" #include "mainapp.h" #include "mk48t02.h" +#include "mpu680x0.h" +#include "mpu88xx0.h" #include "pio.h" +#include "prom.h" #include "ram.h" +#include "ram_partial.h" #include "renderer.h" -#include "romemu_luna.h" +#include "romemu_luna1.h" #include "romemu_luna88k.h" -#include "romimg_luna.h" #include "scheduler.h" #include "sio.h" #include "spc.h" #include "sysclk.h" +#include "sysctlr.h" +#include "tas.h" #include "zram.h" -// LUNA のデバイス割り当て表 (上位8ビット) +// +// LUNA 共通部 +// + +// デバイスマップ用の識別子 +enum { + NONE, + BUSERR, + PROM, + MK48, + PIO0, + PIO1, + SIO, + TAS, + SYSCLK, + ZRAM, + MROM, + BITMAP, + BT454, + CRTC2, + SCSI, + LANCE, + FUSE, + SYSCTL, + CMMU, +}; + +// コンストラクタ +VM_LUNA::VM_LUNA() +{ + // この機種に不要なパラメータはここで削除する + // (機種が決まるより前に全機種の設定の和集合を用意してあるため)。 + // o LUNA-I は 68881 固定なので不要。 + // o これは m68k パラメータなので LUNA88K には不要。 + gConfig->Delete("mpu-has-fpu"); + + // LUNA 共通だしここで作成しておく + gNull.reset(new NullDevice()); +} + +// デストラクタ +VM_LUNA::~VM_LUNA() +{ +} + +// デバイスマップから devtable を作成 (ここは共通にできる) +void +VM_LUNA::MakeDevtable(const uint8 *maptable) +{ + for (uint i = 0; i < countof(::devtable); i++) { + IODevice *d; + switch (maptable[i]) { + case NONE: d = gNull.get(); break; + case BUSERR: d = gBusErr.get(); break; + case PROM: d = prom.get(); break; + case MK48: d = gRTC.get(); break; + case PIO0: d = gPIO0.get(); break; + case PIO1: d = gPIO1.get(); break; + case SIO: d = gSIO.get(); break; + case TAS: d = gTAS.get(); break; + case SYSCLK: d = gSysClk.get(); break; + case ZRAM: d = gZRAM.get(); break; + case MROM: d = gNull.get(); break; + case BITMAP: d = gBitmap.get(); break; + case BT454: d = gBT454.get(); break; + case CRTC2: d = gCRTC2.get(); break; + case SCSI: d = gSPC.get(); break; + case LANCE: d = gEthernet.get(); break; + case FUSE: d = gFuseROM.get(); break; + case SYSCTL: d = gInterrupt.get(); break; + case CMMU: d = gCMMU.get(); break; + default: + __unreachable(); + } + ::devtable[i] = d; + } +} + +// 初期化 +bool +VM_LUNA::Init() +{ + // 親クラス + if (inherited::Init() == false) { + return false; + } + + // RAM 容量が確定したので、ここで devtable に RAM を配置。 + int ram_size_MB = gRAM->GetSizeMB(); + int i = 0; + while (ram_size_MB >= 16) { + // 16MB あれば RAM が直接担当 + ::devtable[i++] = gRAM.get(); + ram_size_MB -= 16; + } + // 16MB 未満なら PartialRAM が担当 + if (ram_size_MB > 0) { + ::devtable[i] = gPartialRAM.get(); + } + + return true; +} + +void +VM_LUNA::PowerButton() +{ + // LUNA の電源ボタンは電源オンにしか使わない。 + // + // 電源 ボタン + // ON PUSH (何も起きない) + // OFF PUSH 電源オン + + // スケジューラに指示 + gScheduler->RequestPowerOn(); +} + +// ブートページを切り替える。 +void +VM_LUNA::SwitchBootPage(Device *parent, bool isrom) +{ + // 共通処理 + inherited::SwitchBootPage(parent, isrom); + + // ROM は 128KB しかないので 16MB まるごと切り替わったりはしないとは + // 思うけど、具体的にどの範囲が切り替わるのかを知る方法がないのと + // 大して副作用もないので、先頭の 1ブロックをまるごと切り替えておく。 + if (isrom) { + ::devtable[0] = prom.get(); + } else { + ::devtable[0] = gRAM.get(); + } +} + + +// +// LUNA-I +// + +// LUNA-I のデバイス割り当て表 (上位8ビット) // // 仕様 実際 // 00 00 メインメモリ @@ -68,36 +215,12 @@ // f1 f0..f3 LANCE (WW、N=2 でミラー) // -- f4..ff 0xff が読めるようだ -// デバイスマップ用の識別子 -enum { - NONE, - BUSERR, - RAM, - PROM, - MK48, - PIO0, - PIO1, - SIO, - TAS, - SYSCLK, - ZRAM, - MROM, - BITMAP, - BT454, - CRTC2, - SCSI, - LANCE, - FUSE, -}; - -// -// LUNA-I -// - /*static*/ const uint8 -VM_LUNA::maptable[256] = { - // 01,02,03 は実際には二重バスフォールトになるがそれは未対応 - RAM, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 00 +VM_LUNA1::maptable[256] = { + // (00,)01,02,03 は実際にはたぶんパリティチェックが入っていて(?) + // 非実装領域にアクセスすると二重バスフォールトになるがそれは未対応。 + // RAM は Init() で動的に配置する。 + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 00 NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 08 BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 10 BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 18 @@ -135,89 +258,66 @@ VM_LUNA::maptable[256] = { }; // コンストラクタ -VM_LUNA::VM_LUNA() +VM_LUNA1::VM_LUNA1() { + // 機種固有パラメータ + // MPU クロックの初期値は機種ごとに異なる。単位は MHz + gConfig->SetDefault("mpu-clock", 20); + // RAM 初期値は MAX にしておく + gConfig->SetDefault("ram-size", 16); + // SPC の入力クロック (おそらく 6.144MHz = 163ns が入ってる) + gConfig->Add("!spc-tCLF", 163); + // LUNA-I のクロック割り込みは 60Hz + gConfig->Add("!sysclk-period", 16.666667_msec); + // デバイス (順序に注意) - // Scheduler (と BusErrDevice) は親コンストラクタで作成済み。 - gMPU.reset(new MPU680x0Device(0x41000000)); - gRAM.reset(new RAMDevice()); - if (gConfig->Get("prom-use-rom").AsInt() && gMainApp.host_file == NULL) { - gPROM.reset(new PROMDevice()); + // BusErrDevice, NullDevice は親コンストラクタで作成済み。 + + gMPU.reset(new MPU680x0Device()); // required by Scheduler + gScheduler.reset(new Scheduler()); // required by * + gInterrupt.reset(new LunaInterrupt()); + gRAM.reset(new RAMDevice()); // required by PartialRAM + gPartialRAM.reset(new PartialRAMDevice()); + gEthernet.reset(new BusIO_W()); // required by PROM + if (gMainApp.host_file || gConfig->Find("prom-image").AsString().empty()) { + prom.reset(new Luna1PROMEmuDevice()); } else { - gPROM.reset(new LunaPROMEmuDevice()); + prom.reset(new PROMDevice()); } gRTC.reset(new BusIO_B()); gPIO0.reset(new BusIO_B()); gPIO1.reset(new BusIO_B()); gSIO.reset(new BusIO_BB()); - sysclk.reset(new BusIO_B()); + gSysClk.reset(new BusIO_B()); + gTAS.reset(new BusIO_B()); gZRAM.reset(new ZRAMDevice()); - gBitmap.reset(new BitmapDevice()); // required by BT454 + gBitmap.reset(new BitmapDevice()); // required by BT454 gBT454.reset(new BusIO_B()); - crtc2.reset(new BusIO_B()); + gCRTC2.reset(new BusIO_B()); gSPC.reset(new BusIO_BBBB()); - gEthernet.reset(new BusIO_W()); - nulldev.reset(new NullDevice()); gLCD.reset(new LCDDevice()); gKeyboard.reset(new LunaKeyboard()); gRenderer.reset(new LunaRenderer()); // デバイスマップから devtable を作成 - for (uint i = 0; i < countof(::devtable); i++) { - IODevice *d; - switch (maptable[i]) { - case NONE: d = nulldev.get(); break; - case BUSERR: d = buserr.get(); break; - case RAM: d = gRAM.get(); break; - case PROM: d = gPROM.get(); break; - case MK48: d = gRTC.get(); break; - case PIO0: d = gPIO0.get(); break; - case PIO1: d = gPIO1.get(); break; - case SIO: d = gSIO.get(); break; - case TAS: d = gZRAM.get(); break; - case SYSCLK: d = sysclk.get(); break; - case ZRAM: d = gZRAM.get(); break; - case MROM: d = nulldev.get(); break; - case BITMAP: d = gBitmap.get(); break; - case BT454: d = gBT454.get(); break; - case CRTC2: d = crtc2.get(); break; - case SCSI: d = gSPC.get(); break; - case LANCE: d = gEthernet.get(); break; - default: - __unreachable(); - } - ::devtable[i] = d; - } + MakeDevtable(maptable); } // デストラクタ -VM_LUNA::~VM_LUNA() -{ -} - -void -VM_LUNA::PowerButton() +VM_LUNA1::~VM_LUNA1() { - // LUNA の電源ボタンは電源オンにしか使わない。 - // - // 電源 ボタン - // ON PUSH (何も起きない) - // OFF PUSH 電源オン - - // デバイスに指示 - DevicePowerOn(); } - // // LUNA88K // /*static*/ const uint8 VM_LUNA88K::maptable[256] = { - RAM, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 00 - NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 08 + // RAM は Init() で動的に配置する。 + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 00 + NONE, NONE, NONE, NONE, NONE, NONE, NONE, BUSERR, // 08 BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 10 BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 18 BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 20 @@ -226,14 +326,13 @@ VM_LUNA88K::maptable[256] = { BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 38 // LUNA88K2 は 47 に(も?) NVRAM がいるようだ - // 65 に割り込みコントローラ? // 69,6b,6d にも何かのコントローラ? PROM, PROM, PROM, FUSE, MK48, MK48, MK48, MK48, // 40 PIO0, PIO0, PIO0, PIO0, PIO1, PIO1, PIO1, PIO1, // 48 SIO, SIO, SIO, SIO, NONE, NONE, NONE, NONE, // 50 NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 58 - TAS, TAS, SYSCLK, SYSCLK, NONE, NONE, NONE, NONE, // 60 - NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 68 + TAS, TAS, SYSCLK, SYSCLK, NONE, SYSCTL, NONE, NONE, // 60 + NONE, SYSCTL, NONE, NONE, NONE, SYSCTL, NONE, NONE, // 68 ZRAM, ZRAM, ZRAM, ZRAM, ZRAM, ZRAM, ZRAM, ZRAM, // 70 ZRAM, ZRAM, ZRAM, ZRAM, ZRAM, ZRAM, ZRAM, ZRAM, // 78 @@ -247,7 +346,6 @@ VM_LUNA88K::maptable[256] = { BUSERR, BITMAP, BUSERR, BITMAP, BUSERR, BITMAP, BUSERR, BITMAP, // b8 // d0 にボードチェックレジスタ? - // ff に CMMU BUSERR, BT454, BUSERR, BT454, BUSERR, BT454, BUSERR, BT454, // c0 BUSERR, BT454, BUSERR, BT454, BUSERR, BT454, BUSERR, BT454, // c8 BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, // d0 @@ -255,76 +353,63 @@ VM_LUNA88K::maptable[256] = { SCSI, SCSI, SCSI, SCSI, NONE, NONE, NONE, NONE, // e0 NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // e8 LANCE, LANCE, LANCE, LANCE, NONE, NONE, NONE, NONE, // f0 - NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // f8 + NONE, NONE, NONE, NONE, NONE, NONE, NONE, CMMU, // f8 }; // コンストラクタ VM_LUNA88K::VM_LUNA88K() { + // 機種固有パラメータ + // MPU クロックの初期値は機種ごとに異なる。単位は MHz + gConfig->SetDefault("mpu-clock", 25); + // RAM 初期値は MAX にしておく + gConfig->SetDefault("ram-size", 64); + // SPC の入力クロック (XXX LUNA-I と同じ?) + gConfig->Add("!spc-tCLF", 163); + // LUNA-II, LUNA88K, LUNA88K2 のクロック割り込みは 100Hz らしい + gConfig->Add("!sysclk-period", 10_msec); + + // この機種に不要なパラメータはここで削除する + // (機種が決まるより前に全機種の設定の和集合を用意してあるため) + gConfig->Delete("mpu-has-fpu"); + // デバイス (順序に注意) - // Scheduler (と BusErrDevice) は親コンストラクタで作成済み。 - gMPU.reset(new MPU88xx0Device(0x41000000)); - gRAM.reset(new RAMDevice()); - if (0) { - //gPROM.reset(new PROMDevice()); + // BusErrDevice, NullDevice は親コンストラクタで作成済み。 + + gMPU.reset(new MPU88xx0Device()); // required by Scheduler + gScheduler.reset(new Scheduler()); // required by * + gInterrupt.reset(new SysCtlrDevice()); + gRAM.reset(new RAMDevice()); // required by PartialRAM + gPartialRAM.reset(new PartialRAMDevice()); + if (gMainApp.host_file || gConfig->Find("prom-image").AsString().empty()) { + prom.reset(new Luna88kPROMEmuDevice()); } else { - gPROM.reset(new Luna88kPROMEmuDevice()); + prom.reset(new PROMDevice()); } gRTC.reset(new BusIO_BFFF()); - gPIO0.reset(new PIO0Device()); - gPIO1.reset(new PIO1Device()); + gPIO0.reset(new BusIO_BFFF()); + gPIO1.reset(new BusIO_BFFF()); gSIO.reset(new BusIO_BFFF()); - sysclk.reset(new SysClkDevice()); + gSysClk.reset(new BusIO_BFFF()); + gTAS.reset(new BusIO_BFFF()); gZRAM.reset(new ZRAMDevice()); - gBitmap.reset(new BitmapDevice()); // required by BT454 + gBitmap.reset(new BitmapDevice()); // required by BT454 gBT454.reset(new BusIO_B()); - crtc2.reset(new BusIO_BFFF()); + gCRTC2.reset(new BusIO_BFFF()); gSPC.reset(new BusIO_BFFF()); - //gEthernet.reset(new BusIO_WF()); - fuserom.reset(new FuseROMDevice()); - nulldev.reset(new NullDevice()); + gEthernet.reset(new BusIO_WF()); // required by FuseROM + gFuseROM.reset(new BusIO_BFFF()); + gCMMU.reset(new CMMUDevice()); gLCD.reset(new LCDDevice()); gKeyboard.reset(new LunaKeyboard()); gRenderer.reset(new LunaRenderer()); // デバイスマップから devtable を作成 - for (uint i = 0; i < countof(::devtable); i++) { - IODevice *d; - switch (maptable[i]) { - case NONE: d = nulldev.get(); break; - case BUSERR: d = buserr.get(); break; - case RAM: d = gRAM.get(); break; - case PROM: d = gPROM.get(); break; - case MK48: d = gRTC.get(); break; - case PIO0: d = gPIO0.get(); break; - case PIO1: d = gPIO1.get(); break; - case SIO: d = gSIO.get(); break; - case TAS: d = gZRAM.get(); break; - case SYSCLK: d = sysclk.get(); break; - case ZRAM: d = gZRAM.get(); break; - case MROM: d = nulldev.get(); break; - case BITMAP: d = gBitmap.get(); break; - case BT454: d = gBT454.get(); break; - case CRTC2: d = crtc2.get(); break; - case SCSI: d = gSPC.get(); break; - case LANCE: d = buserr.get(); break; // XXX not yet - case FUSE: d = fuserom.get(); break; - default: - __unreachable(); - } - ::devtable[i] = d; - } + MakeDevtable(maptable); } // デストラクタ VM_LUNA88K::~VM_LUNA88K() { } - -void -VM_LUNA88K::PowerButton() -{ - // デバイスに指示 - DevicePowerOn(); -}