File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / xiospace.cpp
Revision 1.1.1.11 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:14 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v016, HEAD
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;
	}
}

unix.superglobalmegacorp.com

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