|
|
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: }
1.1.1.2 ! root 255: if (id < 0 || id > 16) {
! 256: warnx("%s='%s': out of range", si.name, input.c_str());
! 257: return -1;
! 258: }
1.1 root 259: newval = 0x8000 + (id << 8);
260: } else if (starts_with_ignorecase(input, "fd")) {
261: errno = 0;
1.1.1.2 ! root 262: start = input.c_str() + 2;
1.1 root 263: int id = strtoul(start, &end, 10);
264: if (end == start || *end != '\0' || errno == ERANGE) {
1.1.1.2 ! root 265: warnx("%s='%s': bad unit number", si.name, input.c_str());
! 266: return -1;
! 267: }
! 268: if (id < 0 || id > 4) {
! 269: warnx("%s='%s': out of range", si.name, input.c_str());
1.1 root 270: return -1;
271: }
272: newval = 0x9070 + (id << 8);
273: } else if (strcasecmp(input.c_str(), "rom") == 0) {
274: newval = 0xa000;
275: } else if (strcasecmp(input.c_str(), "ram") == 0) {
276: newval = 0xb000;
277: } else {
278: warnx("%s='%s': bad parameter", si.name, input.c_str());
279: return -1;
280: }
281:
282: return update16(si, newval);
283: }
284:
285: static const std::string
286: h_bootdev(const sraminfo_t& si)
287: {
288: return string_format("%s = { std | sasi<0..15> | fd<0..3> | rom | ram }",
289: si.name);
290: }
291:
292:
293: static std::string
294: r_rs232c(const sraminfo_t& si)
295: {
296: uint32 v = read16(si);
297: std::string res = string_format("$%04x (", v);
298:
299: std::array<std::string, 4> stopbit {
300: "2",
301: "1",
302: "1.5",
303: "2",
304: };
305: res += "stop=";
306: res += stopbit[(v >> 14)];
307: res += ',';
308:
309: std::array<std::string, 4> parity {
310: "none",
311: "odd",
312: "even",
313: "none",
314: };
315: res += "parity=";
316: res += parity[(v >> 12) & 3];
317: res += ',';
318:
319: res += string_format("%dbit,", ((v >> 10) & 3) + 5);
320:
321: std::array<int, 9> speed {
322: 75,
323: 150,
324: 300,
325: 600,
326: 1200,
327: 2400,
328: 4800,
329: 9600,
330: 17361, // X68030 only
331: };
332: uint32 vs = (v & 0x0f);
333: if (vs < speed.size()) {
334: res += string_format("%dbps", speed[vs]);
335: } else {
336: res += "?bps";
337: }
338:
339: res += ')';
340: return res;
341: }
342:
343: static std::string
344: r_led(const sraminfo_t& si)
345: {
346: uint8 v = read8(si);
347: std::string res = string_format("$%02x", v);
348:
349: std::array<std::string, 8> names {
350: "", // b7
351: "Zenkaku", // b6
352: "Hiragana", // b5
353: "INS", // b4
354: "CAPS", // b3
355: "Code", // b2
356: "Roma", // b1
357: "Kana", // b0
358: };
359: std::string map;
360: uint8 b = 0x40;
361: for (int i = 0; b; i++, b >>= 1) {
362: if ((v & b) != 0) {
363: if (map.empty() == false) {
364: map += ',';
365: }
366: map += names[i];
367: }
368: }
369:
370: if (map.empty() == false) {
371: res += ' ';
372: res += map;
373: }
374: return res;
375: }
376:
377: static std::string
378: r_crtmod(const sraminfo_t& si)
379: {
380: uint8 v = read8(si);
381: return string_format("$%02x", v);
382: }
383:
384: static std::string
385: r_contrast(const sraminfo_t& si)
386: {
387: uint8 v = read8(si);
388: return string_format("$%02x", v);
389: }
390:
391: static std::string
392: r_sram_use(const sraminfo_t& si)
393: {
394: uint8 v = read8(si);
395: std::string res;
396:
397: if (v == 0) {
398: res = "NotUsed";
399: } else if (v == 1) {
400: res = "SRAMDISK";
401: } else if (v == 2) {
402: res = "Program";
403: } else {
404: res = string_format("$%02x ?", v);
405: }
406: return res;
407: }
408:
409: //----- key_delay, key_repeat
410:
411: static std::string
412: r_key_repeat(const sraminfo_t& si)
413: {
414: uint8 v = read8(si);
415: std::string res = string_format("$%02x ", v);
416:
417: if (v < 16) {
418: int msec;
419: if (si.offset == 0x3a) {
420: msec = 200 + 100 * v;
421: } else {
422: msec = 30 + 5 * v * v;
423: }
424: res += string_format("(%dmsec)", msec);
425: } else {
426: res += "(??msec)";
427: }
428: return res;
429: }
430:
431: static int
432: w_key_repeat(const sraminfo_t& si, const std::string& input)
433: {
434: char *end;
435: int newval;
436:
437: errno = 0;
438: newval = strtoul(input.c_str(), &end, 10);
439: if (end == input.c_str() || *end != '\0' || errno == ERANGE) {
440: warnx("%s='%s': bad parameter", si.name, input.c_str());
441: return 0;
442: }
443:
444: // 値は10進数、直接指定
445: if (newval < 0 || newval > 255) {
446: warnx("%s='%d': invalid range", si.name, newval);
447: return -1;
448: }
449:
450: return update8(si, newval);
451: }
452:
453: static const std::string
454: h_key_repeat(const sraminfo_t& si)
455: {
456: return string_format("%s = { 0..15 }", si.name);
457: }
458:
459: //-----
460:
461: static std::string
462: r_boottime(const sraminfo_t& si)
463: {
464: uint32 v = read32(si);
465: return string_format("%u (%u:%u)", v, (v / 60), (v % 60));
466: }
467:
468: static std::string
469: r_bootcount(const sraminfo_t& si)
470: {
471: uint32 v = read32(si);
472: return string_format("%d", v);
473: }
474:
475:
476: static std::string
477: r_debugger(const sraminfo_t& si)
478: {
479: uint8 v = read8(si);
480: std::string res;
481:
482: if (v == 0x00) {
483: res = "off";
484: } else if (v == 0xff) {
485: res = "on";
486: } else {
487: res = string_format("on? (0x%02x)", v);
488: }
489: return res;
490: }
491:
492: static int
493: w_debugger(const sraminfo_t& si, const std::string& input)
494: {
495: uint8 newval;
496:
497: if (strcasecmp(input.c_str(), "off") == 0) {
498: newval = 0;
499: } else if (strcasecmp(input.c_str(), "on") == 0) {
500: newval = 0xff;
501: } else {
502: warnx("%s='%s': bad parameter", si.name, input.c_str());
503: return -1;
504: }
505:
506: return update8(si, newval);
507: }
508:
509: static const std::string
510: h_debugger(const sraminfo_t& si)
511: {
512: return string_format("%s = { on | off }", si.name);
513: }
514:
515: // パラメータ一覧
516: #define RWH(name) r_##name, w_##name, h_##name
517: std::vector<sraminfo_t> sraminfo = {
518: // offset name reader writer help
519: { 0x08, "ramsize", RWH(ramsize) },
520: { 0x0c, "romaddr", RWH(romaddr) },
521: { 0x10, "ramaddr", r_ramaddr, NULL },
522: { 0x14, "alarm_until?" },
523: { 0x18, "bootdev", RWH(bootdev) },
524: { 0x1a, "rs232c", r_rs232c, NULL },
525: { 0x1c, "led", r_led, NULL },
526: { 0x1d, "crtmod", r_crtmod, NULL },
527: { 0x1e, "alarm_op?" },
528: { 0x22, "alarm_time?" },
529: { 0x26, "alarm_en?" },
530: { 0x27, "tvctrl_en?" },
531: { 0x28, "contrast", r_contrast, NULL },
532: { 0x29, "fd_eject?" },
533: { 0x2a, "tvctrl_code?" },
534: { 0x2b, "keyboard?" },
535: { 0x2c, "calc_font" },
536: { 0x2d, "sram_use", r_sram_use, NULL },
537: { 0x2e, "textpal0" },
538: { 0x30, "textpal1" },
539: { 0x32, "textpal2" },
540: { 0x34, "textpal3" },
541: { 0x36, "textpal4" },
542: { 0x38, "textpal8" },
543: { 0x3a, "key_delay", RWH(key_repeat) },
544: { 0x3b, "key_repeat", RWH(key_repeat) },
545: { 0x3c, "prn_timeout?" },
546: { 0x40, "boottime", r_boottime, NULL },
547: { 0x44, "bootcount",r_bootcount, NULL },
548: { 0x48, "romdisk_fat?" },
549: { 0x58, "debugger", RWH(debugger) },
550: { 0x59, "charmode" },
551: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.