File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / cmmu.cpp
Revision 1.1.1.10 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:38 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, v024, v023, v022, HEAD
nono 1.2.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// M88200 CMMU の I/O デバイス部分
//

// CMMU が確定しない場合はこのデバイスのログを使う。
// CMMU が確定したらそっちのデバイスログから出力する。

#include "cmmu.h"
#include "m88200.h"
#include "mainapp.h"

// コンストラクタ
CMMUDevice::CMMUDevice()
	: inherited(OBJ_CMMUIO)
{
}

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

// 初期化
bool
CMMUDevice::Init()
{
	// CMMU をポイントしておく
	for (int i = 0; i < cmmus.size(); i++) {
		cmmus[i] = gMainApp.FindObject<m88200>(OBJ_M88200(i));
	}

	return true;
}

// アドレスデコーダ
/*static*/ inline uint32
CMMUDevice::Decoder(uint32 addr)
{
	uint32 offset = addr & 0xfff;

	// BWP* の A5 はデコードされてない
	if (0x420 <= offset && offset < 0x440) {
		offset &= ~0x20;
	}
	// CDP*,CTP* の A4,A5 はデコードされていない
	if (0x800 <= offset && offset < 0x880) {
		offset &= ~0x30;
	}

	return offset;
}

busdata
CMMUDevice::Read(busaddr addr)
{
	busdata data;

	uint32 paddr = addr.Addr();
	uint32 id = (paddr >> 12) & 0xff;
	m88200 *cmmu = GetCMMU(id);
	if (cmmu == NULL) {
		putlog(3, "Read not-equipped CMMU[%u] $%08x", id, paddr);
		return 0xffffffff;
	}

	uint32 offset = Decoder(paddr);
	switch (offset) {
	 case IDR:
		data = cmmu->GetIDR();
		cmmu->putlogf(2, lstr("IDR  -> $%08x", data.Data()));
		break;

	 case SCR:
		data = cmmu->GetSCR();
		cmmu->putlogf(2, lstr("SCR  -> $%08x", data.Data()));
		break;

	 case SSR:
		data = cmmu->GetSSR();
		cmmu->putlogf(2, lstr("SSR  -> $%08x", data.Data()));
		break;

	 case SAR:
		data = cmmu->GetSAR();
		cmmu->putlogf(2, lstr("SAR  -> $%08x", data.Data()));
		break;

	 case SCTR:
		data = cmmu->GetSCTR();
		cmmu->putlogf(2, lstr("SCTR -> $%08x", data.Data()));
		break;

	 case PFSR:
		data = cmmu->GetPFSR();
		cmmu->putlogf(2, lstr("PFSR -> $%08x", data.Data()));
		break;

	 case PFAR:
		data = cmmu->GetPFAR();
		cmmu->putlogf(2, lstr("PFAR -> $%08x", data.Data()));
		break;

	 case SAPR:
		data = cmmu->GetSAPR();
		cmmu->putlogf(2, lstr("SAPR -> $%08x", data.Data()));
		break;

	 case UAPR:
		data = cmmu->GetUAPR();
		cmmu->putlogf(2, lstr("UAPR -> $%08x", data.Data()));
		break;

	 case BWP0 ... BWP7:
		// BWP は書き込み専用 (何が読めるだろうか)
		data = 0xffffffff;
		break;

	 case CSSP:
		data = cmmu->GetCSSP();
		cmmu->putlogf(2, lstr("CSSP -> $%08x", data.Data()));
		break;

	 case CDP0 ... CDP3:
	 case CTP0 ... CTP3:
	 default:
		putlog(0, "Read $%08x (NOT IMPLEMENTED)", paddr);
		data = 0xffffffff;
	}

	// XXX wait?
	data |= BusData::Size4;
	return data;
}

