File:  [Isaki's NoNo m68k/m88k emulator] / nono / util / sramedit / params.cpp
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:27 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, v024, v023, v022, v021, v020, HEAD
nono 1.0.0

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

#include "sramedit.h"
#include <array>

// アクセスヘルパー

uint32 read1(uint32 offset);
uint32 read2(uint32 offset);
uint32 read4(uint32 offset);
void write1(uint32 offset, uint32 val);
void write2(uint32 offset, uint32 val);
void write4(uint32 offset, uint32 val);
uint32 read1(const sraminfo_t&);
uint32 read2(const sraminfo_t&);
uint32 read4(const sraminfo_t&);
void write1(const sraminfo_t&, uint32 val);
void write2(const sraminfo_t&, uint32 val);
void write4(const sraminfo_t&, uint32 val);
int update1(const sraminfo_t&, uint32 val);
int update2(const sraminfo_t&, uint32 val);
int update4(const sraminfo_t&, uint32 val);

uint32
read1(uint32 offset)
{
	return sram[offset];
}

uint32
read2(uint32 offset)
{
	uint32 h = read1(offset) << 8;
	uint32 l = read1(offset + 1);

	return (h | l);
}

uint32
read4(uint32 offset)
{
	uint32 h = read2(offset) << 16;
	uint32 l = read2(offset + 2);

	return (h | l);
}

void
write1(uint32 offset, uint32 val)
{
	sram[offset] = (uint8)val;
}

void
write2(uint32 offset, uint32 val)
{
	write1(offset,     val >> 8);
	write1(offset + 1, val & 0xff);
}

void
write4(uint32 offset, uint32 val)
{
	write2(offset,     val >> 16);
	write2(offset + 2, val & 0xffff);
}

uint32 read1(const sraminfo_t& si) { return read1(si.offset); }
uint32 read2(const sraminfo_t& si) { return read2(si.offset); }
uint32 read4(const sraminfo_t& si) { return read4(si.offset); }
void write1(const sraminfo_t& si, uint32 val) {
	return write1(si.offset, val);
}
void write2(const sraminfo_t& si, uint32 val) {
	return write2(si.offset, val);
}
void write4(const sraminfo_t& si, uint32 val) {
	return write4(si.offset, val);
}

int
update1(const sraminfo_t& si, uint32 val)
{
	if (read1(si) == val) {
		return 0;
	}
	write1(si, val);
	return 1;
}

int
update2(const sraminfo_t& si, uint32 val)
{
	if (read2(si) == val) {
		return 0;
	}
	write2(si, val);
	return 1;
}

int
update4(const sraminfo_t& si, uint32 val)
{
	if (read4(si) == val) {
		return 0;
	}
	write4(si, val);
	return 1;
}

//
// 個別処理
//

//----- ramsize

static std::string
r_ramsize(const sraminfo_t& si)
{
	uint32 v = read4(si);
	std::string res = string_format("$%08x", v);
	if (v % (1024 * 1024) == 0) {
		res += string_format(" (%dMB)", v / 1024 / 1024);
	}
	return res;
}

static int
w_ramsize(const sraminfo_t& si, const std::string& input)
{
	char *end;
	uint32 newval;

	errno = 0;
	newval = strtoul(input.c_str(), &end, 10);
	// 後ろに M が付くのだけ許容する?
	if (end == input.c_str() || errno == ERANGE ||
	    (*end != '\0' && *end != 'm' && *end != 'M')) {
		warnx("%s='%s': bad parameter", si.name, input.c_str());
		return -1;
	}
	newval *= 1024 * 1024;

	return update4(si, newval);
}

static const std::string
h_ramsize(const sraminfo_t& si)
{
	return string_format("%s = { 4..12 }", si.name);
}

//----- romaddr

static std::string
r_romaddr(const sraminfo_t& si)
{
	uint32 v = read4(si);
	std::string res = string_format("$%08x", v);
	if (0xfc0000 <= v && v < 0xfc0020) {
		res += string_format(" (SCSI%d)", (v - 0xfc0000) / 4);
	}
	return res;
}

static int
w_romaddr(const sraminfo_t& si, const std::string& input)
{
	char *end;
	uint32 newval;

	errno = 0;
	if (starts_with_ignorecase(input, "scsi")) {
		const char *start = input.c_str() + 4;
		int id = strtoul(start, &end, 10);
		if (end == start || *end != '\0' || errno == ERANGE) {
			warnx("%s='%s': bad SCSI ID", si.name, input.c_str());
			return -1;
		}
		newval = 0xfc0000 + id * 4;
	} else {
		newval = strtoul(input.c_str(), &end, 16);
		if (end == input.c_str() || *end != '\0' || errno == ERANGE) {
			warnx("%s='%s': bad address", si.name, input.c_str());
		}
		if (newval > 0xffffff) {
			warnx("%s='%s': bad address", si.name, input.c_str());
		}
	}

	return update4(si, newval);
}

static const std::string
h_romaddr(const sraminfo_t& si)
{
	return string_format("%s = { [0x]<hexaddr> | scsi<0..7> }", si.name);
}

//---

static std::string
r_ramaddr(const sraminfo_t& si)
{
	uint32 v = read4(si);
	return string_format("$%08x", v);
}

//----- bootdev

static std::string
r_bootdev(const sraminfo_t& si)
{
	uint32 v = read2(si);
	std::string res = string_format("$%04x ", v);

	if (v == 0x0000) {
		res += "STD (FD->HD->ROM->RAM)";
	} else if ((v & 0xf0ff) == 0x8000) {
		res += string_format("SASI%d", (v >> 8) & 0x0f);
	} else if ((v & 0xf0ff) == 0x9070) {
		res += string_format("FD%d", (v >> 8) & 0x0f);
	} else if (v == 0xa000) {
		res += "ROM";
	} else if (v == 0xb000) {
		res += "RAM";
	} else {
		res += "?";
	}

	return res;
}

static int
w_bootdev(const sraminfo_t& si, const std::string& input)
{
	const char *start;
	char *end;
	int32 newval;

	if (strcasecmp(input.c_str(), "std") == 0) {
		newval = 0x0000;
	} else if (starts_with_ignorecase(input, "sasi")) {
		errno = 0;
		start = input.c_str() + 4;
		int id = strtoul(start, &end, 10);
		if (end == start || *end != '\0' || errno == ERANGE) {
			warnx("%s='%s': bad SASI ID", si.name, input.c_str());
			return -1;
		}
		if (id < 0 || id > 16) {
			warnx("%s='%s': out of range", si.name, input.c_str());
			return -1;
		}
		newval = 0x8000 + (id << 8);
	} else if (starts_with_ignorecase(input, "fd")) {
		errno = 0;
		start = input.c_str() + 2;
		int id = strtoul(start, &end, 10);
		if (end == start || *end != '\0' || errno == ERANGE) {
			warnx("%s='%s': bad unit number", si.name, input.c_str());
			return -1;
		}
		if (id < 0 || id > 4) {
			warnx("%s='%s': out of range", si.name, input.c_str());
			return -1;
		}
		newval = 0x9070 + (id << 8);
	} else if (strcasecmp(input.c_str(), "rom") == 0) {
		newval = 0xa000;
	} else if (strcasecmp(input.c_str(), "ram") == 0) {
		newval = 0xb000;
	} else {
		warnx("%s='%s': bad parameter", si.name, input.c_str());
		return -1;
	}

	return update2(si, newval);
}

static const std::string
h_bootdev(const sraminfo_t& si)
{
	return string_format("%s = { std | sasi<0..15> | fd<0..3> | rom | ram }",
		si.name);
}


static std::string
r_rs232c(const sraminfo_t& si)
{
	uint32 v = read2(si);
	std::string res = string_format("$%04x (", v);

	std::array<std::string, 4> stopbit {
		"2",
		"1",
		"1.5",
		"2",
	};
	res += "stop=";
	res += stopbit[(v >> 14)];
	res += ',';

	std::array<std::string, 4> parity {
		"none",
		"odd",
		"even",
		"none",
	};
	res += "parity=";
	res += parity[(v >> 12) & 3];
	res += ',';

	res += string_format("%dbit,", ((v >> 10) & 3) + 5);

	std::array<int, 9> speed {
		75,
		150,
		300,
		600,
		1200,
		2400,
		4800,
		9600,
		17361,	// X68030 only
	};
	uint32 vs = (v & 0x0f);
	if (vs < speed.size()) {
		res += string_format("%dbps", speed[vs]);
	} else {
		res += "?bps";
	}

	res += ')';
	return res;
}

static std::string
r_led(const sraminfo_t& si)
{
	uint8 v = read1(si);
	std::string res = string_format("$%02x", v);

	std::array<std::string, 8> names {
		"",			// b7
		"Zenkaku",	// b6
		"Hiragana",	// b5
		"INS",		// b4
		"CAPS",		// b3
		"Code",		// b2
		"Roma",		// b1
		"Kana",		// b0
	};
	std::string map;
	uint8 b = 0x40;
	for (int i = 0; b; i++, b >>= 1) {
		if ((v & b) != 0) {
			if (map.empty() == false) {
				map += ',';
			}
			map += names[i];
		}
	}

	if (map.empty() == false) {
		res += ' ';
		res += map;
	}
	return res;
}

static std::string
r_crtmod(const sraminfo_t& si)
{
	uint8 v = read1(si);
	return string_format("$%02x", v);
}

static std::string
r_contrast(const sraminfo_t& si)
{
	uint8 v = read1(si);
	return string_format("$%02x", v);
}

static std::string
r_sram_use(const sraminfo_t& si)
{
	uint8 v = read1(si);
	std::string res;

	if (v == 0) {
		res = "NotUsed";
	} else if (v == 1) {
		res = "SRAMDISK";
	} else if (v == 2) {
		res = "Program";
	} else {
		res = string_format("$%02x ?", v);
	}
	return res;
}

//----- key_delay, key_repeat

static std::string
r_key_repeat(const sraminfo_t& si)
{
	uint8 v = read1(si);
	std::string res = string_format("$%02x ", v);

	if (v < 16) {
		int msec;
		if (si.offset == 0x3a) {
			msec = 200 + 100 * v;
		} else {
			msec = 30 + 5 * v * v;
		}
		res += string_format("(%dmsec)", msec);
	} else {
		res += "(??msec)";
	}
	return res;
}

static int
w_key_repeat(const sraminfo_t& si, const std::string& input)
{
	char *end;
	int newval;

	errno = 0;
	newval = strtoul(input.c_str(), &end, 10);
	if (end == input.c_str() || *end != '\0' || errno == ERANGE) {
		warnx("%s='%s': bad parameter", si.name, input.c_str());
		return 0;
	}

	// 値は10進数、直接指定
	if (newval < 0 || newval > 255) {
		warnx("%s='%d': invalid range", si.name, newval);
		return -1;
	}

	return update1(si, newval);
}

static const std::string
h_key_repeat(const sraminfo_t& si)
{
	return string_format("%s = { 0..15 }", si.name);
}

//-----

static std::string
r_boottime(const sraminfo_t& si)
{
	uint32 v = read4(si);
	return string_format("%u (%u:%u)", v, (v / 60), (v % 60));
}

static std::string
r_bootcount(const sraminfo_t& si)
{
	uint32 v = read4(si);
	return string_format("%d", v);
}


static std::string
r_debugger(const sraminfo_t& si)
{
	uint8 v = read1(si);
	std::string res;

	if (v == 0x00) {
		res = "off";
	} else if (v == 0xff) {
		res = "on";
	} else {
		res = string_format("on? (0x%02x)", v);
	}
	return res;
}

static int
w_debugger(const sraminfo_t& si, const std::string& input)
{
	uint8 newval;

	if (strcasecmp(input.c_str(), "off") == 0) {
		newval = 0;
	} else if (strcasecmp(input.c_str(), "on") == 0) {
		newval = 0xff;
	} else {
		warnx("%s='%s': bad parameter", si.name, input.c_str());
		return -1;
	}

	return update1(si, newval);
}

static const std::string
h_debugger(const sraminfo_t& si)
{
	return string_format("%s = { on | off }", si.name);
}

// パラメータ一覧
#define RWH(name)	r_##name, w_##name, h_##name
std::vector<sraminfo_t> sraminfo = {
	// offset	name		reader		writer	help
	{ 0x08,		"ramsize",	RWH(ramsize) },
	{ 0x0c,		"romaddr",	RWH(romaddr) },
	{ 0x10,		"ramaddr",	r_ramaddr, NULL },
	{ 0x14,		"alarm_until?" },
	{ 0x18,		"bootdev",	RWH(bootdev) },
	{ 0x1a,		"rs232c",	r_rs232c,	NULL },
	{ 0x1c,		"led",		r_led,		NULL },
	{ 0x1d,		"crtmod",	r_crtmod,	NULL },
	{ 0x1e,		"alarm_op?" },
	{ 0x22,		"alarm_time?" },
	{ 0x26,		"alarm_en?" },
	{ 0x27,		"tvctrl_en?" },
	{ 0x28,		"contrast",	r_contrast,	NULL },
	{ 0x29,		"fd_eject?" },
	{ 0x2a,		"tvctrl_code?" },
	{ 0x2b,		"keyboard?" },
	{ 0x2c,		"calc_font" },
	{ 0x2d,		"sram_use",	r_sram_use, NULL },
	{ 0x2e,		"textpal0" },
	{ 0x30,		"textpal1" },
	{ 0x32,		"textpal2" },
	{ 0x34,		"textpal3" },
	{ 0x36,		"textpal4" },
	{ 0x38,		"textpal8" },
	{ 0x3a,		"key_delay",	RWH(key_repeat) },
	{ 0x3b,		"key_repeat",	RWH(key_repeat) },
	{ 0x3c,		"prn_timeout?" },
	{ 0x40,		"boottime",	r_boottime,	NULL },
	{ 0x44,		"bootcount",r_bootcount,	NULL },
	{ 0x48,		"romdisk_fat?" },
	{ 0x58,		"debugger",	RWH(debugger) },
	{ 0x59,		"charmode" },
};

unix.superglobalmegacorp.com

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