File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / human_mi.h
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:17 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?
//

#pragma once

#include "device.h"
#include "mpu.h"
#include <array>

class MPU680x0Device;
class MPU88xx0Device;
class Scheduler;

// 謎の機種非依存 Human68k(?) システムコール
class HumanMI : public Object
{
	using inherited = Object;
 protected:
	// DOS コールの引数について
	//
	// m68k では引数はスタックに積まれる (本来の仕様のまま)。
	// m88k では、m88k のサブルーチン呼び出し規約を真似てレジスタに置くことに
	// する。ただしその際のレジスタは本来 r2..r9 固定だが、ここでは rS1 で
	// その先頭レジスタを指定できることにする。
	// どちらも Pop16()、Pop32() を使って引数を前から順番に取り出すことで
	// その差を吸収する。
	//
	// 例えば DOS _OPEN は第1引数が 32bit ポインタ、第1引数が 16bit の mode
	// なので、m68k では以下のようにコールする。
	//
	//		move.w	#MODE,-(sp)
	//		pea		nameptr
	//		DOS		_OPEN
	//		addq.l	#6,sp
	//
	// m88k からこの DOS コールを呼ぶ際は、例えば引数を r4 以降に置き、
	// 戻り値を r2 で受け取りたい場合は以下のようになる。
	//
	//		or.u	r4, r0, #(nameptr).Hi
	//		or		r4, r4, #(nameptr).Lo
	//		or		r5, r0, #mode
	//		doscall	r2, r4, #_OPEN
	//
	// どちらの場合でも HumanMI は
	//
	//		ptr  = Pop32();
	//		mode = Pop16();
	//
	// として引数を取り出す。

	virtual uint64 Pop16() = 0;
	virtual uint64 Pop32() = 0;

	// レジスタにアクセスする。
	// レジスタ番号 rn は 機種依存。
	virtual uint32 ReadReg(int rn) = 0;
	virtual void WriteReg(int rn, uint32 data) = 0;

	// 結果をセットする。
	// m68k の場合は d0.l に格納される。
	// m88k の場合は rD に格納される。
	virtual void Result(uint32 data) = 0;

 public:
	HumanMI();
	virtual ~HumanMI();

	virtual bool Init() = 0;

	// CPU からのシステムコール呼び出しを受け取る口。
	// コール番号を解釈して引数リストを作る。
	virtual bool SysCallEntry() = 0;

	// バスアクセス
	uint64 Read8(uint32 addr) const { return gMPU->Read8(addr); }
	uint64 Read16(uint32 addr) const { return gMPU->Read16(addr); }
	uint64 Read32(uint32 addr) const { return gMPU->Read32(addr); }
	uint64 Write8(uint32 addr, uint32 data) const {
		return gMPU->Write8(addr, data); }
	uint64 Write16(uint32 addr, uint32 data) const {
		return gMPU->Write16(addr, data); }
	uint64 Write32(uint32 addr, uint32 data) const {
		return gMPU->Write32(addr, data); }


	// システムコール
	// システムコールは HumanMIFunc で、未実装など、エミュレートできないとき
	// false を返す。
	// システムコール自体のゲスト的なエラーは Result() 経由でゲストに
	// 伝えられる。

	using HumanMIFunc = bool (HumanMI::*)(void);
	std::array<HumanMIFunc, 256> scTable {};

	bool DOS_EXIT();
	bool DOS_GETCHAR();
	bool DOS_PUTCHAR();
	bool DOS_COMINP() { return false; }
	bool DOS_COMOUT() { return false; }
	bool DOS_PRNOUT() { return false; }
	bool DOS_INPOUT() { return false; }
	bool DOS_INKEY() { return false; }
	bool DOS_GETC() { return false; }
	bool DOS_PRINT();
	bool DOS_GETS() { return false; }
	bool DOS_KEYSNS() { return false; }
	bool DOS_KFLUSH() { return false; }
	bool DOS_FFLUSH() { return false; }
	bool DOS_CHGDRV() { return false; }
	bool DOS_DRVCTRL() { return false; }