busdata
CMMUDevice::Write(busaddr addr, uint32 data)
{
	uint32 paddr = addr.Addr();

	uint32 id = (paddr >> 12) & 0xff;
	m88200 *cmmu = GetCMMU(id);
	if (cmmu == NULL) {
		putlog(3, "Write not-equipped CMMU[%u] $%08x <- $%08x",
			id, paddr, data);
		return 0;
	}

	// 普通はロングワードアクセスしかしないはず。
	// m88k 専用なのでミスアラインアクセスは起きない。
	// 88200 p5-27
	uint32 size = addr.GetSize();
	if (size == 4) {
		// nop
	} else {
		if (size == 1) {
			data |= data << 8;
		}
		data |= data << 16;
	}

	uint32 offset = Decoder(paddr);
	uint n;
	switch (offset) {
	 case IDR:
	 {
		uint32 newid = data >> 24;
		if (id != newid) {
			// 後から ID を変更するのはサポートしない。というか実際無理では。
			cmmu->putlogf(0, lstr(
				"IDR  <- $%08x (change ID $%02x to $%02x; NOT SUPPORTED)",
				data, id, newid));
		} else {
			cmmu->putlogf(2, lstr("IDR  <- $%08x", data));
		}
		break;
	 }

	 case SCR:
		cmmu->SetSCR(data);
		break;

	 case SSR:
		cmmu->putlogf(1, lstr("SSR  <- $%08x", data));
		cmmu->SetSSR(data);
		break;

	 case SAR:
		cmmu->putlogf(2, lstr("SAR  <- $%08x", data));
		cmmu->SetSAR(data);
		break;

	 case SCTR:
		cmmu->SetSCTR(data);
		break;

	 case PFSR:
		cmmu->SetPFSR(data);
		break;

	 case PFAR:
		cmmu->SetPFAR(data);
		break;

	 case SAPR:
		cmmu->SetSAPR(data);
		break;

	 case UAPR:
		cmmu->SetUAPR(data);
		break;

	 case BWP0 ... BWP7:
		n = (offset - BWP0) / 4;
		assert(n < 8);
		cmmu->SetBWP(n, data);
		break;

	 case CSSP:
		cmmu->SetCSSP(data);
		break;

	 case CDP0 ... CDP3:
	 case CTP0 ... CTP3:
	 default:
		putlog(0, "Write $%08x <- $%08x (NOT IMPLEMENTED)", paddr, data);
		VMPANIC("not impl");
		break;
	}

	// wait?
	busdata r = BusData::Size4;
	return r;
}

// Peek1() の下請け。ロングワードで処理して後でバイトに分割するほうが楽。
uint32
CMMUDevice::Peek4(uint32 addr) const
{
	uint32 id = (addr >> 12) & 0xff;

	m88200 *cmmu = GetCMMU(id);
	if (cmmu == NULL) {
		return 0xffffffff;
	}

	uint32 offset = Decoder(addr);
	switch (offset) {
	 case IDR:
		return cmmu->GetIDR();

	 case SCR:
		return cmmu->GetSCR();

	 case SSR:
		return cmmu->GetSSR();

	 case SAR:
		return cmmu->GetSAR();

	 case SCTR:
		return cmmu->GetSCTR();

	 case PFSR:
		return cmmu->GetPFSR();

	 case PFAR:
		return cmmu->GetPFAR();

	 case SAPR:
		return cmmu->GetSAPR();

	 case UAPR:
		return cmmu->GetUAPR();

	 case BWP0 ... BWP7:
		return 0xffffffff;

	 case CDP0 ... CDP3:
	 case CTP0 ... CTP3:
		break;

	 case CSSP:
		return cmmu->GetCSSP();

	 default:
		break;
	}
	return 0xffffffff;
}

busdata
CMMUDevice::Peek1(uint32 addr)
{
	uint32 data = Peek4(addr & ~3U);
	switch (addr & 3) {
	 case 0:
		return data >> 24;
	 case 1:
		return (data >> 16) & 0xff;
	 case 2:
		return (data >>  8) & 0xff;
	 case 3:
		return data & 0xff;
	 default:
		return 0xff;
	}
}

unix.superglobalmegacorp.com

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