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

//
// MPU (共通部分)
//

// Device
//    |  +-----------+
//    +--| MPUDevice | (全 MPU の共通部)
//       +-----------+
//         |
//         |  +---------------+
//         +--| MainMPUDevice | (680x0/88xx0 の共通部)
//         |  +---------------+
//         |    |
//         |    +-- MPU680x0Device
//         |    +-- MPU88xx0Device
//         |
//         +-- MPU64180Device

#include "mpu.h"
#include "config.h"
#include "debugger.h"
#include "event.h"
#include "mainbus.h"
#include "scheduler.h"
#include "syncer.h"

//
// 全 MPU 共通
//

// コンストラクタ
MPUDevice::MPUDevice(uint objid_)
	: inherited(objid_)
{
}

// デストラクタ
MPUDevice::~MPUDevice()
{
}

// 初期化
bool
MPUDevice::Init()
{
	debugger = GetDebugger();

	auto evman = GetEventManager();
	exec_event = evman->Regist(this, NULL, "MPU Execute");

	return true;
}

void
MPUDevice::ResetHard(bool poweron)
{
	inherited::ResetHard(poweron);
	last_vector = -1;
}

void
MPUDevice::PowerOff()
{
	scheduler->StopEvent(exec_event);
}

int32
MPUDevice::GetAndResetLastVector()
{
	auto vector = last_vector;
	last_vector = -1;
	return vector;
}


//
// メイン MPU (680x0/88xx0) 共通部
//

// コンストラクタ
MainMPUDevice::MainMPUDevice()
	: inherited(OBJ_MPU)
{
}

// デストラクタ
MainMPUDevice::~MainMPUDevice()
{
}

// 初期化
bool
MainMPUDevice::Init()
{
	if (inherited::Init() == false) {
		return false;
	}

	mainbus = GetMainbusDevice();
	syncer = GetSyncer();

	// MPU クロック。
	// 設定の "mpu-clock" は MHz 単位だが、変数 clock_khz は kHz 単位。
	int val;
	const ConfigItem& item = gConfig->Find("mpu-clock");
	if (item.TryFixedDecimal(&val, 3) == false) {
		item.Err();
		return false;
	}
	clock_khz = (uint)val;
	// 1MHz 未満はエラー。実際 10MHz 未満でもいい気がするけど
	if (clock_khz < 1000) {
		item.Err();
		return false;
	}
	clock_tsec = 1_msec / clock_khz;
	if (clock_tsec < 1) {
		item.Err("Clock speed too high");
		return false;
	}

	// キャッシュを無効にするテスト用。
	force_disable_dcache = gConfig->Find("mpu-force-disable-dcache").AsBool();
	force_disable_icache = gConfig->Find("mpu-force-disable-icache").AsBool();

	scheduler->ConnectMessage(MessageID::MPU_TRACE_MAIN, this,
		ToMessageCallback(&MainMPUDevice::TraceMessage));

	return true;
}

// MPU トレース状態設定要求メッセージ
void
MainMPUDevice::TraceMessage(MessageID msgid, uint32 arg)
{
	// リセット中は SetTrace しない
	if (resetting) {
		return;
	}

	// デバッガから MPU のトレース状態を設定してくれと言われた
	SetTrace((bool)arg);
}

void
MainMPUDevice::ChangeState(uint32 new_state)
{
	// new_mode (CPU_STATE_*) と
	// NotifyCPUMode() の引数 Syncer::SYNCMODE_CPU_* は
	// 実は同じ値なのでそのまま渡してよいことにする。
	static_assert(CPU_STATE_NORMAL == Syncer::SYNCMODE_CPU_NORMAL, "");
	static_assert(CPU_STATE_STOP   == Syncer::SYNCMODE_CPU_STOP,   "");
	static_assert(CPU_STATE_HALT   == Syncer::SYNCMODE_CPU_HALT,   "");

	if (cpu_state != new_state) {
		cpu_state = new_state;
		// スケジューラに通知
		syncer->NotifyCPUMode(cpu_state);
	}
}

// Round Mode (モニタ表示用)
/*static*/ const char * const
MainMPUDevice::rmstr[4] = {
	"Near",
	"Zero",
	"Minus",
	"Plus",
};

unix.superglobalmegacorp.com

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