File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / mainbus_x68k.cpp
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:59 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// メインバス (X68030)
//

// IODevice
//   +-- MainbusBaseDevice (InitMainbus() と FC アクセスを持つ)
//   |    +-- MainbusDevice (これがメインバス、システムに1つ)
//   |    |    +-- Mainbus24Device (上位8ビットがテーブルで表せるメインバス)
//   |    |    |    +-- LunaMainbus
//   |    |    |    |    +-- Luna1Mainbus
//   |    |    |    |    +-- Luna88kMainbus
//   |    |    |    +-- NewsMainbus
//   |    |    |    +-- Virt68kMainbus
//   |    |    |
//   |    |    |  +-------------+
//   |    |    +--| X68kMainbus |(上位8ビットが IODevice で表せないため)
//   |    |       +-------------+
//   |    |
//   |    +-- X68kIODevice (FC を受け取るため)
//   |
//   +-- XPbusDevice

#include "mainbus_x68k.h"
#include "bankram.h"
#include "extram.h"
#include "interrupt.h"
#include "mainapp.h"
#include "monitor.h"
#include "x68kio.h"

// コンストラクタ
X68kMainbus::X68kMainbus()
	: inherited(OBJ_MAINBUS)
{
	// デバイス
	NEWDV(Interrupt, new X68030Interrupt());
	NEWDV(X68kIO, new X68kIODevice());
	NEWDV(ExtRAM, new ExtRAMDevice());

	// デバイスの割り当ては Init() で行っている。

	monitor = gMonitorManager->Regist(ID_MONITOR_MAINBUS, this);
	monitor->SetCallback(&X68kMainbus::MonitorScreen);
	monitor->SetSize(75, 33);

	accstat_monitor->SetCallback(&X68kMainbus::MonitorScreenAccStat);
	accstat_monitor->SetSize(80, 2 + 32 + 3);
}

// デストラクタ
X68kMainbus::~X68kMainbus()
{
}

// 初期化
bool
X68kMainbus::Init()
{
	if (inherited::Init() == false) {
		return false;
	}

	for (int i = 0; i < bankram.size(); i++) {
		bankram[i] = gMainApp.FindObject<BankRAMDevice>(OBJ_BANKRAM(i));
	}

	return true;
}

// メインバスの初期化
bool
X68kMainbus::InitMainbus()
{
	int extstart;
	int extsize;

	// 拡張メモリはサイズが確定した後のここで配置。
	extsize = pExtRAM->GetSizeMB();

	// 上位8ビット全域を一旦全部内蔵空間にしてから
	std::fill(is_intio.begin(), is_intio.end(), true);

	if (extsize == 16) {
		// TS-6BE16 互換 (16MB) なら $01 の 16MB。
		extstart = 16;
		is_intio[1] = false;
	} else {
		// 060turbo 互換なら $10 から。
		extstart = 256;
		for (int i = 0x10, end = i + (extsize / 16); i < end; i++) {
			is_intio[i] = false;
		}
	}

	// 親子構造になっている。
	if (pX68kIO->InitMainbus() == false) {
		return false;
	}

	// アクセス統計のデバイスがある領域。
	accstat_avail[0] = 0x80;
	for (int i = extstart / 16; i < (extstart + extsize) / 16; i++) {
		accstat_avail[i / 8] |= 0x80U >> (i % 8);
	}

	return true;
}

// リセットについて。
//
//           PWRRESET
// 電源オン ----------+--> VIPS
// (7505)             +--> VideoCtlr
//                    +--> OSCIAN2
//                    |
//                    |   +------+
//                    +-->|      |
// 本体      SWRESET      | YUKI |
// リセット ------------->|      |
// スイッチ               +------+
//                         | IPLRESET
//                         |
//                         +--> FPU
//                         |
//                         ▽
//                   RESET |
//                         |<-> MPU (68030)
//                         +--> PPI (8255)
//                         +--> SPC (MB89352)
//                         +--> ADPCM (MSM6258)
//                         +--> FDC (uPD72065B)
//                         +--> MFP (MC68901)
//                         |
//                         |   +-------+
//                         +-->| PEDEC |
//                         |   +-------+
//                         |     |
//                         |     +-- OPMIC -----> OPM(YM2151)
//                         |     +-- SCCRD/WR --> SCC(Z8530)
//                         |
//                         |      EXRESET
//                         +---|>-----------> 外部バス
//                         ▽
//                SYSRESET |
//                         |<-> SAKI  ---+
//                         |             | BEC0,BEC1
//                         +--> DMAC  <--+
//                         +--> CYNTHIA
// リセットされない?
// o CACHY

