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

//
// NEWS の ROM エミュレーション (-X のみ対応)
//

// IODevice
//  |
//  +- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
//  |   +- PROMDevice    (LUNA* の PROM)
//  |   +- IPLROM1Device (X680x0 の IPLROM 後半)
//  |   +- IPLROM2Device (X680x0 の IPLROM 前半)
//  |   +- CGROMDevice   (X680x0 の CGROM)
//  |   |
//  |   +- ROMEmuDevice
//  |       +- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分)
//  |       |   +- Luna1PROMEmuDevice   (LUNA-I の PROM エミュレーション)
//  |       |   +- Luna88kPROMEmuDevice (LUNA-88K の PROM エミュレーション)
//  |       |
//  |       | +------------------+
//  |       +-| NewsROMEmuDevice | (NEWS の ROM エミュレーション)
//  |       | +------------------+
//  |       |
//  |       +- ROM30EmuDevice      (X68030 の ROM30 エミュレーション)
//  |       +- Virt68kROMEmuDevice (virt-m68k の IPLROM 相当の何か)
//  |
//  +- PROM0Device   (LUNA* のブートページ切り替え用プロキシ)
//  +- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ)

#include "romemu_news.h"
#include "mainapp.h"
#include "mainbus.h"
#include "mainram.h"
#include "memorystream.h"
#include "mpu680x0.h"
#include "newsfb.h"
#include "power.h"

// コンストラクタ
NewsROMEmuDevice::NewsROMEmuDevice()
	: inherited(OBJ_PROM)
{
}

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

// 初期化
bool
NewsROMEmuDevice::Init()
{
	// ROM 領域を用意。サイズは適当。
	if (AllocROM(2048, 0) == false) {
		return false;
	}

	mainram = GetMainRAMDevice();

	MemoryStreamBE roms(imagebuf.get());
	roms.Write4(0x00000400);	// +00: リセットベクタ SP
	roms.Write4(0xf8000400);	// +04: リセットベクタ PC
	// ベクタ
	for (int i = 2; i < 256; i++) {
		roms.Write4(0);
	}
	roms.SetOffset(32 * 4);
	roms.Write4(0xf8000500);	// Trap#0 で ROM のサービスコール
	// Trap#15 は ROM モニタらしい。今の所停止するだけ。
	// とりあえず Trap#1..#14 も全部ここへ向けておく。
	for (int i = 1; i < 16; i++) {
		roms.Write4(0xf8000600);
	}

	// リセット時に実行する命令
	roms.SetOffset(0x400);
	roms.Write2(0x2039);		//	move.l	(ROMIO_INIT),d0
	roms.Write4(ROMIO_INIT);
	roms.Write2(0x2040);		//	move.l	d0,a0	; ジャンプ先を a0 にセット
	roms.Write2(0x4ed0);		//	jmp		(a0)	; ジャンプ

	// ROM サービスコール
	roms.SetOffset(0x500);
	roms.Write2(0x0c80);		//	cmpi.l	#3,d0
	roms.Write4(0x00000003);	//
	roms.Write2(0x6708);		//	beq		@f
	roms.Write2(0x2039);		//	move.l	(ROMIO_SYS),d0
	roms.Write4(ROMIO_SYS);		//
	roms.Write2(0x4e73);		//	rte
								//@@:				; Read は対応してないので
	roms.Write4(0x4e722500);	//	stop	#0x2500	; STOP しつつ
	roms.Write2(0x60fa);		//	bra		@b		; 無限ループ。
	roms.Write2(0x4e73);		//	rte

	// ROM モニタの TRAP#n。はないのでここに来たらとりあえず停止する?
	roms.SetOffset(0x600);
								//@@:
	roms.Write4(0x4e722700);	//	stop	#0x2700	; STOP しつつ
	roms.Write2(0x60fa);		//	bra		@b		; 無限ループ。

	return true;
}

void
NewsROMEmuDevice::ResetHard(bool poweron)
{
	// 起動時に RAM にリセットベクタを書き込んでおく。(手抜き)
	mainram->WriteMem(0, &imagebuf[0], 8);
}

// ROMIO から読み出す。
// ROMIO が応答すべきでなければ (uint64)-1 を返す。
uint64
NewsROMEmuDevice::ReadROMIO(busaddr addr)
{
	if (addr.GetSize() == 4) {
		switch (addr.Addr()) {
		 case ROMIO_INIT:
			return ROM_Init();

		 case ROMIO_SYS:
			return ROM_Sys();

		 default:
			break;
		}
	}

	return (uint64)-1;
}

uint32
NewsROMEmuDevice::ROM_Init()
{
	// -X file で指定されたホストファイルを読み込んでエントリポイント
	// アドレスをこの Read アクセスの読み出し値として返す。

	LoadInfo info(gMainApp.exec_file);
	if (BootLoader::LoadExec(mainram, &info) == false) {
		// エラーメッセージは表示済み。
		auto power = GetPowerDevice();
		power->PushPowerButton();
		return -1;
	}
	putmsg(1, "Host program loaded.  Entry point = $%08x", info.entry);

	// ROMCONS のために VBR を設定
	m68kreg& reg = GetMPU680x0Device(mpu)->reg;
	reg.vbr = 0xf8000000;

	// %d2 には MARK_END (たぶん最後の番地)
	// %d4 にメモリサイズ。
	// %d5 には読み込んだファイル名の先頭番地?
	// %d6 に bootdev、NetBSD/news68k の場合は
	// bootdev = $MCxUHPTT
	//            || |||++ Type? (SD=0)
	//            || ||+-- Partition?
	//            || |+--- Host: 機種? (NEWS1700 は 0)
	//            || +---- Unit?
	//            |+------ Controller?
	//            +------- magic ($5)
	// 下位28ビット(7桁) は ROM から渡されるようだ。
	// %d7 は boothowto。
	reg.D[2] = info.sym;
	reg.D[4] = (uint32)mainram->GetSize();
	reg.D[6] = 0x50000000;
	reg.D[7] = 0;

	return info.entry;
}

uint32
NewsROMEmuDevice::ROM_Sys()
{
	auto mainbus = GetMainbusDevice();
	auto mpu680x0 = GetMPU680x0Device(mpu);
	m68kreg& reg = mpu680x0->reg;
	auto newsfb = GetNewsfbDevice();

	if (reg.D[0] == SYS_write) {
		uint32 a6 = reg.A[6];
		uint32 fd  = mainbus->HVRead4(a6 + 8);
		uint32 buf = mainbus->HVRead4(a6 + 12);
		uint32 len = mainbus->HVRead4(a6 + 16);

		for (int i = 0; i < len; i++) {
			busdata bd = mainbus->HVRead1(buf++);
			if (bd.IsBusErr()) {
				// XXX ?
				return 0;
			}
			uint8 ch = bd.Data();
			if (ch == '\r') {
				continue;
			}
			newsfb->Putc(ch);
		}
		(void)fd;
		return len;
	}

	VMPANIC("Unknown service call $%02x", reg.D[0]);
	return 0;
}

unix.superglobalmegacorp.com

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