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

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

//
// Human68k?
//

#include "human_mi.h"
#include "m88100acc.h"
#include "mpu680x0.h"
#include "mpu88xx0.h"
#include "scheduler.h"

bool human_m680x0_fline_callback(MPU680x0Device *cpu, void *arg);
bool human_m88xx0_fline_callback(MPU88xx0Device *cpu, void *arg);

HumanMI::HumanMI()
	: inherited(OBJ_HUMAN_MI)
{
#define SC_DEF(id, name)	scTable[(id)] = &HumanMI::name

	SC_DEF(0x00, DOS_EXIT);
	SC_DEF(0x01, DOS_GETCHAR);
	SC_DEF(0x02, DOS_PUTCHAR);
	SC_DEF(0x03, DOS_COMINP);
	SC_DEF(0x04, DOS_COMOUT);
	SC_DEF(0x05, DOS_PRNOUT);
	SC_DEF(0x06, DOS_INPOUT);
	SC_DEF(0x07, DOS_INKEY);
	SC_DEF(0x08, DOS_GETC);
	SC_DEF(0x09, DOS_PRINT);
	SC_DEF(0x0a, DOS_GETS);
	SC_DEF(0x0b, DOS_KEYSNS);
	SC_DEF(0x0c, DOS_KFLUSH);
	SC_DEF(0x0d, DOS_FFLUSH);
	SC_DEF(0x0e, DOS_CHGDRV);
	SC_DEF(0x0f, DOS_DRVCTRL);

	SC_DEF(0x10, DOS_CONSNS);
	SC_DEF(0x11, DOS_PRNSNS);
	SC_DEF(0x12, DOS_CINSNS);
	SC_DEF(0x13, DOS_COUTSNS);
	// $14..16 は欠番
	SC_DEF(0x17, DOS_FATCHK);
	SC_DEF(0x18, DOS_HENDSP);
	SC_DEF(0x19, DOS_CURDRV);
	SC_DEF(0x1a, DOS_GETSS);
	SC_DEF(0x1b, DOS_FGETC);
	SC_DEF(0x1c, DOS_FGETS);
	SC_DEF(0x1d, DOS_FPUTC);
	SC_DEF(0x1e, DOS_FPUTS);
	SC_DEF(0x1f, DOS_ALLCLOSE);

	SC_DEF(0x20, DOS_SUPER);
	SC_DEF(0x21, DOS_FNCKEY);
	SC_DEF(0x22, DOS_KNJCTRL);
	SC_DEF(0x23, DOS_CONCTRL);
	SC_DEF(0x24, DOS_KEYCTRL);
	SC_DEF(0x25, DOS_INTVCS);
	SC_DEF(0x26, DOS_PSPSET);
	SC_DEF(0x27, DOS_GETTIM2);
	SC_DEF(0x28, DOS_SETTIM2);
	SC_DEF(0x29, DOS_NAMESTS);
	SC_DEF(0x2a, DOS_GETDATE);
	SC_DEF(0x2b, DOS_SETDATE);
	SC_DEF(0x2c, DOS_GETTIME);
	SC_DEF(0x2d, DOS_SETTIME);
	SC_DEF(0x2e, DOS_VERIFY);
	SC_DEF(0x2f, DOS_DUP0);

	SC_DEF(0x30, DOS_VERNUM);
	SC_DEF(0x31, DOS_KEEPPR);
	SC_DEF(0x32, DOS_GETDPB);
	SC_DEF(0x33, DOS_BREAKCK);
	SC_DEF(0x34, DOS_DRVXCHG);
	SC_DEF(0x35, DOS_INTVCG);
	SC_DEF(0x36, DOS_DSKFRE);
	SC_DEF(0x37, DOS_NAMECK);
	// $38 は欠番
	SC_DEF(0x39, DOS_MKDIR);
	SC_DEF(0x3a, DOS_RMDIR);
	SC_DEF(0x3b, DOS_CHDIR);
	SC_DEF(0x3c, DOS_CREATE);
	SC_DEF(0x3d, DOS_OPEN);
	SC_DEF(0x3e, DOS_CLOSE);
	SC_DEF(0x3f, DOS_READ);

	SC_DEF(0x40, DOS_WRITE);
	SC_DEF(0x41, DOS_DELETE);
	SC_DEF(0x42, DOS_SEEK);
	SC_DEF(0x43, DOS_CHMOD);
	SC_DEF(0x44, DOS_IOCTRL);
	SC_DEF(0x45, DOS_DUP);
	SC_DEF(0x46, DOS_DUP2);
	SC_DEF(0x47, DOS_CURDIR);
	SC_DEF(0x48, DOS_MALLOC);
	SC_DEF(0x49, DOS_MFREE);
	SC_DEF(0x4a, DOS_SETBLOCK);
	SC_DEF(0x4b, DOS_EXEC);
	SC_DEF(0x4c, DOS_EXIT2);
	SC_DEF(0x4d, DOS_WAIT);
	SC_DEF(0x4e, DOS_FILES);
	SC_DEF(0x4f, DOS_NFILES);

	SC_DEF(0x80, DOS_SETPDB);
	SC_DEF(0x81, DOS_GETPDB);
	SC_DEF(0x82, DOS_SETENV);
	SC_DEF(0x83, DOS_GETENV);
	SC_DEF(0x84, DOS_VERIFYG);
	SC_DEF(0x85, DOS_COMMON);
	SC_DEF(0x86, DOS_RENAME);
	SC_DEF(0x87, DOS_FILEDATE);
	SC_DEF(0x88, DOS_MALLOC2);
	SC_DEF(0x8a, DOS_MAKETMP);
	SC_DEF(0x8b, DOS_NEWFILE);
	SC_DEF(0x8c, DOS_LOCK);
	// $8d..8e は欠番
	SC_DEF(0x8f, DOS_ASSIGN);

	SC_DEF(0xaa, DOS_FFLUSH_SET);
	SC_DEF(0xab, DOS_OS_PATCH);
	SC_DEF(0xac, DOS_GETFCB);
	SC_DEF(0xad, DOS_S_MALLOC);
	SC_DEF(0xae, DOS_S_MFREE);
	SC_DEF(0xaf, DOS_S_PROCESS);

	SC_DEF(0xf0, DOS_EXITVC);
	SC_DEF(0xf1, DOS_CTRLVC);
	SC_DEF(0xf2, DOS_ERRJVC);
	SC_DEF(0xf3, DOS_DISKRED);
	SC_DEF(0xf4, DOS_DISKWRT);
	SC_DEF(0xf5, DOS_INDOSFLG);
	SC_DEF(0xf6, DOS_SUPER_JSR);
	SC_DEF(0xf7, DOS_BUS_ERR);
	SC_DEF(0xf8, DOS_OPEN_PR);
	SC_DEF(0xf9, DOS_KILL_PR);
	SC_DEF(0xfa, DOS_GET_PR);
	SC_DEF(0xfb, DOS_SUSPEND_PR);
	SC_DEF(0xfc, DOS_SLEEP_PR);
	SC_DEF(0xfd, DOS_SEND_PR);
	SC_DEF(0xfe, DOS_TIME_PR);
	SC_DEF(0xff, DOS_CHANGE_PR);

	// XXX not tested
	scheduler = GetScheduler();
}

