void ti68k_display_tib_infos(IMG_INFO *s) { tiemu_info(_("TIB information:")); tiemu_info(_(" Calculator : %s"), ti68k_calctype_to_string(s->calc_type)); tiemu_info(_(" Firmware : %s"), s->version); tiemu_info(_(" Memory type : %s"), ti68k_romtype_to_string(s->flash)); tiemu_info(_(" Memory size : %iMB (%i bytes)"), s->size >> 20, s->size); tiemu_info(_(" ROM base : %02x"), s->rom_base & 0xff); }
/* Read hardware parameter block from image. */ int ti68k_get_hw_param_block(uint8_t *rom_data, uint8_t rom_base, HW_PARM_BLOCK *s) { int i = 0; uint32_t addr; addr = rd_long(&rom_data[0x104]); addr &= 0x000fffff; memset(s, 0, sizeof(HW_PARM_BLOCK)); s->len = rd_word(&(rom_data[addr+0])); if(s->len > 2+(4*i++)) s->hardwareID = rd_long(&(rom_data[addr+2])); if(s->len > 2+(4*i++)) s->hardwareRevision = rd_long(&(rom_data[addr+6])); if(s->len > 2+(4*i++)) s->bootMajor = rd_long(&(rom_data[addr+10])); if(s->len > 2+(4*i++)) s->bootRevision = rd_long(&(rom_data[addr+14])); if(s->len > 2+(4*i++)) s->bootBuild = rd_long(&(rom_data[addr+18])); if(s->len > 2+(4*i++)) s->gateArray = rd_long(&(rom_data[addr+22])); if(s->len > 2+(4*i++)) s->physDisplayBitsWide = rd_long(&(rom_data[addr+26])); if(s->len > 2+(4*i++)) s->physDisplayBitsTall = rd_long(&(rom_data[addr+30])); if(s->len > 2+(4*i++)) s->LCDBitsWide = rd_long(&(rom_data[addr+34])); if(s->len > 2+(4*i++)) s->LCDBitsTall = rd_long(&(rom_data[addr+38])); if((s->hardwareID == HWID_V200) && (rom_base == 0x40)) { tiemu_info(_("Detected V200 patched ROM (ExtendeD): emulated as TI92+ by changing the hwID from 8 to 1.")); s->hardwareID = HWID_TI92P; } if((s->hardwareID == HWID_TI89T) && (rom_base == 0x20)) { tiemu_info(_("Detected TI89 Titanium patched ROM (ExtendeD): emulated as TI89 by changing the hwID from 9 to 3.")); s->hardwareID = HWID_TI89; } return 0; }
void ti68k_display_img_infos(IMG_INFO *s) { tiemu_info(_("Image information:")); tiemu_info(_(" Calculator : %s"), ti68k_calctype_to_string(s->calc_type)); tiemu_info(_(" Firmware : %s"), s->version); tiemu_info(_(" Memory type : %s"), ti68k_romtype_to_string(s->flash)); tiemu_info(_(" Memory size : %iMB (%i bytes)"), s->size >> 20, s->size); tiemu_info(_(" ROM base : %02x"), s->rom_base & 0xff); tiemu_info(_(" Hardware : %i"), s->hw_type); tiemu_info(_(" Has boot : %s"), s->has_boot ? _("yes") : _("no")); }
/* Load a FLASH upgrade (.tib/.9xu/.89u). Note: an image must have been loaded before calling this function. */ int ti68k_load_upgrade(const char *filename) { IMG_INFO tib; int err; IMG_INFO *img = &img_infos; if(!img_loaded) return -1; // No filename, exits if(!strcmp(g_basename(filename), "")) return 0; //ERR_CANT_OPEN; memset(&tib, 0, sizeof(IMG_INFO)); err = ti68k_get_tib_infos(filename, &tib, !0); if(err) { free(img->data); tiemu_info(_("Unable to get information on FLASH upgrade: <%s>"), filename); return err; } ti68k_display_tib_infos(&tib); // Allow upgrade ? if(tib.calc_type != img->calc_type) { free(tib.data); return ERR_CANT_UPGRADE; } tib.has_boot = 1; // still bootable memset(tihw.rom+SPP, 0xff, tihw.rom_size-SPP); // clear FLASH memcpy(tihw.rom+SPP, tib.data+SPP, tib.size-SPP); free(tib.data); strcpy(tihw.rom_version, tib.version); img_loaded = 2; img_changed = 2; return 0; }
void ti68k_display_hw_param_block(HW_PARM_BLOCK *s) { int i = 0; tiemu_info(_("Hardware Parameters Block:")); tiemu_info(_(" length : %i"), s->len); if(s->len > 2+(4*i++)) tiemu_info(" hardwareID : %i", s->hardwareID); if(s->len > 2+(4*i++)) tiemu_info(" hardwareRevision : %i", s->hardwareRevision); if(s->len > 2+(4*i++)) tiemu_info(" bootMajor : %i", s->bootMajor); if(s->len > 2+(4*i++)) tiemu_info(" bootRevision : %i", s->bootRevision); if(s->len > 2+(4*i++)) tiemu_info(" bootBuild : %i", s->bootBuild); if(s->len > 2+(4*i++)) tiemu_info(" gateArray : %i", s->gateArray); if(s->len > 2+(4*i++)) tiemu_info(" physDisplayBitsWide : %i", s->physDisplayBitsWide & 0xff); if(s->len > 2+(4*i++)) tiemu_info(" physDisplayBitsTall : %i", s->physDisplayBitsTall & 0xff); if(s->len > 2+(4*i++)) tiemu_info(" LCDBitsWide : %i", s->LCDBitsWide & 0xff); if(s->len > 2+(4*i++)) tiemu_info(" LCDBitsTall : %i", s->LCDBitsTall & 0xff); }
/* Read the RC file and configure the corresponding variables */ void rcfile_read(void) { FILE *txt; char buffer[256]; char *p; int l=0; rcfile_get_path(&rc_file); txt=fopen(rc_file, "rt"); g_free(rc_file); if(txt == NULL) { tiemu_info(_("Configuration file not found, use default values. You can create one by the 'File|Save config' command menu.")); return; } while(!feof(txt)) { if (!fgets(buffer, 256, txt)) break; l++; buffer[strlen(buffer)-1]='\0'; if(!strcmp(buffer, "RC_END")) { fclose(txt); return; } if(buffer[0]=='#' || !strlen(buffer)) continue; /* Common part with TiLP: hardware section */ if ((p = find_str(buffer, "cable_model="))) { linkp.cable_model = ticables_string_to_model(p); continue; } if ((p = find_str(buffer, "cable_port="))) { linkp.cable_port = ticables_string_to_port(p); continue; } if ((p = find_str(buffer, "cable_timeout="))) { sscanf(p, "%i", &(linkp.cable_timeout)); continue; } if ((p = find_str(buffer, "cable_delay="))) { sscanf(p, "%i", &(linkp.cable_delay)); continue; } if( (p=find_str(buffer, "qs_file=")) ) { g_free(options.qs_file); options.qs_file = g_strdup(p); continue; } if( (p=find_str(buffer, "qs_enabled=")) ) { sscanf(p, "%i", &(options.qs_enabled)); continue; } /* GtkTiEmu specific part: emulator section */ if( (p=find_str(buffer, "rom_file=")) ) { g_free(params.rom_file); params.rom_file = g_strdup(p); continue; } if( (p=find_str(buffer, "img_file=")) ) { g_free(params.rom_file); params.rom_file = g_strdup(p); continue; } if( (p=find_str(buffer, "tib_file=")) ) { g_free(params.tib_file); params.tib_file = g_strdup(p); continue; } if( (p=find_str(buffer, "sav_file=")) ) { g_free(params.sav_file); params.sav_file = g_strdup(p); continue; } if( (p=find_str(buffer, "skin=")) ) { sscanf(p, "%i", &(options.skin)); continue; } if( (p=find_str(buffer, "view_mode=")) ) { if(!strcmp(p, "normal")) options.view = VIEW_NORMAL; else if(!strcmp(p, "large")) options.view = VIEW_LARGE; else if(!strcmp(p, "full")) options.view = VIEW_FULL; else if(!strncmp(p, "custom", strlen("custom"))) { //char *q; options.view = VIEW_CUSTOM; p=find_str(buffer, "view_mode=custom"); /*q = strchr(p, ','); if(q) *q = '.';*/ sscanf(p, " (%f)", &(options.scale)); if(options.scale < 0.01) options.scale = 1.0; } else stop(l); continue; } if( (p=find_str(buffer, "cpu_rate=")) ) { sscanf(p, "%u", &(params.cpu_rate)); continue; } if( (p=find_str(buffer, "hw_rate=")) ) { sscanf(p, "%u", &(params.hw_rate)); continue; } if( (p=find_str(buffer, "lcd_rate=")) ) { sscanf(p, "%i", &(params.lcd_rate)); continue; } if( (p=find_str(buffer, "hw_protect=")) ) { sscanf(p, "%i", &(params.hw_protect)); continue; } if( (p=find_str(buffer, "img_format=")) ) { if(!strcmp(p, "jpg")) options2.format=IMG_JPG; else if(!strcmp(p, "png")) options2.format=IMG_PNG; else if(!strcmp(p, "ico")) options2.format=IMG_ICO; else if(!strcmp(p, "eps")) options2.format=IMG_EPS; else if(!strcmp(p, "pdf")) options2.format=IMG_PDF; else if(!strcmp(p, "bmp")) options2.format=IMG_BMP; else stop(l); continue; } if( (p=find_str(buffer, "img_type=")) ) { if(!strcmp(p, "bw")) options2.type = IMG_BW; else if(!strcmp(p, "color")) options2.type = IMG_COL; else stop(l); continue; } if( (p=find_str(buffer, "img_size=")) ) { if(!strcmp(p, "lcd")) options2.size = IMG_LCD; else if(!strcmp(p, "skin")) options2.size = IMG_SKIN; else stop(l); continue; } if( (p=find_str(buffer, "screen_folder=")) ) { g_free(options2.folder); options2.folder = g_strdup(p); continue; } if( (p=find_str(buffer, "screen_file=")) ) { g_free(options2.file); options2.file = g_strdup(p); continue; } if( (p=find_str(buffer, "screen_counter=")) ) { sscanf(p, "%i", &(options2.counter)); continue; } if( (p=find_str(buffer, "screen_shots=")) ) { sscanf(p, "%i", &(options2.shots)); continue; } if( (p=find_str(buffer, "screen_skips=")) ) { sscanf(p, "%i", &(options2.skips)); continue; } if( (p=find_str(buffer, "clipboard=")) ) { if(!strcmp(p, "no")) options2.clipboard = 0; else if(!strcmp(p, "yes")) options2.clipboard = 1; continue; } if( (p=find_str(buffer, "console=")) ) { if(!strcmp(p, "no")) options.console = 0; else if(!strcmp(p, "yes")) options.console = 1; else if(!strcmp(p, "boot")) options.console = 2; else stop(l); continue; } if( (p=find_str(buffer, "kbd_dbg=")) ) { if(!strcmp(p, "no")) options.kbd_dbg = 0; else if(!strcmp(p, "yes")) options.kbd_dbg = 1; } if( (p=find_str(buffer, "fs_type=")) ) { if(!strcmp(p, "old")) options.fs_type = 0; else if(!strcmp(p, "new")) options.fs_type = 1; else if(!strcmp(p, "native") || !strcmp(p, "win32")) options.fs_type = 2; else if(!strcmp(p, "kde")) options.fs_type = 3; } if( (p=find_str(buffer, "skin_file=")) ) { g_free(options.skin_file); options.skin_file = g_strdup(p); continue; } if( (p=find_str(buffer, "keys_file=")) ) { g_free(options.keys_file); options.keys_file = g_strdup(p); continue; } if( (p=find_str(buffer, "calc_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.calc.rect.x), &(options3.calc.rect.y), &(options3.calc.rect.w), &(options3.calc.rect.h), &(options3.calc.minimized), &(options3.calc.closed) ); continue; } if( (p=find_str(buffer, "bkpts_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.bkpts.rect.x), &(options3.bkpts.rect.y), &(options3.bkpts.rect.w), &(options3.bkpts.rect.h), &(options3.bkpts.minimized), &(options3.bkpts.closed) ); continue; } if( (p=find_str(buffer, "code_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.code.rect.x), &(options3.code.rect.y), &(options3.code.rect.w), &(options3.code.rect.h), &(options3.code.minimized), &(options3.code.closed)); continue; } if( (p=find_str(buffer, "mem_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.mem.rect.x), &(options3.mem.rect.y), &(options3.mem.rect.w), &(options3.mem.rect.h), &(options3.mem.minimized), &(options3.mem.closed)); continue; } if( (p=find_str(buffer, "regs_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.regs.rect.x), &(options3.regs.rect.y), &(options3.regs.rect.w), &(options3.regs.rect.h), &(options3.regs.minimized), &(options3.regs.closed)); continue; } if( (p=find_str(buffer, "pclog_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.pclog.rect.x), &(options3.pclog.rect.y), &(options3.pclog.rect.w), &(options3.pclog.rect.h), &(options3.pclog.minimized), &(options3.pclog.closed)); continue; } if( (p=find_str(buffer, "stack_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.stack.rect.x), &(options3.stack.rect.y), &(options3.stack.rect.w), &(options3.stack.rect.h), &(options3.stack.minimized), &(options3.stack.closed)); continue; } if( (p=find_str(buffer, "heap_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.heap.rect.x), &(options3.heap.rect.y), &(options3.heap.rect.w), &(options3.heap.rect.h), &(options3.heap.minimized), &(options3.heap.closed)); continue; } if( (p=find_str(buffer, "iop_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.iop.rect.x), &(options3.iop.rect.y), &(options3.iop.rect.w), &(options3.iop.rect.h), &(options3.iop.minimized), &(options3.iop.closed)); continue; } if( (p=find_str(buffer, "dock_wnd=")) ) { sscanf(p, "(%i;%i;%i;%i;%i;%i)", &(options3.dock.rect.x), &(options3.dock.rect.y), &(options3.dock.rect.w), &(options3.dock.rect.h), &(options3.dock.minimized), &(options3.dock.closed)); continue; } if( (p=find_str(buffer, "wnd_transient=")) ) { if(!strcmp(p, "no")) options3.transient = 0; else if(!strcmp(p, "yes")) options3.transient = 1; else stop(l); continue; } if( (p=find_str(buffer, "dbg_font_type=")) ) { if(!strcmp(p, "default")) options3.dbg_font_type = 0; else if(!strcmp(p, "custom")) options3.dbg_font_type = 1; else stop(l); continue; } if( (p=find_str(buffer, "dbg_font_name=")) ) { g_free(options3.dbg_font_name); options3.dbg_font_name = g_strdup(p); continue; } if( (p=find_str(buffer, "dbg_dock=")) ) { if(!strcmp(p, "no")) options3.dbg_dock = 0; else if(!strcmp(p, "yes")) options3.dbg_dock = 1; else stop(l); continue; } } fclose(txt); return; }
/* Scan images in a given directory and write list into img_list.txt. */ int ti68k_scan_images(const char *dirname, const char *filename) { FILE *file; IMG_INFO img; GDir *dir; GError *error = NULL; G_CONST_RETURN gchar *dirent; gchar *path, *str; int ret; struct stat f_info; char *line[7]; tiemu_info(_("Scanning images/upgrades... ")); // Create file (and overwrite) file = fopen(filename, "wt"); if(file == NULL) { tiemu_warning(_("Unable to open this file: <%s>"), filename); return ERR_CANT_OPEN; } // List all files available in the directory dir = g_dir_open(dirname, 0, &error); if (dir == NULL) { tiemu_warning(_("Opendir error")); return ERR_CANT_OPEN_DIR; } while ((dirent = g_dir_read_name(dir)) != NULL) { if (dirent[0] == '.') continue; path = g_strconcat(dirname, dirent, NULL); ret = stat(path, &f_info); if(ret == -1) { tiemu_warning(_("Can not stat: <%s>"), dirent); perror("stat: "); } else { if(ti68k_is_a_img_file(path)) { memset(&img, 0, sizeof(IMG_INFO)); ret = ti68k_get_img_infos(path, &img); if(ret) { tiemu_warning(_("Can not get ROM/update info: <%s>"), path); break; } } else continue; str = g_strdup_printf("%iKB", (int)(img.size >> 10)); line[0] = (char *)dirent; line[1] = (char *)ti68k_calctype_to_string(img.calc_type); line[2] = img.version; line[3] = (char *)ti68k_romtype_to_string(img.flash); line[4] = str; line[5] = img.has_boot ? _("yes") : _("no"); line[6] = (char *)ti68k_hwtype_to_string(img.hw_type); fprintf(file, "%s,%s,%s,%s,%s,%s,%s\n", line[0], line[1], line[2], line[3], line[4], line[5], line[6]); g_free(str); } g_free(path); } // Close g_dir_close(dir); fclose(file); tiemu_info(_("Done.")); return 0; }
/* This function loads an image. */ int ti68k_load_image(const char *filename) { IMG_INFO *img = &img_infos; FILE *f; int err; // Clear infos memset(img, 0, sizeof(IMG_INFO)); // No filename, exits if(!strcmp(g_basename(filename), "")) return ERR_CANT_OPEN; // Load infos err = ti68k_get_img_infos(filename, img); if(err) { tiemu_info(_("Unable to get information on image: %s"), filename); return err; } ti68k_display_img_infos(img); // Open file f = fopen(filename, "rb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", filename); return ERR_CANT_OPEN; } // Read pure data if (fseek(f, img->header_size, SEEK_SET)) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } img->data = malloc(img->size + 4); if(img->data == NULL) return ERR_MALLOC; if (fread(img->data, 1, img->size, f) < (size_t)img->size) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } #if 1 { HW_PARM_BLOCK hwblock; ti68k_get_hw_param_block((uint8_t *)img->data, img->rom_base, &hwblock); ti68k_display_hw_param_block(&hwblock); } #endif if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", filename); return ERR_CANT_OPEN; } img_loaded = 1; img_changed = 1; return 0; }
/* Convert an romdump into image and replace SPP by upgrade. The resulting image has boot block. */ int ti68k_merge_rom_and_tib_to_image(const char *srcname1, const char *srcname2, const char *dirname, char **dstname) { FILE *f; int err; IMG_INFO img; char *ext; gchar *basename; int real_size; *dstname = NULL; // No filename, exits if(!strcmp(g_basename(srcname1), "")) return ERR_CANT_OPEN; if(!strcmp(g_basename(srcname2), "")) return ERR_CANT_OPEN; // Preload romdump memset(&img, 0, sizeof(IMG_INFO)); err = ti68k_get_rom_infos(srcname1, &img, !0); if(err) { free(img.data); tiemu_info(_("Unable to get information on ROM dump: %s"), srcname1); return err; } ti68k_display_rom_infos(&img); // Save size real_size = img.size; // Load upgrade err = ti68k_get_tib_infos(srcname2, &img, !0); if(err) { free(img.data); tiemu_info(_("Unable to get information on ROM dump: %s"), srcname2); return err; } ti68k_display_tib_infos(&img); // Create destination file basename = g_path_get_basename(srcname1); ext = strrchr(basename, '.'); *ext='\0'; strcat(basename, ".img"); *dstname = g_strconcat(dirname, basename, NULL); g_free(basename); // Restore size img.size = real_size; // Open dest file f = fopen(*dstname, "wb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", *dstname); return ERR_CANT_OPEN; } // Fill header strcpy(img.signature, IMG_SIGN); img.header_size = sizeof(IMG_INFO); img.revision = IMG_REV; img.has_boot = 1; // Write file if (fwrite(&img, 1, sizeof(IMG_INFO), f) < sizeof(IMG_INFO) || fwrite(img.data, sizeof(char), img.size, f) < (size_t)img.size) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", *dstname); return ERR_CANT_OPEN; } return 0; }
/* Convert an upgrade into an image. The image has neither boot block nor certificate. */ int ti68k_convert_tib_to_image(const char *srcname, const char *dirname, char **dstname, int hw_type) { FILE *f; int err; IMG_INFO img; char *ext; gchar *basename; int i, j; int num_blocks, last_block; int real_size; HW_PARM_BLOCK hwpb; *dstname = NULL; // No filename, exits if(!strcmp(g_basename(srcname), "")) return ERR_CANT_OPEN; // Preload upgrade memset(&img, 0, sizeof(IMG_INFO)); err = ti68k_get_tib_infos(srcname, &img, !0); if(err) { free(img.data); tiemu_info(_("Unable to get information on FLASH upgrade: <%s>"), srcname); return err; } ti68k_display_tib_infos(&img); // Create destination file basename = g_path_get_basename(srcname); ext = strrchr(basename, '.'); *ext='\0'; strcat(basename, ".img"); *dstname = g_strconcat(dirname, basename, NULL); g_free(basename); // Open dest file f = fopen(*dstname, "wb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", *dstname); return ERR_CANT_OPEN; } // Fill header strcpy(img.signature, IMG_SIGN); img.header_size = sizeof(IMG_INFO); img.revision = IMG_REV; real_size = img.size - SPP; img.size = ti68k_get_rom_size(img.calc_type); img.hw_type = hw_type; if(hw_type == -1) { if(img.calc_type == TI89t) img.hw_type = HW3; //default else if(img.calc_type == TI89 || img.calc_type == TI92p || img.calc_type == V200) img.hw_type = HW2; // default } // Write header if (fwrite(&img, 1, sizeof(IMG_INFO), f) < sizeof(IMG_INFO)) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Write boot block memcpy(img.data, &img.data[SPP + BO], 256); if (fwrite(img.data, 1, 256, f) < 256) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Write hardware param block // fill structure hwpb.len = 24; switch(img.calc_type) { case TI89: hwpb.hardwareID = HWID_TI89; hwpb.hardwareRevision = img.hw_type - 1; break; case TI92p: hwpb.hardwareID = HWID_TI92P; hwpb.hardwareRevision = img.hw_type - 1; break; case V200: hwpb.hardwareID = HWID_V200; hwpb.hardwareRevision = 2; break; case TI89t: hwpb.hardwareID = HWID_TI89T; hwpb.hardwareRevision = 2; break; } hwpb.bootMajor = hwpb.bootRevision = hwpb.bootBuild = 1; hwpb.gateArray = img.hw_type; ti68k_put_hw_param_block((uint8_t *)img.data, img.rom_base, &hwpb); // write filler if (fputc(0xfe, f) < 0 || fputc(0xed, f) < 0 || fputc(0xba, f) < 0 || fputc(0xbe, f) < 0 //fwrite(&hwpb, 1hwpb.len+2, f); // write address (pointer) || fputc(0x00, f) < 0 || fputc(img.rom_base, f) < 0 || fputc(0x01, f) < 0 || fputc(0x08, f) < 0 // write structure || fputc(MSB(hwpb.len), f) < 0 || fputc(LSB(hwpb.len), f) < 0 || fputc(MSB(MSW(hwpb.hardwareID)), f) < 0 || fputc(LSB(MSW(hwpb.hardwareID)), f) < 0 || fputc(MSB(LSW(hwpb.hardwareID)), f) < 0 || fputc(LSB(LSW(hwpb.hardwareID)), f) < 0 || fputc(MSB(MSW(hwpb.hardwareRevision)), f) < 0 || fputc(LSB(MSW(hwpb.hardwareRevision)), f) < 0 || fputc(MSB(LSW(hwpb.hardwareRevision)), f) < 0 || fputc(LSB(LSW(hwpb.hardwareRevision)), f) < 0 || fputc(MSB(MSW(hwpb.bootMajor)), f) < 0 || fputc(LSB(MSW(hwpb.bootMajor)), f) < 0 || fputc(MSB(LSW(hwpb.bootMajor)), f) < 0 || fputc(LSB(LSW(hwpb.bootMajor)), f) < 0 || fputc(MSB(MSW(hwpb.hardwareRevision)), f) < 0 || fputc(LSB(MSW(hwpb.hardwareRevision)), f) < 0 || fputc(MSB(LSW(hwpb.hardwareRevision)), f) < 0 || fputc(LSB(LSW(hwpb.hardwareRevision)), f) < 0 || fputc(MSB(MSW(hwpb.bootBuild)), f) < 0 || fputc(LSB(MSW(hwpb.bootBuild)), f) < 0 || fputc(MSB(LSW(hwpb.bootBuild)), f) < 0 || fputc(LSB(LSW(hwpb.bootBuild)), f) < 0 || fputc(MSB(MSW(hwpb.gateArray)), f) < 0 || fputc(LSB(MSW(hwpb.gateArray)), f) < 0 || fputc(MSB(LSW(hwpb.gateArray)), f) < 0 || fputc(LSB(LSW(hwpb.gateArray)), f) < 0) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Fill with 0xff up-to System Part for(i = 0x108 + hwpb.len+2; i < SPP; i++) if (fputc(0xff, f) < 0) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Copy FLASH upgrade at 0x12000 (SPP) num_blocks = real_size / 65536; for(i = 0; i < num_blocks; i++ ) { tiemu_info("."); fflush(stdout); if (fwrite(&img.data[65536 * i + SPP], sizeof(char), 65536, f) < 65536) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } } last_block = real_size % 65536; if (fwrite(&img.data[65536 * i + SPP], sizeof(char), last_block, f) < (size_t)last_block) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } tiemu_info(""); tiemu_info("Completing to %iMB size\n", img.size >> 20); for(j = SPP + real_size; j < img.size; j++) if (fputc(0xff, f) < 0) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", *dstname); return ERR_CANT_OPEN; } return 0; }
/* Convert a romdump into an image. This kind of image is complete (boot & certificate). */ int ti68k_convert_rom_to_image(const char *srcname, const char *dirname, char **dstname) { FILE *f; int err; IMG_INFO img; char *ext; gchar *basename; *dstname = NULL; // No filename, exits if(!strcmp(g_basename(srcname), "")) return ERR_CANT_OPEN; // Preload romdump memset(&img, 0, sizeof(IMG_INFO)); err = ti68k_get_rom_infos(srcname, &img, !0); if(err) { free(img.data); tiemu_info(_("Unable to get information on ROM dump: %s"), srcname); return err; } ti68k_display_rom_infos(&img); // Create destination file basename = g_path_get_basename(srcname); ext = strrchr(basename, '.'); *ext='\0'; strcat(basename, ".img"); *dstname = g_strconcat(dirname, basename, NULL); g_free(basename); // Open dest file f = fopen(*dstname, "wb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", *dstname); return ERR_CANT_OPEN; } // Some V200 and TI89 Titanium ROMs are half the size if((img.size < 4*MB) && (img.calc_type == V200 || img.calc_type == TI89t)) { img.size = 4*MB; img.data = realloc(img.data, 4*MB + 4); tiemu_info(_("Completing image to 4 MB!")); memset(img.data + 2*MB, 0xff, 2*MB); } // Fill header strcpy(img.signature, IMG_SIGN); img.header_size = sizeof(IMG_INFO); img.revision = IMG_REV; // Write file if (fwrite(&img, 1, sizeof(IMG_INFO), f) < (size_t)sizeof(IMG_INFO) || fwrite(img.data, sizeof(char), img.size, f) < (size_t)img.size) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", *dstname); return ERR_CANT_OPEN; } return 0; }
/* Get some information on the FLASH upgrade: - size - ROM base address - os version - calc type */ int ti68k_get_tib_infos(const char *filename, IMG_INFO *tib, int preload) { FlashContent *content; FlashContent *ptr; int nheaders = 0; int i; // No filename, exits if(!strcmp(g_basename(filename), "")) return ERR_CANT_OPEN; // Check valid file if(!tifiles_file_is_ti(filename)) return ERR_NOT_TI_FILE; if(!tifiles_file_is_os(filename)) return ERR_INVALID_UPGRADE; // Load file content = tifiles_content_create_flash(CALC_TI89); if(tifiles_file_read_flash(filename, content) != 0) return ERR_INVALID_UPGRADE; // count headers for (ptr = content; ptr != NULL; ptr = ptr->next) nheaders++; // keep the last one (data) for (i = 0, ptr = content; i < nheaders - 1; i++) ptr = ptr->next; // Load TIB into memory and relocate at SPP if(tib->data == NULL) tib->data = malloc(SPP + ptr->data_length + 4); if(tib->data == NULL) return ERR_MALLOC; memset(tib->data + SPP, 0xff, ptr->data_length); memcpy(tib->data + SPP, ptr->data_part, ptr->data_length); // Update current rom infos tib->rom_base = tib->data[BO+5 + SPP] & 0xf0; // libtifiles can't distinguish TI89/TI89t and 92+/V200. We need to look. switch(ptr->device_type & 0xff) { case DEVICE_TYPE_89: // can be a Titanium, too switch(tib->rom_base & 0xff) { case 0x20: tib->calc_type = TI89; break; case 0x80: tib->calc_type = TI89t; break; default: return ERR_INVALID_UPGRADE; } break; case DEVICE_TYPE_92P: switch(tib->rom_base & 0xff) { case 0x20: tib->calc_type = V200; break; case 0x40: tib->calc_type = TI92p; break; default: return ERR_INVALID_UPGRADE; } break; default: tiemu_info("TIB problem: %02x!\n", 0xff & ptr->device_type); return ERR_INVALID_UPGRADE; break; } tib->flash = FLASH_ROM; tib->has_boot = 0; tib->size = ptr->data_length + SPP; get_rom_version(tib->data, tib->size, tib->version); tifiles_content_delete_flash(content); if(!preload) free(tib->data); return 0; }
/* Get some information on the ROM dump: - size - ROM base address - FLASH/EPROM - os version - calc type Note: if the data field is NULL, memory is allocated. Otherwise, data is overwritten. Thanks to Kevin for HW2 detection code. */ int ti68k_get_rom_infos(const char *filename, IMG_INFO *rom, int preload) { FILE *file; HW_PARM_BLOCK hwblock; // No filename, exits if(!strcmp(g_basename(filename), "")) return ERR_CANT_OPEN; // Open file file = fopen(filename, "rb"); if(file == NULL) { tiemu_info(_("Unable to open this file: <%s>"), filename); return ERR_CANT_OPEN; } // Retrieve ROM size fseek(file, 0, SEEK_END); rom->size = ftell(file); fseek(file, 0, SEEK_SET); if(rom->size < 256) return ERR_INVALID_ROM_SIZE; if (rom->size == 8*MB) { // TiLP used to dump 8 MB images for HW4, try to load them anyway. tiemu_info(_("Warning: truncating 8 MB image to 4 MB: <%s>"), filename); rom->size = 4*MB; } if (rom->size > 4*MB) return ERR_INVALID_ROM_SIZE; if(rom->data == NULL) rom->data = malloc(rom->size + 4); if(rom->data == NULL) return ERR_MALLOC; memset(rom->data, 0xff, rom->size); if (fread(rom->data, 1, rom->size, file) < (size_t)rom->size) { tiemu_info(_("Failed to read from file: <%s>"), filename); fclose(file); return ERR_CANT_OPEN; } if (fclose(file)) { tiemu_info(_("Failed to close file: <%s>"), filename); return ERR_CANT_OPEN; } rom->has_boot = 1; rom->rom_base = rom->data[0x05] & 0xf0; rom->flash = (rom->data[0x65] & 0x0f) ? 0 : FLASH_ROM; get_rom_version(rom->data, rom->size, rom->version); if(!rom->flash) { rom->calc_type = TI92; rom->hw_type = HW1; } else { // Get hw param block to determine calc type & hw type if(ti68k_get_hw_param_block((uint8_t*)rom->data, rom->rom_base, &hwblock) == -1) return ERR_INVALID_ROM; ti68k_display_hw_param_block(&hwblock); switch(hwblock.hardwareID) { case HWID_TI92P: rom->calc_type = TI92p; break; case HWID_TI89: rom->calc_type = TI89; break; case HWID_V200: rom->calc_type = V200; break; case HWID_TI89T: rom->calc_type = TI89t; break; default: break; } if(rom->flash) { if(hwblock.len < 24) rom->hw_type = HW1; else rom->hw_type = (char)hwblock.gateArray; } } if(!preload) free(rom->data); return 0; }
/* This function saves the state of the calculator. Can be called at any time. Return an error code if an error occured, 0 otherwise */ int ti68k_state_save(const char *filename) { FILE *f; IMG_INFO *img = &img_infos; SAV_INFO sav; int i; long len; long bkpts_size; if(!strlen(filename)) return ERR_CANT_OPEN_STATE; // Open file tiemu_info(_("saving state image (TiEmu v2.00 format): %s"), filename); f = fopen(filename, "wb"); if(f == NULL) return ERR_CANT_OPEN_STATE; // Save current image infos fwrite(img, 1, sizeof(IMG_INFO), f); // Fill state image infos sav.revision = SAV_REVISION; sav.size = sizeof(SAV_INFO); sav.regs_offset = sizeof(IMG_INFO) + sizeof(SAV_INFO); sav.io_offset = sav.regs_offset + sizeof(regs); sav.ram_offset = sav.io_offset + tihw.io_size + tihw.io2_size + tihw.io3_size; sav.misc_offset = sav.ram_offset + tihw.ram_size; sav.rom_offset = sav.misc_offset + sizeof(Ti68kHardware); sav.bkpts_offset = sav.rom_offset + wsm.nblocks*sizeof(int) + hw_flash_nblocks()*65536; bkpts_size = g_list_length(bkpts.code) * sizeof(long) + sizeof(long) + g_list_length(bkpts.exception) * sizeof(long) + sizeof(long) + g_list_length(bkpts.pgmentry) * sizeof(long) + sizeof(long) + g_list_length(bkpts.mem_rb) * sizeof(long) + sizeof(long) + g_list_length(bkpts.mem_rw) * sizeof(long) + sizeof(long) + g_list_length(bkpts.mem_rl) * sizeof(long) + sizeof(long) + g_list_length(bkpts.mem_wb) * sizeof(long) + sizeof(long) + g_list_length(bkpts.mem_ww) * sizeof(long) + sizeof(long) + g_list_length(bkpts.mem_wl) * sizeof(long) + sizeof(long) + g_list_length(bkpts.mem_rng_r) * sizeof(ADDR_RANGE) + sizeof(long) + g_list_length(bkpts.mem_rng_w) * sizeof(ADDR_RANGE) + sizeof(long) + g_list_length(bkpts.bits) * sizeof(ADDR_BIT) + sizeof(long) ; sav.str_offset = sav.bkpts_offset + bkpts_size; fwrite(&sav, 1, sizeof(SAV_INFO), f); // Update UAE structures MakeSR(); m68k_setpc(m68k_getpc()); // Save registers and special flags fwrite(®s, sizeof(regs), 1, f); // Save I/O ports state fwrite(tihw.io , tihw.io_size, 1, f); fwrite(tihw.io2, tihw.io2_size, 1, f); fwrite(tihw.io3, tihw.io3_size, 1, f); // Save RAM content fwrite(tihw.ram, tihw.ram_size, 1, f); // Save misc informations rtc3_state_save(); fwrite(&tihw, sizeof(Ti68kHardware), 1, f); // Save modified FLASH segments for(i=0; i<wsm.nblocks; i++) { fwrite(&wsm.changed[i], sizeof(int), 1, f); if(wsm.changed[i]) fwrite(&tihw.rom[i<<16], 1, 65536, f); } // Save breakpoints save_bkpt(f, bkpts.code); save_bkpt(f, bkpts.exception); save_bkpt(f, bkpts.pgmentry); save_bkpt(f, bkpts.mem_rb); save_bkpt(f, bkpts.mem_rw); save_bkpt(f, bkpts.mem_rl); save_bkpt(f, bkpts.mem_wb); save_bkpt(f, bkpts.mem_ww); save_bkpt(f, bkpts.mem_wl); save_bkpt2(f, bkpts.mem_rng_r); save_bkpt2(f, bkpts.mem_rng_w); save_bkpt3(f, bkpts.bits); // Save image location associated with this state image len = strlen(params.rom_file) + 1; fwrite(&len, 1, sizeof(len), f); fwrite(params.rom_file, len, 1, f); len = strlen(params.tib_file) + 1; fwrite(&len, 1, sizeof(len), f); fwrite(params.tib_file, len, 1, f); fclose(f); return 0; }
/* Must be done between init_hardware and M68000_run. Typically called after initLib68k. This function (re)load the state of the calculator. It automagically determine the state file format. Return an error code if an error occured, 0 otherwise */ int ti68k_state_load(const char *filename) { FILE *f; IMG_INFO img; SAV_INFO sav; Ti68kHardware thw; int ret; long pos; int i; gchar *rf=NULL, *tf=NULL; // No filename, exits if(!strcmp(filename, "")) return 0; // Open file tiemu_info(_("loading state image: %s"), g_basename(filename)); f = fopen(filename, "rb"); if(f == NULL) return ERR_CANT_OPEN_STATE; // Load ROM image header fread(&img, 1, sizeof(IMG_INFO), f); // Determine state image revision and load state image header pos = ftell(f); fread(&sav.revision, sizeof(sav.revision), 1, f); fread(&sav.size, sizeof(sav.revision), 1, f); fseek(f, pos, SEEK_SET); fread(&sav, 1, sav.size, f); if(sav.revision < SAV_MINI) { fclose(f); return ERR_REVISION_MATCH; } // Does not accept state image different of emulator image if(ti68k_state_parse(filename, &rf, &tf) < 0) { if (rf) g_free(rf); if (tf) g_free(tf); return ERR_STATE_MATCH; } if (rf) g_free(rf); if (tf) g_free(tf); // Compare image infos with current image if(memcmp(&img, &img_infos, sizeof(IMG_INFO) - sizeof(char *))) return ERR_HEADER_MATCH; // Load internal hardware (registers and special flags) ret = fseek(f, sav.regs_offset, SEEK_SET); fread(®s, sizeof(regs), 1, f); // Load I/O ports state ret = fseek(f, sav.io_offset, SEEK_SET); fread(tihw.io , tihw.io_size, 1, f); fread(tihw.io2, tihw.io2_size, 1, f); fread(tihw.io3, tihw.io3_size, 1, f); // Load RAM content ret = fseek(f, sav.ram_offset, SEEK_SET); fread(tihw.ram, tihw.ram_size, 1, f); // Load extra infos ret = fseek(f, sav.misc_offset, SEEK_SET); fread(&thw, sizeof(Ti68kHardware), 1, f); tihw.on_off = thw.on_off; tihw.lcd_adr = thw.lcd_adr; tihw.contrast = thw.contrast; tihw.protect = thw.protect; tihw.archive_limit = thw.archive_limit; memcpy(tihw.ram_exec, thw.ram_exec, sizeof(tihw.ram_exec)); tihw.rtc3_beg = thw.rtc3_beg; tihw.rtc3_load = thw.rtc3_load; rtc3_state_load(); // Load modified FLASH segments ret = fseek(f, sav.rom_offset, SEEK_SET); for(i=0; i<wsm.nblocks; i++) { fread(&wsm.changed[i], sizeof(int), 1, f); if(wsm.changed[i]) fread(&tihw.rom[i<<16], 1, 65536, f); } // Load bkpts ti68k_bkpt_clear_access(); ti68k_bkpt_clear_range(); ti68k_bkpt_clear_address(); ti68k_bkpt_clear_exception(); ti68k_bkpt_clear_pgmentry(); ret = fseek(f, sav.bkpts_offset, SEEK_SET); load_bkpt(f, &bkpts.code); load_bkpt(f, &bkpts.exception); load_bkpt(f, &bkpts.pgmentry); load_bkpt(f, &bkpts.mem_rb); load_bkpt(f, &bkpts.mem_rw); load_bkpt(f, &bkpts.mem_rl); load_bkpt(f, &bkpts.mem_wb); load_bkpt(f, &bkpts.mem_ww); load_bkpt(f, &bkpts.mem_wl); load_bkpt2(f, &bkpts.mem_rng_r); load_bkpt2(f, &bkpts.mem_rng_w); if(sav.revision >= 21) load_bkpt3(f, &bkpts.bits); // Update UAE structures m68k_setpc(m68k_getpc()); MakeFromSR(); fclose(f); // Update SAV file to latest revision if(sav.revision < SAV_REVISION) { ti68k_state_save(filename); } return 0; }
/* Try to get some information on the ROM dump: - size - ROM base address - FLASH/EPROM - soft version - calc type */ int ti68k_get_img_infos(const char *filename, IMG_INFO *ri) { FILE *f; IMG_INFO32 ri32; IMG_INFO64 ri64; // No filename, exits if(!strcmp(g_basename(filename), "")) return ERR_CANT_OPEN; // Check file if(!ti68k_is_a_img_file(filename)) { tiemu_warning("Images must have '.img' extension (%s).\n", filename); return ERR_CANT_OPEN; } // Open dest file f = fopen(filename, "rb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", filename); return ERR_CANT_OPEN; } // Read header if (fread(&ri32, sizeof(IMG_INFO32), 1, f) < 1) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } *ri = ri32; // below is patch from Lionel if(strcmp(ri->signature, IMG_SIGN) || ri->size > 4*MB || ri->calc_type > CALC_MAX || ri->header_size == 0 || ri->hw_type > 4 || ri->rom_base == 0) { // In addition to plain invalid files, this may happen if the image was // created on a 64-bit platform with TIEmu <= 3.03. // Try to read an IMG_INFO structure as it used to be written by those // 64-bit platforms. fseek(f, 0, SEEK_SET); if (fread(&ri64, sizeof(IMG_INFO64), 1, f) < 1) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } else { memcpy(ri->signature, &(ri64.signature), sizeof(ri64.signature)); ri->revision = (int32_t)(ri64.revision); ri->header_size = (int32_t)(ri64.header_size); ri->calc_type = ri64.calc_type; memcpy(ri->version, &(ri64.version), sizeof(ri64.version)); ri->flash = ri64.flash; ri->has_boot = ri64.has_boot; ri->size = (int32_t)(ri64.size); ri->hw_type = ri64.hw_type; ri->rom_base = ri64.rom_base; if(strcmp(ri->signature, IMG_SIGN) || ri->size > 4*MB || ri->calc_type > CALC_MAX || ri->header_size == 0 || ri->hw_type > 4 || ri->rom_base == 0) { // Nope, it still doesn't seem to be a TIEmu image. tiemu_warning("Bad image: <%s>\n", filename); return ERR_INVALID_UPGRADE; } else { tiemu_info("Found a reasonably valid 64-bit IMG_INFO in <%s>\n", filename); } } } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", filename); return ERR_CANT_OPEN; } return 0; }