File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / mpu64180.h
Revision 1.1.1.7 (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) 2022 nono project
// Licensed under nono-license.txt
//

//
// MPU (HD647180)
//

#pragma once

#include "mpu.h"
#include "branchhistory.h"
#include "hd64180.h"
#include "message.h"
#include <array>

class HD647180ASCIDevice;
class PIO0Device;
class SSGDevice;
class XPbusDevice;

class MPU64180Device : public MPUDevice, private HD64180
{
	using inherited = MPUDevice;

	// タイマー1個分
	struct XPTimer {
		uint16 count;		// 現在のカウント
		uint16 reload;		// リロードカウント
		uint16 tmpcount;	// 読み出し時用の内部バッファ
		bool running;		// カウントダウン中なら true
		bool intr_enable;	// TIEn ビットの状態 (IEF1 の状態は含まない)

		// 割り込みフラグ TIFn はカウントが 0 になると立ち、
		// その後 TCR と TDR をそれぞれ読むことで (AND 条件)、リセットできる。
		// そのため、tif は 2ビットで管理し、
		// カウントが 0 になれば $3 をセット、
		// TCR の読み出しで bit0 をクリア、
		// TDR の読み出しで bit1 をクリア、
		// (tif != 0) なら割り込み状態、とする。
		uint32 tif;
	};

 public:
	MPU64180Device();
	~MPU64180Device() override;

	void putlogn(const char *fmt, ...) const override;
	bool Create() override;
	bool Init() override;
	void ResetHard(bool poweron) override;

	// 現在実行中の命令先頭の PC を取得
	uint32 GetPPC() const override { return ppc; }

	// CPU の動作モードを返す。
	OpMode GetOpMode() const { return opmode; }

	// RESET 信号をアサート(true)/ネゲート(false)する。
	void ChangeRESET(bool);
	void AssertRESET();
	void NegateRESET();

	// プロセッサをリセット
	void Reset();

	// INT0 信号線をアサートする (PIO1 から呼ばれる)。
	// (ネゲートはローカルで行う)
	void AssertINT0();

	// ASCI0/1 の割り込みをアサート/ネゲートする (ASCI から呼ばれる)。
	void ChangeASCIInt(uint n, bool req);

	// ブランチ履歴 (例外履歴を含む)
	BranchHistory_hd64180 brhist { OBJ_XP_BRHIST };
	// 例外履歴のみ
	BranchHistory_hd64180 exhist { OBJ_XP_EXHIST };

	// I, R レジスタ
	uint8 GetI() const		{ return reg_i; }
	uint8 GetR() const		{ return reg_r & 0x7f; }

	bool GetIEF1() const	{ return ief1; }
	bool GetIEF2() const	{ return ief2; }

	// アドレス変換 (デバッガ用)
	uint32 TranslatePeek(uint32) const;

	// MSXDOS エミュレーションのコールバックを指定する。
	void SetSYSCALLCallback(void (*callback)(void *), void *arg);

	hd64180reg reg {};

	// 割り込み名
	static std::vector<const char *> InterruptName;

 private:
	void EnterNormal();
	void EnterSleep();
	void EnterWakeup();
	void ExecTrace(Event *);
	void ExecNormal(Event *);
	void ExecSleep(Event *);
	void ExecWakeup(Event *);
	void SetExec(EventCallback_t);

	// トレース設定。デバッガから呼び出される。
	void SetTrace(bool enable);
	void TraceMessage(MessageID, uint32);

	uint32 GetIHL() const;
	void SetIHL(uint32);
	uint32 LeaIHL();
	uint32 GetWW(uint) const;
	void SetWW(uint, uint32);

	// CPU からの論理メモリアクセス
	uint32 Fetch1();
	uint32 Fetch2();
	uint32 Read1(uint32 addr);
	uint32 Write1(uint32 addr, uint32 data);
	uint32 Read2(uint32 addr);
	void Write2(uint32 addr, uint32 data);

	void Jump(uint16);
	void op_illegal(int pos);

	void ops_ret();
	void ops_ddfd(ixiy_t);
	void ops_ldi(int);
	void ops_cpi(int);
	void ops_ini(int);
	void ops_outi(int);
	void ops_otim(int);
	void ops_otmr_until();

#define OP_PROTO(name)	void __CONCAT(op_,name)()
#include "hd64180ops.h"
#undef OP_PROTO

	uint32 Translate(uint32) const;

	void AssertIntmap(int source);
	void NegateIntmap(int source);
	void NegateINT0();
	void DoInterrupt();
	void ExceptionDirect(int source, uint32 addr);
	void ExceptionVector(int source);

	uint32 Peek1(uint32 addr) const;
	uint32 Peek2(uint32 addr) const;

	void Push2(uint32 data);
	uint32 Pop2();

	uint32 ReadIO(uint32 addr);
	uint32 ReadInternalIO(uint32 offset);
	uint32 ReadExternalIO(uint32 addr);
	uint32 WriteIO(uint32 addr, uint32 data);
	uint32 WriteInternalIO(uint32 offset, uint32 data);
	uint32 WriteExternalIO(uint32 addr, uint32 data);
	uint32 PeekIO(uint32 addr);
	uint32 PeekInternalIO(uint32 offset);
	uint32 PeekExternalIO(uint32 addr);
	static std::string IOName(uint32 addr);

	uint32 ReadTMDRL(int ch);
	uint32 ReadTMDRH(int ch);
	uint32 ReadTCR();