HumanMI::~HumanMI()
{
}

bool
HumanMI::Dispatch()
{
	if (scid < 0 || scid >= scTable.size()) {
		// もともと定義されていないシステムコール。
		return false;
	}
	auto func = scTable[scid];
	if (func == nullptr) {
		// もともと定義されていないシステムコール。
		return false;
	}
	putlog(2, "calling system call $%02X", scid);
	bool r = (this->*func)();

	if (r == false) {
		// 未実装システムコール
		putlog(0, "system call $%02X (NOT IMPLEMENTED)", scid);
		RequestExit(0);
		return false;
	}

	return r;
}

// 内部関数

// 仮想マシンの中から終了させる
void
HumanMI::RequestExit(int code)
{
	scheduler->Terminate();
}

// システムコールの実装

bool
HumanMI::DOS_EXIT()
{
	RequestExit(0);
	return true;
}

bool
HumanMI::DOS_GETCHAR()
{
	int c;
	c = getchar();
	Result((uint32)(c & 0xff));
	return true;
}

bool
HumanMI::DOS_PUTCHAR()
{
	uint16 c = Pop16();
	putchar(c);
	Result(0);
	return true;
}

bool
HumanMI::DOS_PRINT()
{
	uint32 ptr = Pop32();
	putlog(1, "PRINT ptr=%08x", ptr);
	for (;;) {
		uint64 c = Read8(ptr++);
		putlog(1, "c=%d", (int)c);
		if ((int64)c == -1) {
			// バスエラー
			// XXX どうすんの
			// たぶんバスエラーハンドラにジャンプしてバスエラーハンドラが
			// プロセス終了する感じ。
			return false;
		}
		if (c == 0) {
			break;
		}
		printf("%c", (int)c);
	}
	Result(0);
	return true;
}

