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

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

//
// CRTC-II (HD6445)
//

#include "crtc2.h"
#include "event.h"
#include "lunafb.h"
#include "renderer.h"
#include "scheduler.h"

// コンストラクタ
CRTC2Device::CRTC2Device()
	: inherited(OBJ_CRTC2)
{
}

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

// 初期化
bool
CRTC2Device::Init()
{
	lunafb = GetLunafbDevice();
	renderer = GetVideoRenderer();

	auto evman = GetEventManager();
	vdisp_event = evman->Regist(this,
		ToEventCallback(&CRTC2Device::VDispCallback),
		"CRTC2 V-DISP");

	return true;
}

// リセット
void
CRTC2Device::ResetHard(bool poweron)
{
	// リセット信号で初期化されるレジスタ (他は維持)
	reg[30] = 0;
	reg[31] = 0;
	reg[32] = 0;

	// 未確認
	ar = 0;

	// XXX 適当
	// すぐに垂直帰線期間を開始する
	vdisp_state = 1;
	vdisp_event->time = 0;
	scheduler->RestartEvent(vdisp_event);
}

busdata
CRTC2Device::ReadPort(uint32 offset)
{
	busdata data;

	switch (offset) {
	 case 0:	// アドレスレジスタ
		// アドレスレジスタは書き込み専用
		// XXX 何が読めるか
		data = 0xff;
		putlog(1, "Read write-only register AR");
		break;

	 case 1:	// データレジスタ
		switch (ar) {
		 case 12 ... 25:	// 読み出し可能
		 case 28 ... 31:
		 case 33:
		 case 36 ... 39:
			data = reg[ar];
			putlog(2, "R%02u -> $%02x", ar, data.Data());
			break;

		 case 40 ... 63:	// 範囲外
			// 未使用レジスタの読み出しは $00 (p.17)
			data = 0;
			putlog(1, "Read unused register R%02u", ar);
			break;

		 default:			// 書き込み専用レジスタ
			// 読み出しは 0 になる (p.112)
			data = 0;
			putlog(1, "Read write-only register R%02u", ar);
			break;
		}
		break;

	 default:
		VMPANIC("corrupted offset=%u", offset);
	}

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

busdata
CRTC2Device::WritePort(uint32 offset, uint32 data)
{
	switch (offset) {
	 case 0:	// アドレスレジスタ
		ar = data & 0x3f;
		putlog(3, "Address Register <- $%02x", ar);
		break;

	 case 1:	// データレジスタ
		switch (ar) {
		 case 16 ... 17:	// 読み出し専用レジスタ
		 case 28:
			putlog(1, "Write read-only register R%02u <- $%02x", ar, data);
			break;

		 case 40 ... 63:	// 範囲外
			putlog(1, "Write unused register R%02u <- $%02x", ar, data);
			break;

		 default:			// 書き込み可能レジスタ
			reg[ar] = data;
			putlog(2, "R%02u <- $%02x", ar, data);
			break;
		}
		break;

	 default:
		VMPANIC("corrupted offset=%u", offset);
		break;
	}

	// XXX wait?
	busdata r = BusData::Size1;
	return r;
}

busdata
CRTC2Device::PeekPort(uint32 offset)
{
	switch (offset) {
	 case 0:	// アドレスレジスタ
		return ar;

	 case 1:	// データレジスタ
		return reg[ar];

	 default:
		return 0xff;
	}
}

bool
CRTC2Device::PokePort(uint32 offset, uint32 data)
{
	return false;
}

// 垂直表示・帰線イベント
// vdisp_state が 1 なら表示期間開始(V-disp)、0 なら帰線期間開始(V-blank)。
void
CRTC2Device::VDispCallback(Event *ev)
{
	// 今はここで1画面まるごと作成
	if (vdisp_state) {
		// 更新の必要があれば Render に作画指示。
		if (lunafb->Snap()) {
			renderer->NotifyRender();
		}
	}

	// 次のタイミングを計算
	// XXX まだ CRTC から計算していない
	if (vdisp_state) {
		// 垂直表示期間
		ev->time = 16234.496_usec;	// 1024*Ht
		vdisp_state = 0;
	} else {
		// 垂直帰線期間
		ev->time = 507.328_usec;	// 32*Ht
		vdisp_state = 1;
	}
	scheduler->StartEvent(ev);
}

unix.superglobalmegacorp.com

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