	bool DOS_CONSNS() { return false; }
	bool DOS_PRNSNS() { return false; }
	bool DOS_CINSNS() { return false; }
	bool DOS_COUTSNS() { return false; }
	bool DOS_FATCHK() { return false; }
	bool DOS_HENDSP() { return false; }
	bool DOS_CURDRV() { return false; }
	bool DOS_GETSS() { return false; }
	bool DOS_FGETC() { return false; }
	bool DOS_FGETS() { return false; }
	bool DOS_FPUTC() { return false; }
	bool DOS_FPUTS() { return false; }
	bool DOS_ALLCLOSE() { return false; }

	bool DOS_SUPER() { return false; }
	bool DOS_FNCKEY() { return false; }
	bool DOS_KNJCTRL() { return false; }
	bool DOS_CONCTRL() { return false; }
	bool DOS_KEYCTRL() { return false; }
	bool DOS_INTVCS() { return false; }
	bool DOS_PSPSET() { return false; }
	bool DOS_GETTIM2() { return false; }
	bool DOS_SETTIM2() { return false; }
	bool DOS_NAMESTS() { return false; }
	bool DOS_GETDATE() { return false; }
	bool DOS_SETDATE() { return false; }
	bool DOS_GETTIME() { return false; }
	bool DOS_SETTIME() { return false; }
	bool DOS_VERIFY() { return false; }
	bool DOS_DUP0() { return false; }

	bool DOS_VERNUM() { return false; }
	bool DOS_KEEPPR() { return false; }
	bool DOS_GETDPB() { return false; }
	bool DOS_BREAKCK() { return false; }
	bool DOS_DRVXCHG() { return false; }
	bool DOS_INTVCG() { return false; }
	bool DOS_DSKFRE() { return false; }
	bool DOS_NAMECK() { return false; }
	bool DOS_MKDIR() { return false; }
	bool DOS_RMDIR() { return false; }
	bool DOS_CHDIR() { return false; }
	bool DOS_CREATE() { return false; }
	bool DOS_OPEN() { return false; }
	bool DOS_CLOSE() { return false; }
	bool DOS_READ() { return false; }

	bool DOS_WRITE();
	bool DOS_DELETE() { return false; }
	bool DOS_SEEK() { return false; }
	bool DOS_CHMOD() { return false; }
	bool DOS_IOCTRL() { return false; }
	bool DOS_DUP() { return false; }
	bool DOS_DUP2() { return false; }
	bool DOS_CURDIR() { return false; }
	bool DOS_MALLOC() { return false; }
	bool DOS_MFREE() { return false; }
	bool DOS_SETBLOCK();
	bool DOS_EXEC() { return false; }
	bool DOS_EXIT2();
	bool DOS_WAIT() { return false; }
	bool DOS_FILES() { return false; }
	bool DOS_NFILES() { return false; }

	bool DOS_SETPDB() { return false; }
	bool DOS_GETPDB() { return false; }
	bool DOS_SETENV() { return false; }
	bool DOS_GETENV() { return false; }
	bool DOS_VERIFYG() { return false; }
	bool DOS_COMMON() { return false; }
	bool DOS_RENAME() { return false; }
	bool DOS_FILEDATE() { return false; }
	bool DOS_MALLOC2() { return false; }
	bool DOS_MAKETMP() { return false; }
	bool DOS_NEWFILE() { return false; }
	bool DOS_LOCK() { return false; }
	bool DOS_ASSIGN() { return false; }

	bool DOS_FFLUSH_SET() { return false; }
	bool DOS_OS_PATCH() { return false; }
	bool DOS_GETFCB() { return false; }
	bool DOS_S_MALLOC() { return false; }
	bool DOS_S_MFREE() { return false; }
	bool DOS_S_PROCESS() { return false; }

	bool DOS_EXITVC() { return false; }
	bool DOS_CTRLVC() { return false; }
	bool DOS_ERRJVC() { return false; }
	bool DOS_DISKRED() { return false; }
	bool DOS_DISKWRT() { return false; }
	bool DOS_INDOSFLG() { return false; }
	bool DOS_SUPER_JSR() { return false; }
	bool DOS_BUS_ERR() { return false; }
	bool DOS_OPEN_PR() { return false; }
	bool DOS_KILL_PR() { return false; }
	bool DOS_GET_PR() { return false; }
	bool DOS_SUSPEND_PR() { return false; }
	bool DOS_SLEEP_PR() { return false; }
	bool DOS_SEND_PR() { return false; }
	bool DOS_TIME_PR() { return false; }
	bool DOS_CHANGE_PR() { return false; }

