File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / device.h
Revision 1.1.1.19 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:01 2026 UTC (3 months 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 "object.h"
#include "bus.h"
#include "nono.h"

#if BYTE_ORDER == LITTLE_ENDIAN
#define HB(addr)	((addr) ^ 1)
#define HLB(addr)	((addr) ^ 3)
#define HLW(addr)	((addr) ^ 2)
#else
#define HB(addr)	(addr)
#define HLB(addr)	(addr)
#define HLW(addr)	(addr)
#endif

// デバイスを作成して代入するマクロ。
// …だったが今となってはあまり意味がなくなっている。
#define NEWDV(NAME, NEW_CTOR)	do {	\
	__CONCAT(p,NAME).reset(NEW_CTOR);	\
	assert((bool)__CONCAT(p,NAME));	\
} while (0)

// 前方参照
class Device;
class Event;
class MainMPUDevice;
class Scheduler;

using EventCallback_t = void (Device::*)(Event *);

class Device : public Object
{
	using inherited = Object;
 protected:
	explicit Device(uint objid_);
 public:
	~Device() override;

 public:
	// 初期化は以下の手順で行う。
	// 1. コンストラクタ
	//	メンバ変数の初期値代入などを行う。失敗するケースは考慮していない。
	//	gConfig の内部変数の追加はここ(か2.の動的コンストラクション)で
	//	行うこと。この時点ですでに gConfig の設定内容の参照は可能だが、
	//	エラーが出るものはここではなく Create() か Init() で処理すること。
	//	putmsg() は使えない。
	//
	// 2. Create() ... 動的コンストラクション
	//	必要なら設定ファイルによって可変なオブジェクトのコンストラクトを行う。
	//	例えば SCSI ドライブなどが該当する。Create() で作成したインスタンスの
	//	Create() もこのフェーズで呼ばれる。
	//	ここでも gConfig の参照および内部変数の登録は可能、エラー終了する
	//	可能性のあるものも処理できる。
	//	継承クラスの Create() は Device::Create() を呼ぶ必要はない。
	//	putmsg() は使えない。
	//
	// 3. EarlyInit() ... ログ出力の初期化
	//	ここですべての Device に対してログ出力のための変数を初期化する。
	//	ただし putmsg() が使えるのは 4. 以降。
	//	これは override しない。
	//
	// 4. 設定とログの締め切り。
	//	これ以降 gConfig の変更は出来ない。
	//	またログの割り当てを受ける Object 由来のオブジェクトはすべて出揃って
	//	いる必要がある。
	//	4.1 この時点で gConfig の内容は確定したので、--show-config を行う。
	//	4.2 ParseLogopt() ... -L オプションの処理。
	//
	// 5. Create2() ... 動的コンストラクションその2
	//	作成にあたってログ出力をしたいホストドライバのためのフェーズ。
	//	ログは既存のものから従属するしか出来ない。
	//	putmsg() は使える。
	//	EarlyInit() は Create2() のループ後に改めて呼ばれる。
	//
	// 6. ParseMonitors() ... -M オプションの処理
	//	(GUI 版のみ) この時点で Monitor はすべて登録されている必要がある。
	//
	// 7. Init() ... 初期化
	//	この時点で Object 由来のオブジェクトはすべて出揃っているため、他の
	//	Object はすべてアクセス可能。
	//	継承クラスは Device::Init() を呼ぶ必要はないが、子クラスが親クラスの
	//	Init() を呼ぶことを要求することはあるかもしれない。
	//	gConfig の設定項目のうち内容によってエラー終了する可能性があるものは
	//	ここまでに処理する。
	//	複数のオブジェクトが同じ設定項目を処理しないようにすること (複数で
	//	別々に読んでその際の範囲チェックに齟齬が発生するとかを避けるため)。
	//	Object 同士は完全に相互アクセス可能だが、Init() 自身の依存関係
	//	(A::Init() で設定した値を B::Init() が参照する必要があるケース) に
	//	ついては vm.cpp (などコンテナデバイス) 内のコンストラクタの順序で
	//	手動調整すること (循環参照不可)。
	//
	// 8. StartThread() ... スレッド起動
	//
	// 9. ResetHard(true) ... 電源オン

