|
|
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" },
};
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.