// FF40
bool
HumanMI::DOS_WRITE()
{
	uint16 fileno = Pop16();
	uint32 dataptr = Pop32();
	uint32 size = Pop32();
	putmsg(1, "WRITE(%d, 0x%08x, 0x%08x)\n", fileno, dataptr, size);
	for (int i = 0; i < size; i++) {
		putchar(Read8(dataptr++));
	}
	Result(size);
	return true;
}

// FF4A
bool
HumanMI::DOS_SETBLOCK()
{
	uint32 memptr = Pop32();
	uint32 len = Pop32();
	putmsg(1, "DOS SETBLOCK(memptr=$%x len=$%x)", memptr, len);
	// なにもせずに、できたという
	Result(len);
	return true;
}

bool
HumanMI::DOS_EXIT2()
{
	uint16 data = Pop16();
	RequestExit(data);
	return true;
}

// HumanMD_m680x0

bool
HumanMD_m680x0::Init()
{
	mpu = GetMPU680x0Device();
	mpu->SetFLineCallback(human_m680x0_fline_callback, this);
	return true;
}

bool
HumanMD_m680x0::SysCallEntry()
{
	uint16 ir = mpu->GetIR();
	if (ir == 0xf600) {
		return false;
	}

	scid = ir & 0xff;
	sp = mpu->reg.A[7];
	putlog(1, "IR=%04X sp=%08x", ir, sp);

	return Dispatch();
}

uint64
HumanMD_m680x0::Pop16()
{
	uint64 rv = Read16(sp);
	sp += 2;
	return rv;
}

uint64
HumanMD_m680x0::Pop32()
{
	uint64 rv = Read32(sp);
	sp += 4;
	return rv;
}

uint32
HumanMD_m680x0::ReadReg(int rn)
{
	assert(0 <= rn && rn < 16);
	return mpu->reg.R[rn];
}

void
HumanMD_m680x0::WriteReg(int rn, uint32 data)
{
	assert(0 <= rn && rn < 16);
	mpu->reg.R[rn] = data;
}

void
HumanMD_m680x0::Result(uint32 data)
{
	WriteReg(0, data);
}

// HumanMD_m88xx0

bool
HumanMD_m88xx0::Init()
{
	auto mpu88xx0 = GetMPU88xx0Device();
	mpu88xx0->SetFLineCallback(human_m88xx0_fline_callback, this);
	return true;
}

bool
HumanMD_m88xx0::SysCallEntry()
{
	scid = cpu->reg.opX & 0xff;
	rd = m88100opf_D(cpu->reg.opX);
	rs = m88100opf_S1(cpu->reg.opX);
	return Dispatch();
}

uint64
HumanMD_m88xx0::Pop16()
{
	uint64 rv = ReadReg(rs) & 0xffff;
	rs++;
	return rv;
}

uint64
HumanMD_m88xx0::Pop32()
{
	uint64 rv = ReadReg(rs);
	rs++;
	return rv;
}

uint32
HumanMD_m88xx0::ReadReg(int rn)
{
	assert(0 <= rn && rn < 32);
	return cpu->reg.r[rn];
}

void
HumanMD_m88xx0::WriteReg(int rn, uint32 data)
{
	assert(0 <= rn && rn < 32);
	if (rn != 0) {
		cpu->reg.r[rn] = data;
	}
}

void
HumanMD_m88xx0::Result(uint32 data)
{
	WriteReg(rd, data);
}

// CPU からのコールバックはグローバル関数宛なので
// クラス呼び出しに変換するだけを担当。
bool
human_m680x0_fline_callback(MPU680x0Device *, void *arg)
{
	auto *human = (HumanMD_m680x0 *)arg;
	return human->SysCallEntry();
}

bool
human_m88xx0_fline_callback(MPU88xx0Device *cpu, void *arg)
{
	auto *human = (HumanMD_m88xx0 *)arg;
	return human->SysCallEntry();
}

unix.superglobalmegacorp.com

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