// MPU の RESET 命令によるリセット
void
X68kMainbus::ResetByMPU()
{
	std::vector<int> ids {
		OBJ_ADPCM,
		OBJ_BANKRAM0,
		OBJ_BANKRAM1,
		OBJ_DMAC,
		OBJ_ETHERNET0,
		OBJ_ETHERNET1,
		OBJ_FDC,
		OBJ_MFP,
		OBJ_OPM,
		OBJ_PEDEC,
		OBJ_PLUTO,
		OBJ_PPI,
		OBJ_MPSCC,
		OBJ_SPC0,
		OBJ_WINDRV,
	};
	for (auto id : ids) {
		auto dev = gMainApp.FindObject<IODevice>(id);
		if (dev) {
			dev->ResetHard(false);
		}
	}
}

inline bool
X68kMainbus::IsIntio(uint32 addr) const
{
	return is_intio[(addr >> 24) & 0xff];
}

// 内蔵 16MB 分で折り返す
#define ACCSTAT_INTIO(pa)	\
	(((pa) >> AccStat::SHIFT) & ((1U << (24 - AccStat::SHIFT)) - 1))

busdata
X68kMainbus::Read(busaddr addr)
{
	uint32 pa = addr.Addr();
	lastaddr = pa;
	if (IsIntio(pa)) {
		// 内蔵 16MB を 2MB 単位で
		accstat_read[ACCSTAT_INTIO(pa)] = AccStat::READ;
		return pX68kIO->Read(addr);
	} else {
		// 拡張メモリのアドレスは折り返しは起きない
		accstat_read[pa >> AccStat::SHIFT] = AccStat::READ;
		return pExtRAM->Read(addr);
	}
}

busdata
X68kMainbus::Write(busaddr addr, uint32 data)
{
	uint32 pa = addr.Addr();
	lastaddr = pa;
	if (IsIntio(pa)) {
		// 内蔵 16MB を 2MB 単位で
		accstat_write[ACCSTAT_INTIO(pa)] = AccStat::WRITE;
		return pX68kIO->Write(addr, data);
	} else {	\
		// 拡張メモリのアドレスは折り返しは起きない
		accstat_write[pa >> AccStat::SHIFT] = AccStat::WRITE;
		return pExtRAM->Write(addr, data);
	}
}

busdata
X68kMainbus::Peek1(uint32 addr)
{
	if (IsIntio(addr)) {
		return pX68kIO->Peek1(addr);
	} else {
		return pExtRAM->Peek1(addr);
	}
}

bool
X68kMainbus::Poke1(uint32 addr, uint32 data)
{
	if (IsIntio(addr)) {
		return pX68kIO->Poke1(addr, data);
	} else {
		return pExtRAM->Poke1(addr, data);
	}
}

void
X68kMainbus::MonitorScreen(Monitor *, TextScreen& screen)
{
	screen.Clear();

	// 012345678901234567890
	// $0000'0000: 1234567

	for (int i = 0; i < 8; i++) {
		screen.Print(12 + i * 8, 0, "+$0%x", i);
	}

	auto xioname = FormatDevName(pX68kIO.get()).first;
	auto extname = FormatDevName(pExtRAM.get()).first;

	int idx = 0;
	for (int i = 0; i < is_intio.size() / 8; i++) {
		screen.Print(0, i + 1, "$%02x00'0000:", idx);
		for (int j = 0; j < 8; j++) {
			screen.Print(12 + j * 8, i + 1, "%s",
				(is_intio[idx] ? xioname : extname).c_str());
			idx++;
		}
	}
}

void
X68kMainbus::MonitorScreenAccStat(Monitor *monitor_, TextScreen& screen)
{
	// メインバス空間は親クラス側の処理そのまま。
	inherited::MonitorScreenAccStat(monitor_, screen);

	// バンクメモリ側の情報取得。
	for (int n = 0; n < bankram.size(); n++) {
		if (bankram[n]) {
			bankram[n]->FetchAccStat(&accbank[n * AccStat::BANKLEN]);
		}
	}

	// バンクメモリ側の描画。
	for (int n = 0; n < bankram.size(); n++) {
		int y = 35 + n;
		screen.Print(0, y, "BankMem #%u:", n);
		if (bankram[n]) {
			for (int i = 0; i < AccStat::BANKLEN; i++) {
				uint op = accbank[n * AccStat::BANKLEN + i] & 3;
				uint8 ch = ".RWA"[op];
				screen.Putc(12 + i, y, ch);
			}
		}
	}
}

// ブートページを切り替える。
void
X68kMainbus::SwitchBootPage(bool isrom)
{
	// X68030 ではすべて X68kIO が担当している
	pX68kIO->SwitchBootPage(isrom);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.