	uint32 WriteTMDRL(int ch, uint32 data);
	uint32 WriteTMDRH(int ch, uint32 data);
	uint32 WriteRLDRL(int ch, uint32 data);
	uint32 WriteRLDRH(int ch, uint32 data);
	uint32 WriteTCR(uint32 data);
	uint32 WriteDCNTL(uint32 data);
	uint32 WriteIL(uint32 data);
	uint32 WriteITC(uint32 data);
	uint32 WriteRCR(uint32 data);
	uint32 WriteCBR(uint32 data);
	uint32 WriteBBR(uint32 data);
	uint32 WriteCBAR(uint32 data);
	uint32 WriteICR(uint32 data);
	uint32 WriteRMCR(uint32 data);

	uint32 PeekTMDRL(int ch) const;
	uint32 PeekTMDRH(int ch) const;
	uint32 PeekRLDRL(int ch) const;
	uint32 PeekRLDRH(int ch) const;
	uint32 PeekTCR() const;
	uint32 PeekFRC() const;
	uint32 PeekDCNTL() const;
	uint32 PeekIL() const;
	uint32 PeekITC() const;
	uint32 PeekRCR() const;
	uint32 PeekCBR() const;
	uint32 PeekBBR() const;
	uint32 PeekCBAR() const;
	uint32 PeekICR() const;
	uint32 PeekRMCR() const;

	void CYCLE(int n)	{ used_cycle += n; }
	void CYCLE_IX(int, int);

	// タイマー
	void EnableTimer();
	void ChangeTimerInterrupt();
	void TimerCallback(Event *);
	void MakeActiveTimer();

	uint16 ppc {};

	uint8 reg_i {};		// I レジスタ
	uint8 reg_r {};		// R レジスタ

	uint ixiy {};		// 0=HL, 1=IX, 2=IY
	// (IX+d)/(IY+d) の d。
	// 読み込んでない時は (uint32)-1 にしておく。
	// DD と DD CB で読む位置が違うので。
	uint32 ixd {};

	bool ief1 {};		// IEF1: Interrupt Enable Flag1
	bool ief2 {};		// IEF2: Interrupt Enable Flag2
	uint int0mode {};	// INT0 mode
	bool intcheck {};	// この命令後の境界で割り込みチェックするなら true

	// 割り込み信号線の状態
	//
	//     bit 31 30 29 27 26 25 24 23 22 21 20 19 18 17 16 15 ...  0
	//        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--     --+
	// intmap | 0| 0|I0|I1|I2|IC|OC|TV|T0|T1|D0|D1|CS|A0|A1|         |
	//        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- ... --+
	// 優先順位 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
	//
	// intmap (32bit) は最上位から割り込み優先順に 1ビットずつ割り当てる
	// (ただし TRAP と NMI はここでは使わないので %0 のまま)。
	// 割り込みが発生していなければ intmap == 0。
	// 割り込みが発生すれば該当するビットを立てる。割り込みを処理する際は
	// builtin_clz() で上から判定していく。
	uint32 intmap {};

	// 割り込み回数 (アサートのエッジでカウントアップする)
	// [0]  が優先順位  0 (TRAP) の割り込み回数。
	// [14] が優先順位 14 (ASCI1) の割り込み回数。
	uint64 int_counter[15] {};

	// 動作モード。
	// mode == Reset ならリセット信号アサート中。
	OpMode opmode {};

	// 現在の命令列
	std::vector<uint8> ops {};
	// 直近の命令語
	uint8 op {};

	uint64 clock_tsec {};	// MPU クロック [tsec]

	// 電源オンからの累積消費サイクル
	uint64 used_cycle {};

	// タイマーと Free Running Counter
	uint64 timer_epoch {};
	std::array<XPTimer, 2> timer {};
	std::vector<XPTimer *> active_timer {};
	uint8 timer_toc {};		// Timer Output Control

	// DCNTL
	uint32 memwait {};		// メモリウェイト
	uint32 iowait {};		// I/O ウェイト
	uint32 dcntl {};		// DCNTL の残り部分 (未実装)

	// IL: 割り込みベクタの下位バイト(のうち上位3ビット)。
	// 書き込み時にマスクする。
	uint32 intvec_low {};
	// ITC: 割り込み制御
	bool itc_trap {};
	bool itc_ufo {};
	bool itc_ite0 {};		// INT Enable 0
	bool itc_ite1 {};		// INT Enable 1
	bool itc_ite2 {};		// INT Enable 2

	// RCR
	uint32 rcr {};

	// MMU
	uint32 commbase {};		// Common Base Address
	uint32 bankbase {};		// Bank Base Address
	uint32 commarea {};		// Common Area の下限アドレス
	uint32 bankarea {};		// Bank Area の下限アドレス

	// ICR
	uint32 io_address {};	// I/O アドレスの開始番地

	// SYSCALL 用のコールバック
	void (*syscall_callback)(void *) = NULL;
	void *syscall_arg {};

	std::unique_ptr<HD647180ASCIDevice> asci /*{}*/;

	PIO0Device *pio0 {};
	SSGDevice *ssg {};
	XPbusDevice *xpbus {};

	// モニター
	DECLARE_MONITOR_SCREEN(MonitorScreenReg);
	DECLARE_MONITOR_SCREEN(MonitorScreenIO);
	DECLARE_MONITOR_SCREEN(MonitorScreenIntr);
	Monitor *reg_monitor {};
	Monitor *io_monitor {};
	Monitor *intr_monitor {};

	// 実行コールバック
	EventCallback_t exec_func {};

	// イベント
	Event *timer_event {};

	// 名前
	static const char * const opmode_names[];
	static std::vector<const char *> ionames;
};

inline MPU64180Device *GetMPU64180Device() {
	return Object::GetObject<MPU64180Device>(OBJ_MPUXP);
}

unix.superglobalmegacorp.com

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