File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / mainbus.h
Revision 1.1.1.7 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:00 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
//

//
// メインバス (共通部分)
//

#pragma once

#include "device.h"
#include "bus.h"
#include "textscreen.h"
#include <array>
#include <utility>

// メインバスの素質を持つクラス
class MainbusBaseDevice : public IODevice
{
	using inherited = IODevice;
 public:
	explicit MainbusBaseDevice(uint objid_);
	~MainbusBaseDevice() override;

	// メインバスの初期化
	virtual bool InitMainbus() = 0;

	// MPU からのリセット (ここ?)
	virtual void ResetByMPU();

	// ブートページを ROM に切り替える
	void SwitchBootPageToROM() { SwitchBootPage(true); }
	// ブートページを RAM に切り替える
	void SwitchBootPageToRAM() { SwitchBootPage(false); }

	// モニタ表示用にデバイス名を整形。
	static std::pair<std::string, TA> FormatDevName(const Device *dev);

 protected:
	// ブートページを切り替える (内部用)
	virtual void SwitchBootPage(bool isrom) = 0;
};

// 定数クラス。本当はインタフェースっぽくしたい
class AccStat
{
 public:
	// アクセス状況を記録・表示する際に切り捨てる下位ビット数
	static const uint SHIFT = 21;

	// メイン空間とバンクメモリ(1枚分)の要素数
	static const uint MAINLEN	= (1U << (32 - SHIFT));
	static const uint BANKLEN	= (1U << (24 - SHIFT));

	// アクセス状況
	static const uint8 WRITE	= 0x01;
	static const uint8 READ		= 0x02;
};

// メインバス (システムに1つ)
class MainbusDevice : public MainbusBaseDevice
{
	using inherited = MainbusBaseDevice;
	friend class WXAccStatPanel;

 public:
	// ダイナミックバスサイジング処理用のマクロっぽい関数。
	// 使い方は HVReadN()、HVWriteN() を参照。

	// 読み込み後の処理。
	// addr は読み込みに使ったアドレス、bd は読み込んだデータ。
	// 次の読み込み用にアドレスとサイズを更新して addr に書き戻す。
	static inline uint32
	DYNAMIC_BUS_SIZING_R(busaddr& addr, busdata bd)
	{
		uint32 reqsize = addr.GetSize();
		uint32 portsize = bd.GetSize();
		uint32 offset = addr.Addr() & (portsize - 1);
		uint32 datasize = portsize - offset;
		uint32 tmp = bd.Data();
		uint32 mask = 0xffffffffU >> ((4 - datasize) * 8);
		tmp &= mask;
		if (datasize == reqsize) {
			addr += reqsize;
			addr.ChangeSize(0);
		} else if (datasize > reqsize) {
			tmp >>= (datasize - reqsize) * 8;
			addr += reqsize;
			addr.ChangeSize(0);
		} else {
			tmp <<= (reqsize - datasize) * 8;
			addr += datasize;
			addr.ChangeSize(reqsize - datasize);
		}

		// 今回読み出した値を所定の位置に左シフトしたものを返す。
		return tmp;
	}

	// 書き込み後の処理部分。
	// addr、data は書き込みに使ったアドレスとデータ。r が書き込みの応答。
	// 次の書き込み用に、addr はアドレスとサイズを更新したもの、
	// data も使い終わった上位バイトをクリアしたものを書き戻す。
	static inline void
	DYNAMIC_BUS_SIZING_W(busaddr& addr, uint32& data, busdata r)
	{
		uint32 reqsize = addr.GetSize();
		uint32 portsize = r.GetSize();
		uint32 offset = addr.Addr() & (portsize - 1);
		uint32 datasize = std::min(portsize - offset, reqsize);

		addr += datasize;
		reqsize -= datasize;
		addr.ChangeSize(reqsize);
		data &= (1U << (reqsize * 8)) - 1;
	}

 public:
	explicit MainbusDevice(uint objid_);
	~MainbusDevice() override;

	bool Init() override;
	void ResetHard(bool poweron) override;

	// ハイパーバイザ的アクセスというか、
	// 今となってはミスアライン可能なアクセスというだけかも知れない。
	busdata HVRead1(uint32 addr);
	busdata HVRead2(uint32 addr);
	busdata HVRead4(uint32 addr);
	busdata HVWrite1(uint32 addr, uint32 data);
	busdata HVWrite2(uint32 addr, uint32 data);
	busdata HVWrite4(uint32 addr, uint32 data);
	// サイズを addr で指定する版
	busdata HVReadN(busaddr addr);
	busdata HVWriteN(busaddr addr, uint32 data);

	uint64 Peek4(uint32 addr);

	// 直近のアクセスアドレスを返す。
	// アクセス中のデバイスからは、自分へのアクセスとなったバスマスタでの
	// 物理アドレス。
	uint32 GetPaddr() const { return lastaddr; }

 protected:
	DECLARE_MONITOR_SCREEN(MonitorScreenAccStat);

	// 直近の (バスマスタからの) アクセスアドレス。
	// HV* アクセスでは更新しない。
	uint32 lastaddr;

	// アクセス状況は 32bit 空間全域を 2048 * 2MB ずつ。
	// (NEWS は読み出し時にマージする)
	std::array<uint8, AccStat::MAINLEN> accstat_read {};
	std::array<uint8, AccStat::MAINLEN> accstat_write {};
	// R, W をマージした表示用(要素数は機種による)
	std::vector<uint8> accstat_rw {};
	// デバイスの存在有無。MSB 側から 1bit = 16MB のビットマップ。
	std::array<uint8, 32> accstat_avail {};
	// アクセス状況のアドレス表示オフセット。NEWS だけ 0xc0
	uint accstat_baseaddr {};
	// アクセス状況が何ビット空間分か。NEWS だけ 30
	uint accstat_bitlen {};

	// X68030 バンクメモリの表示用アクセス状況。
	// (GUI からのアクセスの便宜のため共通クラスのこっちに置く)
	alignas(8) uint8 accbank[AccStat::BANKLEN * 2] {};

	Monitor *accstat_monitor {};
};

// 上位8ビットがテーブルで表せる構造のメインバス (共通部分)
class Mainbus24Device : public MainbusDevice
{
	using inherited = MainbusDevice;
 public:
	Mainbus24Device();
	~Mainbus24Device() override;

	busdata Read(busaddr addr) override;
	busdata Write(busaddr addr, uint32 data) override;
	busdata ReadBurst16(busaddr addr, uint32 *dst) override;
	busdata WriteBurst16(busaddr addr, const uint32 *src) override;
	busdata Peek1(uint32 addr) override;
	bool Poke1(uint32 addr, uint32 data) override;

 protected:
	DECLARE_MONITOR_SCREEN(MonitorScreen);

	void InitAccStat();

	std::array<IODevice *, 256> devtable {};

	Monitor *monitor {};

 private:
	inline IODevice *Decoder(uint32 addr) const;
};

inline MainbusDevice *GetMainbusDevice() {
	return Object::GetObject<MainbusDevice>(OBJ_MAINBUS);
}

unix.superglobalmegacorp.com

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