File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / sysport.cpp
Revision 1.1.1.16 (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
//

//
// システムポート
//

#include "sysport.h"
#include "keyboard.h"
#include "mainbus.h"
#include "mainram.h"
#include "monitor.h"
#include "nmi.h"
#include "power.h"
#include "romimg_x68k.h"
#include "sram.h"
#include "videoctlr.h"
#include <array>

// コンストラクタ
SysportDevice::SysportDevice()
	: inherited(OBJ_SYSPORT)
{
	monitor = gMonitorManager->Regist(ID_MONITOR_SYSPORT, this);
	monitor->SetCallback(&SysportDevice::MonitorScreen);
	monitor->SetSize(56, 8);
}

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

// 初期化
bool
SysportDevice::Init()
{
	cgrom = GetCGROMDevice();
	iplrom1 = GetIPLROM1Device();
	iplrom2 = GetIPLROM2Device();
	keyboard = GetKeyboard();
	mainram = GetMainRAMDevice();
	nmi = GetNMIDevice();
	sram = GetSRAMDevice();
	videoctlr = GetVideoCtlrDevice();

	return true;
}

// リセット
void
SysportDevice::ResetHard(bool poweron)
{
	sysport.ram_wait = 0;
	sysport.rom_wait = 0;
	sysport.key_ctrl = false;
	sysport.pwoff_count = 0;
	GetPowerDevice()->SetSystemPowerOn(true);
}

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

	data = PeekPort(offset);
	putlog(2, "$%06x -> $%02x", GetMainbusDevice()->GetPaddr(), data.Data());

	data |= BusData::Size1;
	return data;
}

busdata
SysportDevice::WritePort(uint32 offset, uint32 data)
{
	switch (offset) {
	 case SYSPORT::CONTRAST:
		putlog(1, "$e8e001 <- $%02x", data);
		videoctlr->SetContrast(data & 15);
		break;

	 case SYSPORT::SCOPE3D:
	 case SYSPORT::IMAGEUNIT:
		break;

	 case SYSPORT::KEY:
		data &= 0x0e;
		// bit1
		if ((data & 0x02)) {
			putlog(0, "$e8e007 <- $%02x (HRL NOT IMPLEMENTED)", data);
		}
		// bit2: NMI リセット
		if ((data & 0x04)) {
			nmi->NegateNMI();
		}
		sysport.key_ctrl = (data & 0x08);
		break;

	 case SYSPORT::WAIT:
	 {
		uint32 rom_wait = data >> 4;
		uint32 ram_wait = data & 0xf;

		// InsideOut p.124
		rom_wait += 2;
		if (ram_wait > 0) {
			ram_wait += 2;
		}

		// ROM/RAM に指示。
		iplrom1->SetWait(rom_wait);
		iplrom2->SetWait(rom_wait);
		cgrom->SetWait(rom_wait);
		mainram->SetWait(ram_wait);

		// ROM/RAM への指定値で保持する。
		sysport.rom_wait = rom_wait;
		sysport.ram_wait = ram_wait;
		break;
	 }

	 case SYSPORT::MPU:
		break;

	 case SYSPORT::SRAMWP:
		if (data == 0x31) {
			sram->WriteEnable(true);
		} else {
			sram->WriteEnable(false);
		}
		break;

	 case SYSPORT::POWEROFF:
	 {
		static const std::array<uint8, 3> sig { 0x00, 0x0f, 0x0f };

		if (sysport.pwoff_count >= sig.size()) {
			// すでにカウントオーバーしている場合何もしない?
			putlog(2, "$e8e00f (POWEROFF) <- %02x", data);
			break;
		}

		if (data == sig[sysport.pwoff_count]) {
			sysport.pwoff_count++;
		} else {
			sysport.pwoff_count = 0;
		}
		putlog(2, "$e8e00f (POWEROFF) <- %02x (count=%u)",
			data, sysport.pwoff_count);
		if (sysport.pwoff_count == sig.size()) {
			// pwoff_count はここではクリアせず、電源オン時に再初期化する。
			putlog(1, "$e8e00f (POWEROFF) Power Off");
			GetPowerDevice()->SetSystemPowerOn(false);
		}
		break;
	 }

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

	busdata r = BusData::Size1;
	return r;
}

busdata
SysportDevice::PeekPort(uint32 offset)
{
	uint32 data;

	switch (offset) {
	 case SYSPORT::CONTRAST:
		data = 0xf0 | videoctlr->GetContrast();
		break;
	 case SYSPORT::SCOPE3D:
		data = 0xff;
		break;
	 case SYSPORT::IMAGEUNIT:
		data = 0xff;
		break;
	 case SYSPORT::KEY:
		// XXX bit3 以外は要実機確認
		data = 0xf7;
		if (keyboard->IsConnected()) {
			data |= 0x08;
		}
		break;
	 case SYSPORT::WAIT:
		data = 0xff;
		break;
	 case SYSPORT::MPU:
		data = 0xdc;
		break;
	 case SYSPORT::SRAMWP:
		data = 0xff;
		break;
	 case SYSPORT::POWEROFF:
		data = 0xff;
		break;
	 default:
		data = 0xff;
		break;
	}
	return data;
}

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

void
SysportDevice::MonitorScreen(Monitor *, TextScreen& screen)
{
	screen.Clear();

	static const char * const name[] = {
		"Contrast",
		"3D Scope",
		"Image Unit",
		"Keyboard Control",
		"ROM/RAM Wait",
		"MPU/FPU Type",
		"SRAM Protect",
		"PowerOff Sequence",
	};

	uint8 val[8];
	const uint32 disphex = 0x39;
	for (int i = 0; i < 8; i++) {
		char hex[4];
		if ((disphex & (1U << i)) != 0) {
			val[i] = PeekPort(i);
			snprintf(hex, sizeof(hex), "%02x", val[i]);
		} else {
			strlcpy(hex, "--", sizeof(hex));
		}

		screen.Print(0, i, "$%06x %s: #%u %-17s:",
			baseaddr + 1 + i * 2, hex, i, name[i]);
	}

	int x = 34;
	// #0 Contrast
	screen.Print(x, 0, "%2u", videoctlr->GetContrast());
	screen.Puts(x, 1, "(Not Supported)");
	screen.Puts(x, 2, "(Not Supported)");
	// #3 Keyboard
	if ((val[SYSPORT::KEY] & 0x08) != 0) {
		screen.Puts(x, 3, "Connected");
	} else {
		screen.Puts(x, 3, "Not connected");
	}
	// #4 ROM/RAM Wait
	screen.Print(x, 4, "ROM %2u clk, RAM %2u clk",
		sysport.rom_wait, sysport.ram_wait);
	// #5 MPU/FPU Type
	screen.Puts(x, 5, "MC68030 / 25MHz");
	// #6 SRAM
	if (sram->IsWriteable()) {
		screen.Puts(x, 6, "Writeable");
	} else {
		screen.Puts(x, 6, "Protected");
	}
	// #7 PowerOff
	screen.Print(x, 7, "%u/3", sysport.pwoff_count);
}

unix.superglobalmegacorp.com

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