|
|
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);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.