|
|
nono 1.5.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// メインバス (LUNA)
//
// IODevice
// +-- MainbusBaseDevice (InitMainbus() と FC アクセスを持つ)
// | +-- MainbusDevice (これがメインバス、システムに1つ)
// | | +-- Mainbus24Device (上位8ビットがテーブルで表せるメインバス)
// | | | | +-------------+
// | | | +--| LunaMainbus | (LUNA 共通部)
// | | | | +-------------+
// | | | | | +--------------+
// | | | | +--| Luna1Mainbus | (LUNA-I)
// | | | | | +--------------+
// | | | | | +----------------+
// | | | | +--| Luna88kMainbus | (LUNA-88K)
// | | | | +----------------+
// | | | |
// | | | +-- NewsMainbus
// | | | +-- Virt68kMainbus
// | | +-- X68kMainbus
// | +-- X68kIODevice
// +-- XPbusDevice
#include "mainbus_luna.h"
#include "bt45x.h"
#include "buserr.h"
#include "busio.h"
#include "cmmu.h"
#include "config.h"
#include "crtc2.h"
#include "fuserom.h"
#include "interrupt.h"
#include "lance.h"
#include "lunafb.h"
#include "mainapp.h"
#include "mainram.h"
#include "mk48t02.h"
#include "msxdos.h"
#include "nop.h"
#include "partialram.h"
#include "pio.h"
#include "prom.h"
#include "romemu_luna1.h"
#include "romemu_luna88k.h"
#include "sio.h"
#include "spc.h"
#include "subram.h"
#include "sysclk.h"
#include "sysctlr.h"
#include "tas.h"
//
// LUNA 共通部
//
// デバイスマップ用の識別子
enum {
NONE,
BUSERR,
PROM,
MK48,
PIO0,
PIO1,
SIO,
TAS,
SYSCLK,
SUBRAM,
MROM,
LUNAFB,
BT45x,
CRTC2,
SCSI,
LANCE,
FUSE,
SYSCTL,
CMMU,
};
// コンストラクタ
LunaMainbus::LunaMainbus()
{
NEWDV(BusErr, new BusErrDevice());
NEWDV(NopIO, new NopIODevice());
accstat_monitor->SetSize(80, 2 + 32);
}
// デストラクタ
LunaMainbus::~LunaMainbus()
{
}
// デバイスマップから devtable を作成 (ここは共通にできる)
void
LunaMainbus::MakeDevtable(const uint8 *maptable)
{
for (int i = 0; i < devtable.size(); i++) {
IODevice *d;
switch (maptable[i]) {
case NONE: d = pNopIO.get(); break;
case BUSERR: d = pBusErr.get(); break;
case PROM: d = pPROM.get(); break;
case MK48: d = pRTC.get(); break;
case PIO0: d = pPIO0.get(); break;
case PIO1: d = pPIO1.get(); break;
case SIO: d = pSIO.get(); break;
case TAS: d = pTAS.get(); break;
case SYSCLK: d = pSysClk.get(); break;
case SUBRAM: d = pSubRAM.get(); break;
case MROM: d = pNopIO.get(); break;
case LUNAFB: d = pPlaneVRAM.get(); break;
case BT45x: d = pBT45x.get(); break;
case CRTC2: d = pCRTC2.get(); break;
case SCSI: d = pSPC.get(); break;
case LANCE: d = pEthernet.get(); break;
case SYSCTL: d = pInterrupt.get(); break;
// これらはサブクラスが所有しているので Get で取得する必要がある。
case FUSE: d = GetFuseROMDevice(); break;
case CMMU: d = GetCMMUDevice(); break;
default:
PANIC("corrupted maptable[%u]=%d", i, maptable[i]);
}
devtable[i] = d;
}
}
// メインバスの初期化
bool
LunaMainbus::InitMainbus()
{
auto mainram = dynamic_cast<MainRAMDevice *>(pMainRAM.get());
auto partial = dynamic_cast<PartialRAMDevice *>(pPartialRAM.get());
// RAM は容量が確定した後のここで配置。
uint ram_size_MB = mainram->GetSizeMB();
int i = 0;
while (ram_size_MB >= 16) {
// 16MB あれば RAM が直接担当
devtable[i++] = mainram;
ram_size_MB -= 16;
}
// 16MB 未満なら PartialRAM が担当
if (ram_size_MB > 0) {
devtable[i] = partial;
}
// 先頭 (mainram or partial) をブートページ切り替え用に覚えておく。
ram0 = devtable[0];
// アクセス状況用のマップを作成。
InitAccStat();
return true;
}
// ブートページを切り替える。
void
LunaMainbus::SwitchBootPage(bool isrom)
{
// 共通処理
inherited::SwitchBootPage(isrom);
// ROM は 128KB しかないので 16MB まるごと切り替わったりはしないとは
// 思うけど、具体的にどの範囲が切り替わるのかを知る方法がないのと
// 大して副作用もないので、先頭の 1ブロックをまるごと切り替えておく。
if (isrom) {
auto prom0 = GetPROM0Device();
devtable[0x00] = prom0;
devtable[0x41] = prom0;
} else {
auto prom = GetPROMDevice();
devtable[0x00] = ram0;
devtable[0x41] = prom;
}
}
//
// LUNA-I
//
// LUNA-I のデバイス割り当て表 (上位8ビット)
//
// 仕様 実際
// 00 00 メインメモリ
// -- 01..03 二重バスフォールトするようだ
// -- 04..0f 何かよく分からないものが読める
// -- 10..3f BUSERR
// 41 40..43 PROM (B、N=128KBでミラー)
// 45 44..47 mk48t02 (B、N=2048でミラー)
// 49 48..4b pio0 (B、N=4でミラー)
// 4d 4c..4f pio1 (B、N=4でミラー)
// 51 50..53 sio (BB、N=4でミラー)
// -- 54..5f 0xff が読めるようだ
// 61 60..61 TAS (B、N=1でミラー)
// 63 62..63 システムクロック (B、N=1でミラー)
// -- 以降TASとSysClkで2枠ずつ。また無効ビットの読み出しは
// -- 必ずしも Hi とは限らず不安定のようだ。
// 71 70..7f 3ポートRAM (B、N=128KBでミラー)
// 81 80.. BUSERR (オンボード拡張スロットA)
// 83 ..8f BUSERR (オンボード拡張スロットB)
// 91 90..9f 0xff が読めるようだ (PC-9000 拡張スロット)
//
// a1 マスクROM
// a0,a2,a4,... BUSERR
// a1,a3,a5,... マスクROM(なければ0xffが読める)
// b1 ビットマップ
// b0,b2,b4,... BUSERR
// b1,b3,b5,... ビットマップ (内訳は lunafb.cpp 参照)
// c1 パレット
// c0,c2,c4,... BUSERR
// c1,c3,c5,... パレット (B、N=4でミラー)
// d1 CRTC-II
// d0,d2,d4,... BUSERR
// d1,d3,d5,... CRTC-II (B、N=2でミラー)
//
// e1 e0..e3 SCSI (BBBB、N=16 でミラー)
// -- e4..ef 0xff が読めるようだが不安定。
// f1 f0..f3 LANCE (WW、N=2 でミラー)
// -- f4..ff 0xff が読めるようだ
/*static*/ const uint8
Luna1Mainbus::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
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 20
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 28
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 30
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 38
PROM, PROM, PROM, PROM, 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, TAS, TAS, SYSCLK, SYSCLK, // 60
TAS, TAS, SYSCLK, SYSCLK, TAS, TAS, SYSCLK, SYSCLK, // 68
SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, // 70
SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, // 78
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 80
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 88
NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 90
NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // 98
BUSERR, MROM, BUSERR, MROM, BUSERR, MROM, BUSERR, MROM, // a0
BUSERR, MROM, BUSERR, MROM, BUSERR, MROM, BUSERR, MROM, // a8
BUSERR, LUNAFB, BUSERR, LUNAFB, BUSERR, LUNAFB, BUSERR, LUNAFB, // b0
BUSERR, LUNAFB, BUSERR, LUNAFB, BUSERR, LUNAFB, BUSERR, LUNAFB, // b8
BUSERR, BT45x, BUSERR, BT45x, BUSERR, BT45x, BUSERR, BT45x, // c0
BUSERR, BT45x, BUSERR, BT45x, BUSERR, BT45x, BUSERR, BT45x, // c8
BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, // d0
BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, // d8
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
};
// コンストラクタ
Luna1Mainbus::Luna1Mainbus()
{
// デバイス (順序に注意)
// BusErrDevice, NopIODevice は親コンストラクタで作成済み。
NEWDV(Interrupt, new LunaInterrupt());
NEWDV(RTC, new BusIO_B<MK48T02Device>()); // required by SysClk
NEWDV(SysClk, new BusIO_B<SysClkDevice>()); // required by PROMEmu
if (gMainApp.msxdos_mode) {
NEWDV(PROM, new MSXDOSDevice());
} else if (gMainApp.exec_file ||
gConfig->Find("prom-image").AsString().empty()) {
NEWDV(PROM, new Luna1PROMEmuDevice());
} else {
NEWDV(PROM, new PROMDevice()); // required by RAM,BT45x
}
NEWDV(PROM0, new PROM0Device());
NEWDV(MainRAM, new MainRAMDevice()); // required by PartialRAM
NEWDV(PartialRAM, new PartialRAMDevice());
NEWDV(PIO0, new BusIO_B<PIO0Device>());
NEWDV(PIO1, new BusIO_B<PIO1Device>());
NEWDV(SIO, new BusIO_BB<SIODevice>());
NEWDV(TAS, new BusIO_B<TASDevice>());
NEWDV(SubRAM, new SubRAMDevice(128));
NEWDV(CRTC2, new BusIO_B<CRTC2Device>());
NEWDV(SPC, new BusIO_BBBB<SPCDevice>());
NEWDV(Ethernet, new BusIO_W<LanceDevice>());
}
// デストラクタ
Luna1Mainbus::~Luna1Mainbus()
{
}
// 動的なコンストラクション
bool
Luna1Mainbus::Create()
{
int nplane = BT45xDevice::GetConfigPlaneCount();
if (nplane < 0) {
return false;
}
if (nplane == 8) { // required by Lunafb
NEWDV(BT45x, new BusIO_BFFF<BT458Device>());
} else {
NEWDV(BT45x, new BusIO_B<BT454Device>());
}
NEWDV(PlaneVRAM, new LunafbDevice());
// 全部揃ったここで、デバイスマップから devtable を作成。
MakeDevtable(maptable);
return true;
}
//
// LUNA-88K
//
// 00..03 RAM (64MB 実機の場合)
// 04..3f バスエラー
// 40,41 PROM (B、N=256KB でミラー)
// 42,43 FUSEROM (BFFF、N=256 でミラー)
// 44,45 NVRAM (BFFF、N=2048 でミラー)
// 46,47 バスエラー
// 48,49 PIO0 (BFFF、N=4 でミラー)
// 4a,4b バスエラー
// 4c,4d PIO1 (BFFF、N=4 でミラー)
// 4e,4f バスエラー
// 50,51 SIO (BFFF、N=4 でミラー)
// 52..5f バスエラー
// 60,61 TAS? (BFFF、N=1 ?)
// 62,63 SysClk (BFFF、N=1 ?)
// 64,65,66,67 SysCtlr? (L、N=1 ?)
// 68,69,6a,6b SysCtlr? (L、N=4 ?)
// 6c,6d CPU リセット
// 6e,6f $ff (?)
// 70-7f SubRAM
// 80-9f バスエラー
// a0-af 偶数(a0,a2,..)はバスエラー、奇数(a1,a3,..)は $ff
// b0-bf 偶数(b0,b2,..)はバスエラー、奇数(b1,b3,..)は LUNAFB
// c0-cf 偶数(c0,c2,..)はバスエラー、奇数(c1,c3,..)は BT454(BFFF、N=4)
// d0-df 偶数(d0,d2,..)はバスエラー、奇数(d1,d3,..)はたぶん CRTC2
// (CRTC2 は今の所 $ff しか観測できていないので詳細不明)
// e0,e1 SPC (BFFF、N=16 でミラー)
// e2-ef $ff
// f0,f1 たぶん Lance (BFFF、N=2)
// f2-fd $ff
// fe $fe00'0000-$fef7'ffff まではアドレス(*)
// $fef8'0000-$feff'ffff までは $ff
// ff たぶん CMMU 以外はアドレス(*)
//
// バスエラーの領域は 3% くらいの確率で $ffffffff が読めることがある。まじか。
// (OpenBSD の CMMU 検出がバスエラーが起きるはずなのに起きなかった時のことを
// 考慮したコードになってるのはこのためだろうか…)
//
// アドレス(*) のところは、32ビットアドレスが読み出せる。バイトアクセスしても
// そのバイトに応じたところが読み出せるので 32ビットの (フルワード単位の)
// アドレスがデータバスに乗って返って来ているようだ…。
// 以下 PROM でのダンプ結果 (boot の machine read コマンドでも同じ)。
// 0> dw fe000000 fe00000f
// fe000000: fe000000 fe000004 fe000008 fe00000c
// 0> d fe000000 fe00000f
// fe000000: fe 00 00 00 fe 00 00 04 fe 00 00 08 fe 00 00 0c
/*static*/ const uint8
Luna88kMainbus::maptable[256] = {
// RAM は Init() で動的に配置する (64MB なら 00..03 の4枠)。
// 先頭 64MB の空間 (00..03) だけは、PROM 1.20 ではメモリが無いときでも
// バスエラーにならないことを期待しているので NONE にしておく。
// それ以降はバスエラー。
NONE, NONE, NONE, NONE, BUSERR, BUSERR, BUSERR, BUSERR, // 00
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, 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
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 28
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 30
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 38
// LUNA-88K2 は 47 に(も?) NVRAM がいるようだ
// 69,6b,6d にも何かのコントローラ?
PROM, PROM, FUSE, FUSE, MK48, MK48, BUSERR, BUSERR, // 40
PIO0, PIO0, BUSERR, BUSERR, PIO1, PIO1, BUSERR, BUSERR, // 48
SIO, SIO, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 50
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 58
TAS, TAS, SYSCLK, SYSCLK, SYSCTL, SYSCTL, SYSCTL, SYSCTL, // 60
SYSCTL, SYSCTL, SYSCTL, SYSCTL, SYSCTL, SYSCTL, SYSCTL, SYSCTL, // 68
SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, // 70
SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, SUBRAM, // 78
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 80
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 88
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 90
BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, BUSERR, // 98
BUSERR, MROM, BUSERR, MROM, BUSERR, MROM, BUSERR, MROM, // a0
BUSERR, MROM, BUSERR, MROM, BUSERR, MROM, BUSERR, MROM, // a8
BUSERR, LUNAFB, BUSERR, LUNAFB, BUSERR, LUNAFB, BUSERR, LUNAFB, // b0
BUSERR, LUNAFB, BUSERR, LUNAFB, BUSERR, LUNAFB, BUSERR, LUNAFB, // b8
// d0 にボードチェックレジスタ?
BUSERR, BT45x, BUSERR, BT45x, BUSERR, BT45x, BUSERR, BT45x, // c0
BUSERR, BT45x, BUSERR, BT45x, BUSERR, BT45x, BUSERR, BT45x, // c8
BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, // d0
BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, BUSERR, CRTC2, // d8
SCSI, SCSI, NONE, NONE, NONE, NONE, NONE, NONE, // e0
NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, // e8
LANCE, LANCE, NONE, NONE, NONE, NONE, NONE, NONE, // f0
NONE, NONE, NONE, NONE, NONE, NONE, NONE, CMMU, // f8
};
// コンストラクタ
Luna88kMainbus::Luna88kMainbus()
{
// デバイス (順序に注意)
// BusErrDevice, NopIODevice は親コンストラクタで作成済み。
NEWDV(Interrupt, new SysCtlrDevice());
NEWDV(RTC, new BusIO_BFFF<MK48T02Device>()); // required by SysClk
NEWDV(SysClk, new BusIO_BFFF<SysClkDevice>()); // required by PROMEmu
if (gMainApp.exec_file || gConfig->Find("prom-image").AsString().empty()) {
NEWDV(PROM, new Luna88kPROMEmuDevice());
} else {
NEWDV(PROM, new PROMDevice()); // required by RAM
}
NEWDV(PROM0, new PROM0Device());
NEWDV(MainRAM, new MainRAMDevice()); // required by PartialRAM
NEWDV(PartialRAM, new PartialRAMDevice());
NEWDV(FuseROM, new BusIO_BFFF<FuseROMDevice>());
NEWDV(PIO0, new BusIO_BFFF<PIO0Device>());
NEWDV(PIO1, new BusIO_BFFF<PIO1Device>());
NEWDV(SIO, new BusIO_BFFF<SIODevice>());
NEWDV(TAS, new BusIO_BFFF<TASDevice>());
NEWDV(SubRAM, new SubRAMDevice(128));
NEWDV(CRTC2, new BusIO_BFFF<CRTC2Device>());
NEWDV(SPC, new BusIO_BFFF<SPCDevice>());
NEWDV(Ethernet, new BusIO_WF<LanceDevice>());
NEWDV(CMMU, new CMMUDevice());
}
// デストラクタ
Luna88kMainbus::~Luna88kMainbus()
{
}
// 動的なコンストラクション
bool
Luna88kMainbus::Create()
{
int nplane = BT45xDevice::GetConfigPlaneCount();
if (nplane < 0) {
return false;
}
if (nplane == 8) { // required by Lunafb
NEWDV(BT45x, new BusIO_BFFF<BT458Device>());
} else {
NEWDV(BT45x, new BusIO_B<BT454Device>());
}
NEWDV(PlaneVRAM, new LunafbDevice());
// 全部揃ったここで、デバイスマップから devtable を作成。
MakeDevtable(maptable);
return true;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.