|
|
nono 0.4.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// X68030 のメイン空間 ($000000-$FFFFFF) 担当
//
#include "xiospace.h"
#include "adpcm.h"
#include "areaset.h"
#include "busio.h"
#include "config.h"
#include "crtc.h"
#include "dmac.h"
#include "fdc.h"
#include "gvram.h"
#include "mfp.h"
#include "opm.h"
#include "pedec.h"
#include "pio.h"
#include "pluto.h"
#include "printer.h"
#include "ram.h"
#include "romemu_x68k.h"
#include "romimg_x68k.h"
#include "rp5c15.h"
#include "scc.h"
#include "spc.h"
#include "sprite.h"
#include "sram.h"
#include "sysport.h"
#include "tvram.h"
#include "videoctlr.h"
#include "vm.h"
//
// 1つの 8KB ブロックを複数のデバイスで共有する場合
//
class MuxDevice : public IODevice
{
using inherited = IODevice;
public:
MuxDevice();
virtual ~MuxDevice() override;
uint64 Read8(uint32 addr) override;
uint64 Read16(uint32 addr) override;
uint64 Write8(uint32 addr, uint32 data) override;
uint64 Write16(uint32 addr, uint32 data) override;
uint64 Peek8(uint32 addr) override;
IODevice *SearchDevice(uint32 addr) const;
void AddDevice(IODevice *dev);
std::vector<IODevice*> devlist;
};
// コンストラクタ
MuxDevice::MuxDevice()
: inherited("MuxDevice")
{
}
// デストラクタ
MuxDevice::~MuxDevice()
{
}
// デバイスを追加する。
// ここに追加するデバイスは dev->devlen を指定すること。
void
MuxDevice::AddDevice(IODevice *dev)
{
assertmsg(dev->devlen != 0, "MuxDevice::AddDevice '%s'",
dev->GetName().c_str());
devlist.push_back(dev);
}
IODevice *
MuxDevice::SearchDevice(uint32 addr) const
{
for (const auto& d : devlist) {
if (d->devaddr <= addr && addr < d->devaddr + d->devlen) {
return d;
}
}
return nullptr;
}
uint64
MuxDevice::Read8(uint32 addr)
{
IODevice *d = SearchDevice(addr);
if (d == nullptr) {
return (uint64)-1;
}
return d->Read8(addr);
}
uint64
MuxDevice::Read16(uint32 addr)
{
IODevice *d = SearchDevice(addr);
if (d == nullptr) {
return (uint64)-1;
}
return d->Read16(addr);
}
uint64
MuxDevice::Write8(uint32 addr, uint32 data)
{
IODevice *d = SearchDevice(addr);
if (d == nullptr) {
return (uint64)-1;
}
return d->Write8(addr, data);
}
uint64
MuxDevice::Write16(uint32 addr, uint32 data)
{
IODevice *d = SearchDevice(addr);
if (d == nullptr) {
return (uint64)-1;
}
return d->Write16(addr, data);
}
uint64
MuxDevice::Peek8(uint32 addr)
{
IODevice *d = SearchDevice(addr);
if (d == nullptr) {
return (uint64)-1;
}
return d->Peek8(addr);
}
//
// X68030 のメイン空間担当
//
// グローバル参照用
XIOSpaceDevice *gXIOSpace;
// コンストラクタ
XIOSpaceDevice::XIOSpaceDevice()
: inherited("IOSpace")
{
#define ADD_DEVICE(NAME, NEW_CTOR) do { \
NEWDV(NAME, NEW_CTOR); \
AddDevice(dynamic_cast<IODevice *>(__CONCAT(p,NAME).get())); \
} while (0)
// デバイスクラス作成 (順序に注意)
ADD_DEVICE(ADPCM, new BusIO_EB<ADPCMDevice>());
ADD_DEVICE(AreaSet, new AreaSetDevice());
ADD_DEVICE(CGROM, new CGROMDevice());
ADD_DEVICE(CRTC, new BusIO_W<CRTCDevice>());
ADD_DEVICE(DMAC, new DMACDevice());
ADD_DEVICE(FDC, new BusIO_EB<FDCDevice>());
ADD_DEVICE(GVRAM, new GVRAMDevice());
ADD_DEVICE(PEDEC, new BusIO_EB<PEDECDevice>());
ADD_DEVICE(IPLROM1, new IPLROM1Device());
if (gConfig->Find("iplrom2-image").AsString().empty()) {
ADD_DEVICE(IPLROM2, new ROM30EmuDevice());
} else {
ADD_DEVICE(IPLROM2, new IPLROM2Device());
}
ADD_DEVICE(MFP, new BusIO_EB<MFPDevice>());
ADD_DEVICE(PlaneVRAM, new TVRAMDevice());
ADD_DEVICE(Pluto, new PlutoDevice());
ADD_DEVICE(PPI, new BusIO_EB<PPIDevice>());
ADD_DEVICE(Printer, new PrinterDevice());
ADD_DEVICE(RTC, new BusIO_EB<RP5C15Device>());
ADD_DEVICE(SCC, new BusIO_EB<SCCDevice>());
ADD_DEVICE(SRAM, new SRAMDevice()); // Required by SPC
ADD_DEVICE(SPC, new BusIO_X68kSPC<SPCDevice>());
ADD_DEVICE(Sprite, new SpriteDevice());
ADD_DEVICE(Sysport, new BusIO_FB<SysportDevice>());
ADD_DEVICE(VideoCtlr, new BusIO_W<VideoCtlrDevice>());
ADD_DEVICE(OPM, new BusIO_EB<OPMDevice>());
}
// デストラクタ
XIOSpaceDevice::~XIOSpaceDevice()
{
gXIOSpace = NULL;
}
bool
XIOSpaceDevice::Init()
{
// RAM のみ RamDevice::Init() で ram_size が決定してから行う。
int ram_size = gRAM->GetSize();
for (int i = 0; i < ram_size / 8192; i++) {
table[i] = gRAM;
}
// 必要なデバイスは全部埋めたので、この時点で nullptr なエントリを
// BusErr に差し替える。
for (auto&& d : table) {
if (d == nullptr) {
d = gBusErr;
}
}
// デバッグ表示
if (0) {
for (int i = 1536; i < table.size(); i++) {
printf("[%3d] $%06x ", i, i * 8192);
assert(table[i]);
if (dynamic_cast<MuxDevice*>(table[i])) {
printf("MuxDevice\n");
} else {
printf("%s\n", table[i]->GetName().c_str());
}
}
}
return true;
}
// デバイステーブルに dev を追加する。
// ここに追加するデバイスは dev->devlen を指定すること。
void
XIOSpaceDevice::AddDevice(IODevice *dev)
{
assertmsg(dev->devaddr != 0, "XIOSpaceDevice:AddDevice '%s'",
dev->GetName().c_str());
assertmsg(dev->devlen != 0, "XIOSpaceDevice:AddDevice '%s'",
dev->GetName().c_str());
int idx = dev->devaddr / 8192;
for (int i = idx; i < idx + (dev->devlen + 8191) / 8192; i++) {
if (table[i] == nullptr) {
table[i] = dev;
} else {
MuxDevice *mux = dynamic_cast<MuxDevice*>(table[i]);
if (mux) {
mux->AddDevice(dev);
} else {
MuxDevice *muxdev = new MuxDevice();
muxdev->AddDevice(table[i]);
muxdev->AddDevice(dev);
table[i] = muxdev;
}
}
}
}
uint64
XIOSpaceDevice::Read8(uint32 addr)
{
addr &= 0x00ffffff;
IODevice *d = SearchDevice(addr);
return d->Read8(addr);
}
uint64
XIOSpaceDevice::Read16(uint32 addr)
{
addr &= 0x00ffffff;
IODevice *d = SearchDevice(addr);
return d->Read16(addr);
}
uint64
XIOSpaceDevice::Read32(uint32 addr)
{
addr &= 0x00ffffff;
IODevice *d = SearchDevice(addr);
return d->Read32(addr);
}
uint64
XIOSpaceDevice::Write8(uint32 addr, uint32 data)
{
addr &= 0x00ffffff;
IODevice *d = SearchDevice(addr);
return d->Write8(addr, data);
}
uint64
XIOSpaceDevice::Write16(uint32 addr, uint32 data)
{
addr &= 0x00ffffff;
IODevice *d = SearchDevice(addr);
return d->Write16(addr, data);
}
uint64
XIOSpaceDevice::Write32(uint32 addr, uint32 data)
{
addr &= 0x00ffffff;
IODevice *d = SearchDevice(addr);
return d->Write32(addr, data);
}
uint64
XIOSpaceDevice::Peek8(uint32 addr)
{
addr &= 0x00ffffff;
IODevice *d = SearchDevice(addr);
return d->Peek8(addr);
}
// ブートページを切り替える。
// (VM_X68030::SwitchBootPage() の下請け)
void
XIOSpaceDevice::SwitchBootPage(bool isrom)
{
IODevice *ram;
IODevice *rom;
if (isrom) {
// 0x000000 からの 64KB ( 8エントリ)、
// 0xfe0000 からの 128KB (16エントリ) のどちらも IPLROM0 が担当する。
ram = gIPLROM0;
rom = gIPLROM0;
} else {
// 0x000000 からの 64KB ( 8エントリ) に RAM を見せる。
// 0xfe0000 からの 128KB (16エントリ) に IPLROM1 を見せる。
ram = gRAM;
rom = gIPLROM1;
}
for (int i = 0; i < 8; i++) {
table[i] = ram;
}
for (int i = 0; i < 16; i++) {
table[table.size() - 16 + i] = rom;
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.