|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: #include "sramedit.h"
8: #include <array>
9:
10: // アクセスヘルパー
11:
12: uint32 read8(uint32 offset);
13: uint32 read16(uint32 offset);
14: uint32 read32(uint32 offset);
15: void write8(uint32 offset, uint32 val);
16: void write16(uint32 offset, uint32 val);
17: void write32(uint32 offset, uint32 val);
18: uint32 read8(const sraminfo_t&);
19: uint32 read16(const sraminfo_t&);
20: uint32 read32(const sraminfo_t&);
21: void write8(const sraminfo_t&, uint32 val);
22: void write16(const sraminfo_t&, uint32 val);
23: void write32(const sraminfo_t&, uint32 val);
24: int update8(const sraminfo_t&, uint32 val);
25: int update16(const sraminfo_t&, uint32 val);
26: int update32(const sraminfo_t&, uint32 val);
27:
28: uint32
29: read8(uint32 offset)
30: {
31: return sram[offset];
32: }
33:
34: uint32
35: read16(uint32 offset)
36: {
37: uint32 h = read8(offset) << 8;
38: uint32 l = read8(offset + 1);
39:
40: return (h | l);
41: }
42:
43: uint32
44: read32(uint32 offset)
45: {
46: uint32 h = read16(offset) << 16;
47: uint32 l = read16(offset + 2);
48:
49: return (h | l);
50: }
51:
52: void
53: write8(uint32 offset, uint32 val)
54: {
55: sram[offset] = (uint8)val;
56: }
57:
58: void
59: write16(uint32 offset, uint32 val)
60: {
61: write8(offset, val >> 8);
62: write8(offset + 1, val & 0xff);
63: }
64:
65: void
66: write32(uint32 offset, uint32 val)
67: {
68: write16(offset, val >> 16);
69: write16(offset + 2, val & 0xffff);
70: }
71:
72: uint32 read8(const sraminfo_t& si) { return read8(si.offset); }
73: uint32 read16(const sraminfo_t& si) { return read16(si.offset); }
74: uint32 read32(const sraminfo_t& si) { return read32(si.offset); }
75: void write8(const sraminfo_t& si, uint32 val) {
76: return write8(si.offset, val);
77: }
78: void write16(const sraminfo_t& si, uint32 val) {
79: return write16(si.offset, val);
80: }
81: void write32(const sraminfo_t& si, uint32 val) {
82: return write32(si.offset, val);
83: }
84:
85: int
86: update8(const sraminfo_t& si, uint32 val)
87: {
88: if (read8(si) == val) {
89: return 0;
90: }
91: write8(si, val);
92: return 1;
93: }
94:
95: int
96: update16(const sraminfo_t& si, uint32 val)
97: {
98: if (read16(si) == val) {
99: return 0;
100: }
101: write16(si, val);
102: return 1;
103: }
104:
105: int
106: update32(const sraminfo_t& si, uint32 val)
107: {
108: if (read32(si) == val) {
109: return 0;
110: }
111: write32(si, val);
112: return 1;
113: }
114:
115: //
116: // 個別処理
117: //
118:
119: //----- ramsize
120:
121: static std::string
122: r_ramsize(const sraminfo_t& si)
123: {
124: uint32 v = read32(si);
125: std::string res = string_format("$%08x", v);
126: if (v % (1024 * 1024) == 0) {
127: res += string_format(" (%dMB)", v / 1024 / 1024);
128: }
129: return res;
130: }
131:
132: static int
133: w_ramsize(const sraminfo_t& si, const std::string& input)
134: {
135: char *end;
136: uint32 newval;
137:
138: errno = 0;
139: newval = strtoul(input.c_str(), &end, 10);
140: // 後ろに M が付くのだけ許容する?
141: if (end == input.c_str() || errno == ERANGE ||
142: (*end != '\0' && *end != 'm' && *end != 'M')) {
143: warnx("%s='%s': bad parameter", si.name, input.c_str());
144: return -1;
145: }
146: newval *= 1024 * 1024;
147:
148: return update32(si, newval);
149: }
150:
151: static const std::string
152: h_ramsize(const sraminfo_t& si)
153: {
154: return string_format("%s = { 4..12 }", si.name);
155: }
156:
157: //----- romaddr
158:
159: static std::string
160: r_romaddr(const sraminfo_t& si)
161: {
162: uint32 v = read32(si);
163: std::string res = string_format("$%08x", v);
164: if (0xfc0000 <= v && v < 0xfc0020) {
165: res += string_format(" (SCSI%d)", (v - 0xfc0000) / 4);
166: }
167: return res;
168: }
169:
170: static int
171: w_romaddr(const sraminfo_t& si, const std::string& input)
172: {
173: char *end;
174: uint32 newval;
175:
176: errno = 0;
177: if (starts_with_ignorecase(input, "scsi")) {
178: const char *start = input.c_str() + 4;
179: int id = strtoul(start, &end, 10);
180: if (end == start || *end != '\0' || errno == ERANGE) {
181: warnx("%s='%s': bad SCSI ID", si.name, input.c_str());
182: return -1;
183: }
184: newval = 0xfc0000 + id * 4;
185: } else {
186: newval = strtoul(input.c_str(), &end, 16);
187: if (end == input.c_str() || *end != '\0' || errno == ERANGE) {
188: warnx("%s='%s': bad address", si.name, input.c_str());
189: }
190: if (newval > 0xffffff) {
191: warnx("%s='%s': bad address", si.name, input.c_str());
192: }
193: }
194:
195: return update32(si, newval);
196: }
197:
198: static const std::string
199: h_romaddr(const sraminfo_t& si)
200: {
201: return string_format("%s = { [0x]<hexaddr> | scsi<0..7> }", si.name);
202: }
203:
204: //---
205:
206: static std::string
207: r_ramaddr(const sraminfo_t& si)
208: {
209: uint32 v = read32(si);
210: return string_format("$%08x", v);
211: }
212:
213: //----- bootdev
214:
215: static std::string
216: r_bootdev(const sraminfo_t& si)
217: {
218: uint32 v = read16(si);
219: std::string res = string_format("$%04x ", v);
220:
221: if (v == 0x0000) {
222: res += "STD (FD->HD->ROM->RAM)";
223: } else if ((v & 0xf0ff) == 0x8000) {
224: res += string_format("SASI%d", (v >> 8) & 0x0f);
225: } else if ((v & 0xf0ff) == 0x9070) {
226: res += string_format("FD%d", (v >> 8) & 0x0f);
227: } else if (v == 0xa000) {
228: res += "ROM";
229: } else if (v == 0xb000) {
230: res += "RAM";
231: } else {
232: res += "?";
233: }
234:
235: return res;
236: }
237:
238: static int
239: w_bootdev(const sraminfo_t& si, const std::string& input)
240: {
241: const char *start;
242: char *end;
243: int32 newval;
244:
245: if (strcasecmp(input.c_str(), "std") == 0) {
246: newval = 0x0000;
247: } else if (starts_with_ignorecase(input, "sasi")) {
248: errno = 0;
249: start = input.c_str() + 4;
250: int id = strtoul(start, &end, 10);
251: if (end == start || *end != '\0' || errno == ERANGE) {
252: warnx("%s='%s': bad SASI ID", si.name, input.c_str());
253: return -1;
254: }
255: newval = 0x8000 + (id << 8);
256: } else if (starts_with_ignorecase(input, "fd")) {
257: errno = 0;
258: start = input.c_str() + 4;
259: int id = strtoul(start, &end, 10);
260: if (end == start || *end != '\0' || errno == ERANGE) {
261: warnx("%s='%s': bad SASI ID", si.name, input.c_str());
262: return -1;
263: }
264: newval = 0x9070 + (id << 8);
265: } else if (strcasecmp(input.c_str(), "rom") == 0) {
266: newval = 0xa000;
267: } else if (strcasecmp(input.c_str(), "ram") == 0) {
268: newval = 0xb000;
269: } else {
270: warnx("%s='%s': bad parameter", si.name, input.c_str());
271: return -1;
272: }
273:
274: return update16(si, newval);
275: }
276:
277: static const std::string
278: h_bootdev(const sraminfo_t& si)
279: {
280: return string_format("%s = { std | sasi<0..15> | fd<0..3> | rom | ram }",
281: si.name);
282: }
283:
284:
285: static std::string
286: r_rs232c(const sraminfo_t& si)
287: {
288: uint32 v = read16(si);
289: std::string res = string_format("$%04x (", v);
290:
291: std::array<std::string, 4> stopbit {
292: "2",
293: "1",
294: "1.5",
295: "2",
296: };
297: res += "stop=";
298: res += stopbit[(v >> 14)];
299: res += ',';
300:
301: std::array<std::string, 4> parity {
302: "none",
303: "odd",
304: "even",
305: "none",
306: };
307: res += "parity=";
308: res += parity[(v >> 12) & 3];
309: res += ',';
310:
311: res += string_format("%dbit,", ((v >> 10) & 3) + 5);
312:
313: std::array<int, 9> speed {
314: 75,
315: 150,
316: 300,
317: 600,
318: 1200,
319: 2400,
320: 4800,
321: 9600,
322: 17361, // X68030 only
323: };
324: uint32 vs = (v & 0x0f);
325: if (vs < speed.size()) {
326: res += string_format("%dbps", speed[vs]);
327: } else {
328: res += "?bps";
329: }
330:
331: res += ')';
332: return res;
333: }
334:
335: static std::string
336: r_led(const sraminfo_t& si)
337: {
338: uint8 v = read8(si);
339: std::string res = string_format("$%02x", v);
340:
341: std::array<std::string, 8> names {
342: "", // b7
343: "Zenkaku", // b6
344: "Hiragana", // b5
345: "INS", // b4
346: "CAPS", // b3
347: "Code", // b2
348: "Roma", // b1
349: "Kana", // b0
350: };
351: std::string map;
352: uint8 b = 0x40;
353: for (int i = 0; b; i++, b >>= 1) {
354: if ((v & b) != 0) {
355: if (map.empty() == false) {
356: map += ',';
357: }
358: map += names[i];
359: }
360: }
361:
362: if (map.empty() == false) {
363: res += ' ';
364: res += map;
365: }
366: return res;
367: }
368:
369: static std::string
370: r_crtmod(const sraminfo_t& si)
371: {
372: uint8 v = read8(si);
373: return string_format("$%02x", v);
374: }
375:
376: static std::string
377: r_contrast(const sraminfo_t& si)
378: {
379: uint8 v = read8(si);
380: return string_format("$%02x", v);
381: }
382:
383: static std::string
384: r_sram_use(const sraminfo_t& si)
385: {
386: uint8 v = read8(si);
387: std::string res;
388:
389: if (v == 0) {
390: res = "NotUsed";
391: } else if (v == 1) {
392: res = "SRAMDISK";
393: } else if (v == 2) {
394: res = "Program";
395: } else {
396: res = string_format("$%02x ?", v);
397: }
398: return res;
399: }
400:
401: //----- key_delay, key_repeat
402:
403: static std::string
404: r_key_repeat(const sraminfo_t& si)
405: {
406: uint8 v = read8(si);
407: std::string res = string_format("$%02x ", v);
408:
409: if (v < 16) {
410: int msec;
411: if (si.offset == 0x3a) {
412: msec = 200 + 100 * v;
413: } else {
414: msec = 30 + 5 * v * v;
415: }
416: res += string_format("(%dmsec)", msec);
417: } else {
418: res += "(??msec)";
419: }
420: return res;
421: }
422:
423: static int
424: w_key_repeat(const sraminfo_t& si, const std::string& input)
425: {
426: char *end;
427: int newval;
428:
429: errno = 0;
430: newval = strtoul(input.c_str(), &end, 10);
431: if (end == input.c_str() || *end != '\0' || errno == ERANGE) {
432: warnx("%s='%s': bad parameter", si.name, input.c_str());
433: return 0;
434: }
435:
436: // 値は10進数、直接指定
437: if (newval < 0 || newval > 255) {
438: warnx("%s='%d': invalid range", si.name, newval);
439: return -1;
440: }
441:
442: return update8(si, newval);
443: }
444:
445: static const std::string
446: h_key_repeat(const sraminfo_t& si)
447: {
448: return string_format("%s = { 0..15 }", si.name);
449: }
450:
451: //-----
452:
453: static std::string
454: r_boottime(const sraminfo_t& si)
455: {
456: uint32 v = read32(si);
457: return string_format("%u (%u:%u)", v, (v / 60), (v % 60));
458: }
459:
460: static std::string
461: r_bootcount(const sraminfo_t& si)
462: {
463: uint32 v = read32(si);
464: return string_format("%d", v);
465: }
466:
467:
468: static std::string
469: r_debugger(const sraminfo_t& si)
470: {
471: uint8 v = read8(si);
472: std::string res;
473:
474: if (v == 0x00) {
475: res = "off";
476: } else if (v == 0xff) {
477: res = "on";
478: } else {
479: res = string_format("on? (0x%02x)", v);
480: }
481: return res;
482: }
483:
484: static int
485: w_debugger(const sraminfo_t& si, const std::string& input)
486: {
487: uint8 newval;
488:
489: if (strcasecmp(input.c_str(), "off") == 0) {
490: newval = 0;
491: } else if (strcasecmp(input.c_str(), "on") == 0) {
492: newval = 0xff;
493: } else {
494: warnx("%s='%s': bad parameter", si.name, input.c_str());
495: return -1;
496: }
497:
498: return update8(si, newval);
499: }
500:
501: static const std::string
502: h_debugger(const sraminfo_t& si)
503: {
504: return string_format("%s = { on | off }", si.name);
505: }
506:
507: // パラメータ一覧
508: #define RWH(name) r_##name, w_##name, h_##name
509: std::vector<sraminfo_t> sraminfo = {
510: // offset name reader writer help
511: { 0x08, "ramsize", RWH(ramsize) },
512: { 0x0c, "romaddr", RWH(romaddr) },
513: { 0x10, "ramaddr", r_ramaddr, NULL },
514: { 0x14, "alarm_until?" },
515: { 0x18, "bootdev", RWH(bootdev) },
516: { 0x1a, "rs232c", r_rs232c, NULL },
517: { 0x1c, "led", r_led, NULL },
518: { 0x1d, "crtmod", r_crtmod, NULL },
519: { 0x1e, "alarm_op?" },
520: { 0x22, "alarm_time?" },
521: { 0x26, "alarm_en?" },
522: { 0x27, "tvctrl_en?" },
523: { 0x28, "contrast", r_contrast, NULL },
524: { 0x29, "fd_eject?" },
525: { 0x2a, "tvctrl_code?" },
526: { 0x2b, "keyboard?" },
527: { 0x2c, "calc_font" },
528: { 0x2d, "sram_use", r_sram_use, NULL },
529: { 0x2e, "textpal0" },
530: { 0x30, "textpal1" },
531: { 0x32, "textpal2" },
532: { 0x34, "textpal3" },
533: { 0x36, "textpal4" },
534: { 0x38, "textpal8" },
535: { 0x3a, "key_delay", RWH(key_repeat) },
536: { 0x3b, "key_repeat", RWH(key_repeat) },
537: { 0x3c, "prn_timeout?" },
538: { 0x40, "boottime", r_boottime, NULL },
539: { 0x44, "bootcount",r_bootcount, NULL },
540: { 0x48, "romdisk_fat?" },
541: { 0x58, "debugger", RWH(debugger) },
542: { 0x59, "charmode" },
543: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.