ti83-sdk/tool/tilem-src/emu/state.c

893 lines
23 KiB
C
Raw Normal View History

2023-10-08 16:33:37 +00:00
/*
* libtilemcore - Graphing calculator emulation library
*
* Copyright (C) 2009-2012 Benjamin Moody
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tilem.h"
#include "z80.h"
static void set_hw_reg(TilemCalc* calc, const char* name, dword value)
{
int i;
for (i = 0; i < calc->hw.nhwregs; i++) {
if (!strcmp(name, calc->hw.hwregnames[i])) {
calc->hwregs[i] = value;
return;
}
}
tilem_warning(calc, "Unknown hwreg %s", name);
}
static const char* get_timer_name(TilemCalc* calc, int id)
{
if (id == TILEM_TIMER_LCD_DELAY)
return "lcddelay";
else if (id == TILEM_TIMER_FLASH_DELAY)
return "flashdelay";
else if (id == TILEM_TIMER_LINK_ASSIST)
return "linkassist";
else if (id == TILEM_TIMER_USER1)
return "user1";
else if (id == TILEM_TIMER_USER2)
return "user2";
else if (id == TILEM_TIMER_USER3)
return "user3";
else if (id <= TILEM_NUM_SYS_TIMERS)
abort();
id -= TILEM_NUM_SYS_TIMERS + 1;
if (id < calc->hw.nhwtimers)
return calc->hw.hwtimernames[id];
else
return NULL;
}
static void set_ptimer(TilemCalc* calc, const char* name, dword value,
dword period, int rt)
{
int i;
const char* tname;
for (i = 1; i <= calc->z80.ntimers; i++) {
tname = get_timer_name(calc, i);
if (tname && !strcmp(name, tname)) {
tilem_z80_set_timer(calc, i, value, period, rt);
return;
}
}
tilem_warning(calc, "Unknown timer %s", name);
}
static int load_old_sav_file(TilemCalc* calc, FILE* savfile)
{
byte b[76];
dword regs[19];
int i, le, be, c;
unsigned int pageA, pageB;
/* Read memory mapping */
if (fread(calc->mempagemap, 1, 4, savfile) < 4)
return 1;
/* Read CPU registers */
if (fread(b, 1, 76, savfile) < 76)
return 1;
be = le = 0;
/* determine if file is in big-endian or little-endian
format */
for (i = 0; i < 19; i++) {
if (b[i * 4] || b[i * 4 + 1])
le++;
if (b[i * 4 + 2] || b[i * 4 + 3])
be++;
}
if (le > be) {
for (i = 0; i < 19; i++) {
regs[i] = b[i * 4] + (b[i * 4 + 1] << 8);
}
}
else {
for (i = 0; i < 19; i++) {
regs[i] = b[i * 4 + 3] + (b[i * 4 + 2] << 8);
}
}
calc->z80.r.af.d = regs[0];
calc->z80.r.bc.d = regs[1];
calc->z80.r.de.d = regs[2];
calc->z80.r.hl.d = regs[3];
calc->z80.r.ix.d = regs[4];
calc->z80.r.iy.d = regs[5];
calc->z80.r.pc.d = regs[6];
calc->z80.r.sp.d = regs[7];
calc->z80.r.af2.d = regs[8];
calc->z80.r.bc2.d = regs[9];
calc->z80.r.de2.d = regs[10];
calc->z80.r.hl2.d = regs[11];
calc->z80.r.iff1 = regs[12] ? 1 : 0;
calc->z80.r.iff2 = regs[13] ? 1 : 0;
calc->z80.r.im = regs[15];
calc->z80.r.ir.b.h = regs[16];
calc->z80.r.ir.b.l = regs[17];
calc->z80.r.r7 = regs[18] & 0x80;
if (calc->hw.model_id == '2' || calc->hw.model_id == '3') {
if (fread(b, 1, 5, savfile) < 5)
return 1;
if (calc->hw.model_id == '3')
set_hw_reg(calc, "rom_bank", calc->mempagemap[1] & 0x08);
calc->hw.z80_out(calc, 0x02, b[4]);
}
/* Read RAM contents: old save files for TI-82/83/85 store RAM
pages in logical rather than physical order */
if (calc->hw.model_id == '2' || calc->hw.model_id == '3'
|| calc->hw.model_id == '5') {
if (fread(calc->mem + calc->hw.romsize + 0x4000, 1,
0x4000, savfile) < 0x4000)
return 1;
if (fread(calc->mem + calc->hw.romsize, 1,
0x4000, savfile) < 0x4000)
return 1;
}
else {
if (fread(calc->mem + calc->hw.romsize, 1,
calc->hw.ramsize, savfile) < calc->hw.ramsize)
return 1;
}
/* Read LCD contents */
if (calc->hw.flags & TILEM_CALC_HAS_T6A04) {
calc->lcd.rowstride = 12; /* old save files only
support the visible
portion of the screen */
if (fread(calc->lcdmem, 1, 768, savfile) < 768)
return 1;
}
/* Read additional HW state */
switch (calc->hw.model_id) {
case '1':
break;
case '2':
case '3':
if ((c = fgetc(savfile)) != EOF)
calc->lcd.mode = c;
if ((c = fgetc(savfile)) != EOF)
calc->lcd.x = c;
if ((c = fgetc(savfile)) != EOF)
calc->lcd.y = c;
break;
case '5':
pageA = calc->mempagemap[1];
if (pageA >= 0x08)
pageA += 0x38;
calc->hw.z80_out(calc, 0x05, pageA);
if ((c = fgetc(savfile)) != EOF)
calc->hw.z80_out(calc, 0x06, c);
break;
case '6':
pageA = calc->mempagemap[1];
pageB = calc->mempagemap[2];
if (pageA >= 0x10)
pageA += 0x30;
if (pageB >= 0x10)
pageB += 0x30;
calc->hw.z80_out(calc, 0x05, pageA);
calc->hw.z80_out(calc, 0x06, pageB);
break;
default: /* TI-73/83+ series */
if ((c = fgetc(savfile)) != EOF)
calc->lcd.mode = c;
if ((c = fgetc(savfile)) != EOF)
calc->lcd.x = c;
if ((c = fgetc(savfile)) != EOF)
calc->lcd.y = c;
if ((c = fgetc(savfile)) != EOF)
calc->lcd.inc = c;
if ((c = fgetc(savfile)) == EOF)
c = 0;
if (c) {
pageA = calc->mempagemap[2];
pageB = calc->mempagemap[3];
calc->hw.z80_out(calc, 0x04, 0x77);
}
else {
pageA = calc->mempagemap[1];
pageB = calc->mempagemap[2];
calc->hw.z80_out(calc, 0x04, 0x76);
}
if (pageA >= (calc->hw.romsize >> 14))
pageA = ((pageA & 0x1f) | calc->hw.rampagemask);
if (pageB >= (calc->hw.romsize >> 14))
pageB = ((pageB & 0x1f) | calc->hw.rampagemask);
calc->hw.z80_out(calc, 0x06, pageA);
calc->hw.z80_out(calc, 0x07, pageB);
if ((c = fgetc(savfile)) != EOF)
calc->flash.state = c;
if ((c = fgetc(savfile)) != EOF)
calc->flash.unlock = c;
if ((c = fgetc(savfile)) != EOF)
calc->hw.z80_out(calc, 0x20, c);
if ((c = fgetc(savfile)) != EOF)
set_hw_reg(calc, "port21", c);
if ((c = fgetc(savfile)) != EOF)
set_hw_reg(calc, "port22", c);
if ((c = fgetc(savfile)) != EOF)
set_hw_reg(calc, "port23", c);
if ((c = fgetc(savfile)) != EOF)
calc->hw.z80_out(calc, 0x27, c);
if ((c = fgetc(savfile)) != EOF)
calc->hw.z80_out(calc, 0x28, c);
break;
}
calc->poweronhalt = calc->lcd.active = 1;
return 0;
}
static int read_sav_line(FILE* savfile, char **buf)
{
int c, n, na;
tilem_free(*buf);
na = 100;
*buf = tilem_malloc_atomic(na);
n = 0;
while ((c = fgetc(savfile)) != EOF) {
if (c == '\r' || c == '\n')
break;
n++;
if (n >= na) {
na = n * 2;
*buf = tilem_realloc(*buf, na);
}
if (c == '#')
c = 0;
(*buf)[n - 1] = c;
}
if (n == 0 && c == EOF) {
tilem_free(*buf);
*buf = NULL;
return 0;
}
else {
(*buf)[n] = 0;
return 1;
}
}
static int parse_sav_definition(char* line, char** value)
{
char *p;
p = strchr(line, '=');
if (!p)
return 0;
while (p != line && p[-1] == ' ')
p--;
*p = 0;
p++;
while (*p == ' ' || *p == '=')
p++;
*value = p;
return 1;
}
static int load_new_sav_file(TilemCalc* calc, FILE* savfile)
{
char *buf = NULL;
char *p, *q;
dword value, length;
byte *data;
int ok = 0;
byte digit;
int firstdigit;
dword period;
int rt;
while (read_sav_line(savfile, &buf)) {
if (!parse_sav_definition(buf, &p))
continue;
if (*p == '{') {
p++;
if (!strcmp(buf, "RAM")) {
length = calc->hw.ramsize;
data = calc->ram;
}
else if (!strcmp(buf, "LCD")) {
length = calc->hw.lcdmemsize;
data = calc->lcdmem;
}
else {
length = 0;
data = NULL;
}
value = 0;
firstdigit = 1;
while (*p != '}') {
if (*p == 0 || *p == '#') {
if (!read_sav_line(savfile, &buf))
return 1;
p = buf;
continue;
}
if (*p >= '0' && *p <= '9') {
digit = *p - '0';
p++;
}
else if (*p >= 'A' && *p <= 'F') {
digit = *p + 10 - 'A';
p++;
}
else if (*p >= 'a' && *p <= 'f') {
digit = *p + 10 - 'a';
p++;
}
else {
p++;
continue;
}
if (firstdigit) {
value = digit << 4;
firstdigit = 0;
}
else {
value |= digit;
if (length != 0) {
*data = value;
data++;
length--;
}
firstdigit = 1;
}
}
continue;
}
if (!strcmp(buf, "MODEL")) {
q = p;
while (*q >= ' ')
q++;
*q = 0;
if (strcmp(p, calc->hw.name)) {
tilem_free(buf);
return 1;
}
ok = 1;
continue;
}
value = strtol(p, &q, 16);
/* Persistent timers */
if (!strncmp(buf, "timer:", 6)) {
while (*q == ' ')
q++;
if (*q != ',')
continue;
q++;
while (*q == ' ')
q++;
period = strtol(q, &q, 16);
while (*q == ' ')
q++;
if (*q != ',')
continue;
q++;
while (*q == ' ')
q++;
rt = strtol(q, &q, 16);
set_ptimer(calc, buf + 6, value, period, rt);
continue;
}
/* Z80 */
if (!strcmp(buf, "af")) calc->z80.r.af.d = value;
else if (!strcmp(buf, "bc")) calc->z80.r.bc.d = value;
else if (!strcmp(buf, "de")) calc->z80.r.de.d = value;
else if (!strcmp(buf, "hl")) calc->z80.r.hl.d = value;
else if (!strcmp(buf, "af'")) calc->z80.r.af2.d = value;
else if (!strcmp(buf, "bc'")) calc->z80.r.bc2.d = value;
else if (!strcmp(buf, "de'")) calc->z80.r.de2.d = value;
else if (!strcmp(buf, "hl'")) calc->z80.r.hl2.d = value;
else if (!strcmp(buf, "ix")) calc->z80.r.ix.d = value;
else if (!strcmp(buf, "iy")) calc->z80.r.iy.d = value;
else if (!strcmp(buf, "pc")) calc->z80.r.pc.d = value;
else if (!strcmp(buf, "sp")) calc->z80.r.sp.d = value;
else if (!strcmp(buf, "ir")) {
calc->z80.r.ir.d = value;
calc->z80.r.r7 = value & 0x80;
}
else if (!strcmp(buf, "wz")) calc->z80.r.wz.d = value;
else if (!strcmp(buf, "wz'")) calc->z80.r.wz2.d = value;
else if (!strcmp(buf, "iff1")) calc->z80.r.iff1 = value;
else if (!strcmp(buf, "iff2")) calc->z80.r.iff2 = value;
else if (!strcmp(buf, "im")) calc->z80.r.im = value;
else if (!strcmp(buf, "interrupts"))
calc->z80.interrupts = value;
else if (!strcmp(buf, "clockspeed"))
calc->z80.clockspeed = value;
else if (!strcmp(buf, "halted")) calc->z80.halted = value;
/* LCD */
else if (!strcmp(buf, "lcd.active"))
calc->lcd.active = value;
else if (!strcmp(buf, "lcd.addr"))
calc->lcd.addr = value;
else if (!strcmp(buf, "lcd.rowshift"))
calc->lcd.rowshift = value;
else if (!strcmp(buf, "lcd.contrast"))
calc->lcd.contrast = value;
else if (!strcmp(buf, "lcd.inc"))
calc->lcd.inc = value;
else if (!strcmp(buf, "lcd.mode"))
calc->lcd.mode = value;
else if (!strcmp(buf, "lcd.x"))
calc->lcd.x = value;
else if (!strcmp(buf, "lcd.y"))
calc->lcd.y = value;
else if (!strcmp(buf, "lcd.nextbyte"))
calc->lcd.nextbyte = value;
else if (!strcmp(buf, "lcd.rowstride"))
calc->lcd.rowstride = value;
else if (!strcmp(buf, "lcd.busy"))
calc->lcd.busy = value;
/* Link port */
else if (!strcmp(buf, "linkport.lines"))
calc->linkport.lines = value;
else if (!strcmp(buf, "linkport.mode"))
calc->linkport.mode = value;
else if (!strcmp(buf, "linkport.assistflags"))
calc->linkport.assistflags = value;
else if (!strcmp(buf, "linkport.assistin"))
calc->linkport.assistin = value;
else if (!strcmp(buf, "linkport.assistinbits"))
calc->linkport.assistinbits = value;
else if (!strcmp(buf, "linkport.assistout"))
calc->linkport.assistout = value;
else if (!strcmp(buf, "linkport.assistoutbits"))
calc->linkport.assistoutbits = value;
else if (!strcmp(buf, "linkport.assistlastbyte"))
calc->linkport.assistlastbyte = value;
/* Keypad */
else if (!strcmp(buf, "keypad.group"))
calc->keypad.group = value;
else if (!strcmp(buf, "keypad.onkeyint"))
calc->keypad.onkeyint = value;
/* MD5 assist */
else if (!strcmp(buf, "md5assist.a"))
calc->md5assist.regs[0] = value;
else if (!strcmp(buf, "md5assist.b"))
calc->md5assist.regs[1] = value;
else if (!strcmp(buf, "md5assist.c"))
calc->md5assist.regs[2] = value;
else if (!strcmp(buf, "md5assist.d"))
calc->md5assist.regs[3] = value;
else if (!strcmp(buf, "md5assist.x"))
calc->md5assist.regs[4] = value;
else if (!strcmp(buf, "md5assist.t"))
calc->md5assist.regs[5] = value;
else if (!strcmp(buf, "md5assist.shift"))
calc->md5assist.shift = value;
else if (!strcmp(buf, "md5assist.mode"))
calc->md5assist.mode = value;
/* Programmable timers */
else if (!strcmp(buf, "usertimer0.frequency"))
calc->usertimers[0].frequency = value;
else if (!strcmp(buf, "usertimer0.loopvalue"))
calc->usertimers[0].loopvalue = value;
else if (!strcmp(buf, "usertimer0.status"))
calc->usertimers[0].status = value;
else if (!strcmp(buf, "usertimer1.frequency"))
calc->usertimers[1].frequency = value;
else if (!strcmp(buf, "usertimer1.loopvalue"))
calc->usertimers[1].loopvalue = value;
else if (!strcmp(buf, "usertimer1.status"))
calc->usertimers[1].status = value;
else if (!strcmp(buf, "usertimer2.frequency"))
calc->usertimers[2].frequency = value;
else if (!strcmp(buf, "usertimer2.loopvalue"))
calc->usertimers[2].loopvalue = value;
else if (!strcmp(buf, "usertimer2.status"))
calc->usertimers[2].status = value;
/* Main power */
else if (!strcmp(buf, "poweronhalt"))
calc->poweronhalt = value;
/* Battery */
else if (!strcmp(buf, "battery"))
calc->battery = value;
/* Memory */
else if (!strcmp(buf, "mempagemap0"))
calc->mempagemap[0] = value;
else if (!strcmp(buf, "mempagemap1"))
calc->mempagemap[1] = value;
else if (!strcmp(buf, "mempagemap2"))
calc->mempagemap[2] = value;
else if (!strcmp(buf, "mempagemap3"))
calc->mempagemap[3] = value;
else if (!strcmp(buf, "flash.unlock"))
calc->flash.unlock = value;
else if (!strcmp(buf, "flash.state"))
calc->flash.state = value;
else if (!strcmp(buf, "flash.busy"))
calc->flash.busy = value;
else if (!strcmp(buf, "flash.progaddr"))
calc->flash.progaddr = value;
else if (!strcmp(buf, "flash.progbyte"))
calc->flash.progbyte = value;
else if (!strcmp(buf, "flash.toggles"))
calc->flash.toggles = value;
else if (!strcmp(buf, "flash.overridegroup"))
calc->flash.overridegroup = value;
else
set_hw_reg(calc, buf, value);
}
tilem_free(buf);
return !ok;
}
int tilem_calc_load_state(TilemCalc* calc, FILE* romfile, FILE* savfile)
{
int b;
int savtype = 0;
if (romfile) {
if (fread(calc->mem, 1, calc->hw.romsize, romfile)
!= calc->hw.romsize)
return 1;
}
tilem_calc_reset(calc);
if (savfile) {
/* first byte of old save files is always zero */
b = fgetc(savfile);
fseek(savfile, 0L, SEEK_SET);
if (b == 0) {
if (load_old_sav_file(calc, savfile)) {
tilem_calc_reset(calc);
return 1;
}
else
savtype = 1;
}
else {
if (load_new_sav_file(calc, savfile)) {
tilem_calc_reset(calc);
return 1;
}
else
savtype = 2;
}
}
if (calc->hw.stateloaded)
(*calc->hw.stateloaded)(calc, savtype);
return 0;
}
char tilem_get_sav_type(FILE* savfile)
{
int b;
char *buf = NULL, *p, *q;
const TilemHardware **models;
int nmodels, i;
char id = 0;
tilem_get_supported_hardware(&models, &nmodels);
/* first byte of old save files is always zero */
b = fgetc(savfile);
fseek(savfile, 0L, SEEK_SET);
if (b == 0)
return 0; /* old files give no way to detect model */
while (read_sav_line(savfile, &buf)) {
if (parse_sav_definition(buf, &p)
&& !strcmp(buf, "MODEL")) {
q = p;
while (*q >= ' ')
q++;
*q = 0;
for (i = 0; i < nmodels; i++)
if (!strcmp(p, models[i]->name))
id = models[i]->model_id;
break;
}
}
fseek(savfile, 0L, SEEK_SET);
tilem_free(buf);
return id;
}
int tilem_calc_save_state(TilemCalc* calc, FILE* romfile, FILE* savfile)
{
dword i;
dword t;
int j;
const char* tname;
unsigned int rowstride;
if (romfile) {
if (fwrite(calc->mem, 1, calc->hw.romsize, romfile)
!= calc->hw.romsize)
return 1;
}
if (savfile) {
fprintf(savfile, "# Tilem II State File\n# Version: %s\n",
PACKAGE_VERSION);
fprintf(savfile, "MODEL = %s\n", calc->hw.name);
fprintf(savfile, "\n## CPU ##\n");
fprintf(savfile, "af = %04X\n", calc->z80.r.af.w.l);
fprintf(savfile, "bc = %04X\n", calc->z80.r.bc.w.l);
fprintf(savfile, "de = %04X\n", calc->z80.r.de.w.l);
fprintf(savfile, "hl = %04X\n", calc->z80.r.hl.w.l);
fprintf(savfile, "af' = %04X\n", calc->z80.r.af2.w.l);
fprintf(savfile, "bc' = %04X\n", calc->z80.r.bc2.w.l);
fprintf(savfile, "de' = %04X\n", calc->z80.r.de2.w.l);
fprintf(savfile, "hl' = %04X\n", calc->z80.r.hl2.w.l);
fprintf(savfile, "ix = %04X\n", calc->z80.r.ix.w.l);
fprintf(savfile, "iy = %04X\n", calc->z80.r.iy.w.l);
fprintf(savfile, "pc = %04X\n", calc->z80.r.pc.w.l);
fprintf(savfile, "sp = %04X\n", calc->z80.r.sp.w.l);
fprintf(savfile, "ir = %04X\n",
((calc->z80.r.ir.w.l & ~0x80) | calc->z80.r.r7));
fprintf(savfile, "wz = %04X\n", calc->z80.r.wz.w.l);
fprintf(savfile, "wz' = %04X\n", calc->z80.r.wz2.w.l);
fprintf(savfile, "iff1 = %X\n", calc->z80.r.iff1);
fprintf(savfile, "iff2 = %X\n", calc->z80.r.iff2);
fprintf(savfile, "im = %X\n", calc->z80.r.im);
fprintf(savfile, "interrupts = %08X\n", calc->z80.interrupts);
fprintf(savfile, "clockspeed = %X\n", calc->z80.clockspeed);
fprintf(savfile, "halted = %X\n", calc->z80.halted);
fprintf(savfile, "\n## LCD Driver ##\n");
fprintf(savfile, "lcd.active = %X\n",
calc->lcd.active);
fprintf(savfile, "lcd.contrast = %X\n",
calc->lcd.contrast);
fprintf(savfile, "lcd.rowstride = %X\n",
calc->lcd.rowstride);
if (calc->hw.flags & TILEM_CALC_HAS_T6A04) {
fprintf(savfile, "lcd.rowshift = %X\n",
calc->lcd.rowshift);
fprintf(savfile, "lcd.inc = %X\n",
calc->lcd.inc);
fprintf(savfile, "lcd.mode = %X\n",
calc->lcd.mode);
fprintf(savfile, "lcd.x = %02X\n",
calc->lcd.x);
fprintf(savfile, "lcd.y = %02X\n",
calc->lcd.y);
fprintf(savfile, "lcd.nextbyte = %02X\n",
calc->lcd.nextbyte);
fprintf(savfile, "lcd.busy = %X\n",
calc->lcd.busy);
}
fprintf(savfile, "lcd.addr = %X\n", calc->lcd.addr);
if (calc->hw.flags & TILEM_CALC_HAS_LINK) {
fprintf(savfile, "\n## Link Port ##\n");
fprintf(savfile, "linkport.lines = %X\n",
calc->linkport.lines);
fprintf(savfile, "linkport.mode = %08X\n",
calc->linkport.mode);
}
if (calc->hw.flags & TILEM_CALC_HAS_LINK_ASSIST) {
fprintf(savfile, "linkport.assistflags = %08X\n",
calc->linkport.assistflags);
fprintf(savfile, "linkport.assistin = %02X\n",
calc->linkport.assistin);
fprintf(savfile, "linkport.assistinbits = %X\n",
calc->linkport.assistinbits);
fprintf(savfile, "linkport.assistout = %02X\n",
calc->linkport.assistout);
fprintf(savfile, "linkport.assistoutbits = %X\n",
calc->linkport.assistoutbits);
fprintf(savfile, "linkport.assistlastbyte = %02X\n",
calc->linkport.assistlastbyte);
}
fprintf(savfile, "\n## Keypad ##\n");
fprintf(savfile, "keypad.group = %X\n", calc->keypad.group);
fprintf(savfile, "keypad.onkeyint = %X\n",
calc->keypad.onkeyint);
fprintf(savfile, "\n## Memory mapping ##\n");
fprintf(savfile, "mempagemap0 = %X\n", calc->mempagemap[0]);
fprintf(savfile, "mempagemap1 = %X\n", calc->mempagemap[1]);
fprintf(savfile, "mempagemap2 = %X\n", calc->mempagemap[2]);
fprintf(savfile, "mempagemap3 = %X\n", calc->mempagemap[3]);
fprintf(savfile, "\n## Power ##\n");
fprintf(savfile, "poweronhalt = %X\n", calc->poweronhalt);
fprintf(savfile, "battery = %X\n", calc->battery);
if (calc->hw.flags & TILEM_CALC_HAS_FLASH) {
fprintf(savfile, "\n## Flash ##\n");
fprintf(savfile, "flash.unlock = %X\n",
calc->flash.unlock);
fprintf(savfile, "flash.state = %X\n",
calc->flash.state);
fprintf(savfile, "flash.busy = %X\n",
calc->flash.busy);
fprintf(savfile, "flash.progaddr = %X\n",
calc->flash.progaddr);
fprintf(savfile, "flash.progbyte = %X\n",
calc->flash.progbyte);
fprintf(savfile, "flash.toggles = %X\n",
calc->flash.toggles);
fprintf(savfile, "flash.overridegroup = %X\n",
calc->flash.overridegroup);
}
if (calc->hw.flags & TILEM_CALC_HAS_MD5_ASSIST) {
fprintf(savfile, "\n## MD5 assist ##\n");
fprintf(savfile, "md5assist.a = %X\n",
calc->md5assist.regs[0]);
fprintf(savfile, "md5assist.b = %X\n",
calc->md5assist.regs[1]);
fprintf(savfile, "md5assist.c = %X\n",
calc->md5assist.regs[2]);
fprintf(savfile, "md5assist.d = %X\n",
calc->md5assist.regs[3]);
fprintf(savfile, "md5assist.x = %X\n",
calc->md5assist.regs[4]);
fprintf(savfile, "md5assist.t = %X\n",
calc->md5assist.regs[5]);
fprintf(savfile, "md5assist.shift = %X\n",
calc->md5assist.shift);
fprintf(savfile, "md5assist.mode = %X\n",
calc->md5assist.mode);
}
for (j = 0; j < calc->hw.nusertimers; j++) {
fprintf(savfile,
"\n## Programmable timer %d ##\n", j);
fprintf(savfile, "usertimer%d.frequency = %X\n",
j, calc->usertimers[j].frequency);
fprintf(savfile, "usertimer%d.loopvalue = %X\n",
j, calc->usertimers[j].loopvalue);
fprintf(savfile, "usertimer%d.status = %X\n",
j, calc->usertimers[j].status);
}
fprintf(savfile, "\n## Model-specific ##\n");
for (j = 0; j < calc->hw.nhwregs; j++) {
fprintf(savfile, "%s = %X\n", calc->hw.hwregnames[j],
calc->hwregs[j]);
}
fprintf(savfile, "\n## Timers ##\n");
for (j = calc->z80.timer_cpu; j;
j = calc->z80.timers[j].next) {
tname = get_timer_name(calc, j);
if (tname) {
t = tilem_z80_get_timer_clocks(calc, j);
fprintf(savfile, "timer:%s = %X, %X, 0\n",
tname, t, calc->z80.timers[j].period);
}
}
for (j = calc->z80.timer_rt; j;
j = calc->z80.timers[j].next) {
tname = get_timer_name(calc, j);
if (tname) {
t = tilem_z80_get_timer_microseconds(calc, j);
fprintf(savfile, "timer:%s = %X, %X, 1\n",
tname, t, calc->z80.timers[j].period);
}
}
fprintf(savfile, "\n## RAM contents ##\n");
fprintf(savfile, "RAM = {\n");
for (i = 0; i < calc->hw.ramsize; i++) {
if (i % 256 == 0) {
fprintf(savfile, "# %02X:%04X\n",
(i >> 14), (i & 0x3fff));
}
fprintf(savfile, "%02X",
calc->mem[i + calc->hw.romsize]);
if (i % 32 == 31)
fprintf(savfile, "\n");
}
fprintf(savfile, "}\n## End of RAM contents ##\n");
if (calc->hw.lcdmemsize) {
fprintf(savfile, "\n## LCD contents ##\n");
fprintf(savfile, "LCD = {\n");
rowstride = calc->lcd.rowstride;
if (rowstride == 0)
rowstride = 32;
for (i = 0; i < calc->hw.lcdmemsize; i++) {
fprintf(savfile, "%02X", calc->lcdmem[i]);
if (i % rowstride == (rowstride - 1))
fprintf(savfile, "\n");
}
fprintf(savfile, "}\n## End of LCD contents ##\n");
}
}
return 0;
}