	// ログの初期化。
	void EarlyInit();

	// 動的コンストラクション。
	// 成功すれば true を返す。失敗なら warn() 系、あるいは gConfig->Err()
	// 系でエラーメッセージを表示して false を返すこと。
	virtual bool Create();

	// 動的コンストラクションその2。
	// 成功すれば true を返す。失敗なら warn() 系、あるいは gConfig->Err()
	// 系でエラーメッセージを表示して false を返すこと。
	// putmsg() は使える。
	virtual bool Create2();

	// 初期化。
	// 成功すれば true を返す。失敗なら warn() 系、あるいは gConfig->Err()
	// 系でエラーメッセージを表示して false を返すこと。
	virtual bool Init();

	// 電源オンもしくはリセット。
	// true なら電源オン、false ならリセット。
	// このデバイスがどのタイミングでリセットされるかは VM による。
	// X68030 なら vm_x68k.cpp 内のコメント参照。
	// LUNA は詳細不明。
	virtual void ResetHard(bool poweron);

	// 電源オフ
	virtual void PowerOff();

	// ログ出力
	void putlogn(const char *fmt, ...) const override __printflike(2, 3);

 protected:
	// ログに時刻と PPC を出すために必要
	MainMPUDevice *mpu {};
	Scheduler *scheduler {};
};

class IODevice : public Device
{
	using inherited = Device;
 protected:
	explicit IODevice(uint objid_);
 public:
	~IODevice() override;

 public:
	// メイン CPU からのデバイスの読み込み。
	// busaddr.Addr にアドレス、busaddr.Size に要求バイト数がセットされている。
	// busdata.Size にはポートサイズ (応答バイト数) を返す。
	// 戻り値 busdata.Data は下詰めし、不要な上位バイトはクリアして返すこと。
	virtual busdata Read(busaddr addr);

	// メイン CPU からのデバイスへの書き込み。
	// busaddr.Addr にアドレス、busaddr.Size に要求バイト数がセットされている。
	// data は Size バイト分が下詰めされており、上位の不要バイトはクリア済み。
	// 戻り値の busdata.Size にはポートサイズを返すこと。
	virtual busdata Write(busaddr addr, uint32 data);

	// メイン CPU からのバーストアクセス。
	// addr (16バイト境界) からの 16 バイトを転送してウェイトと OK を返す。
	// dst/src の uint32 はホストエンディアン。
	// バースト転送をサポートしてなければ BusData::BusErr を返す。
	virtual busdata ReadBurst16(busaddr addr, uint32 *dst);
	virtual busdata WriteBurst16(busaddr addr, const uint32 *src);

	// XP からのデバイスの読み込み。
	// 戻り値は busdata.Data の1バイトと必要なら Wait。他は使用しない。
	virtual busdata Read1(uint32 addr);

	// XP からのデバイスへの書き込み。
	// data は1バイト。
	// 戻り値は busdata.Wait のみ。他は使用しない。
	virtual busdata Write1(uint32 addr, uint32 data);

	// Peek1() はデバッガアクセスで読み込んだ値を (uint32) で返す。
	// バイトアクセスした時に読める値ではなく、現在このアドレスに見えている
	// であろう値。バスエラーなら BusData::BusErr を返す。
	virtual busdata Peek1(uint32 addr);

	// Poke1() はデバッガからこのアドレス(メモリ)へ書き込む。
	// メモリでない領域 (レジスタなど) は書き込み不可。
	// data が (int32 で) 非負なら data の下位8ビットを書き込む。
	// 書き込めれば true、書き込めなければ false を返す。
	// data が (int32 で) 負なら addr への書き込み可否の問い合わせで、
	// 書き込み可能なら true、書き込み不可能なら false を返す。
	virtual bool Poke1(uint32 addr, uint32 data);
};

unix.superglobalmegacorp.com

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