	// エラーコード
	struct Ecode {
		int code;
		std::string msg;
	};

	const Ecode E_OK			{   0, "" };
	const Ecode E_INVALID_SC	{  -1, "Invalid system call" };
	const Ecode E_FILE_NOTFOUND	{  -2, "File not found" };
	const Ecode E_DIR_NOTFOUND	{  -3, "Directory not found" };
	const Ecode E_MANY_OPEN		{  -4, "Too many open" };
	const Ecode E_ACCESS		{  -5, "Access denied" };
	const Ecode E_NO_HANDLE		{  -6, "Handle not open" };
	const Ecode E_BROKEN_MD		{  -7, "Broken memory discriptor" };
	const Ecode E_MEMORY		{  -8, "Not enough memory" };
	const Ecode E_INVALID_MD	{  -9, "Invalid memory discriptor" };
	const Ecode E_INVALID_ENV	{ -10, "Invalid environment" };
	const Ecode E_BAD_EXEC		{ -11, "Bad executable format" };
	const Ecode E_BAD_OPEN		{ -12, "Bad open mode" };
	const Ecode E_INVALID_FILE	{ -13, "Invalid filename" };
	const Ecode E_INVALID_PARAM	{ -14, "Invalid parameter" };
	const Ecode E_INVALID_DRIVE	{ -15, "Invalid drive" };
	const Ecode E_DEL_CURDIR	{ -16, "Can not delete curdir" };
	const Ecode E_INVALID_IOCTL	{ -17, "Invalid ioctrl" };
	const Ecode E_NO_FILE		{ -18, "No more files" };
	const Ecode E_CANT_WRITE	{ -19, "Can not write file" };
	const Ecode E_DIR_ARE_REG	{ -20, "Directory already registered" };
	const Ecode E_CANT_DEL		{ -21, "Can not delete" };
	const Ecode E_CANT_RENAME	{ -22, "Can not rename" };
	const Ecode E_DISK_FULL		{ -23, "Disk full" };
	const Ecode E_DIR_FULL		{ -24, "Directory full" };
	const Ecode E_CANT_SEEK		{ -25, "Can not seek" };
	const Ecode E_ARE_SUPER		{ -26, "Already supervisor" };
	const Ecode E_TH_ARE_EXIST	{ -27, "Thread already exists" };
	const Ecode E_CANT_IPC		{ -28, "Can not write IPC" };
	const Ecode E_MANY_PROC		{ -29, "Too many process" };

	const Ecode E_MANY_LOCK		{ -32, "Too many locks" };
	const Ecode E_HANDLE_LOCKED	{ -33, "Handle locked" };
	const Ecode E_DRIVE_ARE_OP	{ -34, "Drive already open" };
	const Ecode E_MANY_SYMLINK	{ -35, "Too many nest symlink" };

	const Ecode E_FILE_EXIST	{ -80, "File exist" };

 protected:
	bool Dispatch();

	void RequestExit(int code);

	uint scid {};		// 実行中のシステムコール番号

	Scheduler *scheduler {};
};

// m680x0 に合わせたインタフェース。
class HumanMD_m680x0 : public HumanMI
{
 public:
	bool Init() override;
	bool SysCallEntry() override;
 protected:
	uint64 Pop16() override;
	uint64 Pop32() override;
	uint32 ReadReg(int rn) override;
	void WriteReg(int rn, uint32 data) override;
	void Result(uint32 data) override;

 protected:
	// システムコール時点の SP。
	// 引数の取り出しにより変化する。
	uint32 sp {};

	MPU680x0Device *mpu {};
};

// m88xx0 に合わせたインタフェース。
class HumanMD_m88xx0 : public HumanMI
{
 public:
	bool Init() override;
	bool SysCallEntry() override;
 protected:
	uint64 Pop16() override;
	uint64 Pop32() override;
	uint32 ReadReg(int rn) override;
	void WriteReg(int rn, uint32 data) override;
	void Result(uint32 data) override;

 protected:
	// システムコール時点の rS。
	// 引数の取り出しにより変化する。
	uint32 rs {};
	// システムコール時点の rD。
	uint32 rd {};

	MPU88xx0Device *cpu {};
};

unix.superglobalmegacorp.com

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