void error(const char *fmt, ...) { va_list va; va_start(va, fmt); gui_console_printf("Error (%06X): ", asic.cpu->registers.PC); gui_console_vprintf(fmt, va); gui_console_printf("\n"); va_end(va); debugger(DBG_EXCEPTION, 0); cpu_events |= EVENT_RESET; }
static void watchdog_event(int index) { if (watchdog.control & 1) { watchdog.status = 1; if (watchdog.control & 2) { gui_console_printf("[CEmu] Watchdog reset triggered.\n"); cpuEvents |= EVENT_RESET; } if (watchdog.control & 4) { cpu_nmi(); gui_console_printf("[CEmu] Watchdog NMI triggered.\n"); } event_repeat(index, watchdog.load); } }
static void plug_devices(void) { /* Port ranges 0x0 -> 0xF */ port_map[0x0] = init_control(); port_map[0x1] = init_flash(); port_map[0x2] = init_sha256(); port_map[0x3] = init_usb(); port_map[0x4] = init_lcd(); port_map[0x5] = init_intrpt(); port_map[0x6] = init_watchdog(); port_map[0x7] = init_gpt(); port_map[0x8] = init_rtc(); port_map[0x9] = init_protected(); port_map[0xA] = init_keypad(); port_map[0xB] = init_backlight(); port_map[0xC] = init_cxxx(); port_map[0xD] = init_dxxx(); port_map[0xE] = init_exxx(); port_map[0xF] = init_fxxx(); reset_proc_count = 0; /* Populate reset callbacks */ add_reset_proc(lcd_reset); add_reset_proc(keypad_reset); add_reset_proc(gpt_reset); add_reset_proc(rtc_reset); add_reset_proc(watchdog_reset); add_reset_proc(cpu_reset); gui_console_printf("[CEmu] Initialized APB...\n"); }
void emu_loop(bool reset) { if (reset) { emu_reset(); } exiting = false; #ifdef __EMSCRIPTEN__ emscripten_set_main_loop(emu_inner_loop, -1, 1); #else while (!exiting) { if (cpu_events & EVENT_RESET) { cpu_events = EVENT_NONE; gui_console_printf("CPU Reset triggered..."); emu_reset(); } if (cpu_events & EVENT_DEBUG_STEP) { cpu_events = EVENT_NONE; debugger(DBG_STEP, 0); } sched_process_pending_events(); if (cycle_count_delta < 0) { cpu_execute(); // execute instructions with available clock cycles } else { QThread::yieldCurrentThread(); } } emu_cleanup(); #endif }
void mem_init(void) { unsigned int i; mem.flash.block = (uint8_t*)malloc(flash_size); /* allocate Flash memory */ memset(mem.flash.block, 0xFF, flash_size); mem.flash.size = flash_size; for (i = 0; i < flash_sectors_8K; i++) { mem.flash.sector[i].ptr = mem.flash.block + (i*flash_sector_size_8K); mem.flash.sector[i].locked = true; } for (i = flash_sectors_8K; i < flash_sectors_64K+flash_sectors_8K; i++) { mem.flash.sector[i].ptr = mem.flash.block + (i*flash_sector_size_64K); mem.flash.sector[i].locked = false; } /* Sector 9 is locked */ mem.flash.sector[9].locked = true; mem.flash.locked = true; mem.ram.block = (uint8_t*)calloc(ram_size, sizeof(uint8_t)); /* Allocate RAM */ mem.debug.stepOverAddress = -1; mem.debug.block = (uint8_t*)calloc(0x1000000, sizeof(uint8_t)); /* Allocate Debug memory */ mem.debug.ports = (uint8_t*)calloc(0x10000, sizeof(uint8_t)); /* Allocate Debug Port Monitor */ mem.flash.mapped = false; mem.flash.write_index = 0; mem.flash.command = NO_COMMAND; gui_console_printf("Initialized memory...\n"); }
void debugger_init(void) { debugger.stepOverAddress = -1; debugger.data.block = (uint8_t*)calloc(0x1000000, sizeof(uint8_t)); /* Allocate Debug memory */ debugger.data.ports = (uint8_t*)calloc(0x10000, sizeof(uint8_t)); /* Allocate Debug Port Monitor */ debugger.runUntilSet = false; gui_console_printf("Initialized Debugger...\n"); }
void debugger_free(void) { if (debugger.data.block) { free(debugger.data.block); } if (debugger.data.ports) { free(debugger.data.ports); } gui_console_printf("Freed Debugger.\n"); }
static void flash_erase(uint32_t addr, uint8_t byte) { (void)addr; (void)byte; mem.flash.command = FLASH_CHIP_ERASE; memset(mem.flash.block, 0xFF, flash_size); gui_console_printf("Erased entire Flash chip.\n"); }
void asic_init(void) { /* First, initilize memory and CPU */ mem_init(); cpu_init(); asic.ship_mode_enabled = false; plug_devices(); gui_console_printf("[CEmu] Initialized ASIC...\n"); }
eZ80portrange_t init_control(void) { memset(&control, 0, sizeof control); gui_console_printf("[CEmu] Initialized Control Ports...\n"); /* Set default state to full battery and not charging */ control.batteryCharging = false; control.setBatteryStatus = BATTERY_4; return device; }
void rtc_reset() { memset(&rtc, 0, sizeof rtc); rtc.revision = 0x00010500; sched.items[SCHED_RTC].callback.event = rtc_event; sched.items[SCHED_RTC].clock = CLOCK_1; sched_clear(SCHED_RTC); gui_console_printf("[CEmu] RTC reset.\n"); }
void rtc_reset() { memset(&rtc, 0, sizeof rtc); rtc.revision = 0x00010500; sched.items[SCHED_RTC].clock = CLOCK_32K; sched.items[SCHED_RTC].second = -1; sched.items[SCHED_RTC].proc = rtc_event; gui_console_printf("[CEmu] RTC reset.\n"); }
void debugger_init(void) { debugger.stepOverInstrEnd = -1; debugger.data.block = (uint8_t*)calloc(0x1000000, sizeof(uint8_t)); /* Allocate Debug memory */ debugger.data.ports = (uint8_t*)calloc(0x10000, sizeof(uint8_t)); /* Allocate Debug Port Monitor */ debugger.buffer = (char*)malloc(SIZEOF_DBG_BUFFER * sizeof(char)); /* Used for printing to the console */ debugger.errBuffer = (char*)malloc(SIZEOF_DBG_BUFFER * sizeof(char)); /* Used for printing to the console */ debugger.currentBuffPos = debugger.currentErrBuffPos = 0; gui_console_printf("[CEmu] Initialized Debugger...\n"); }
void watchdog_reset() { /* Initialize device to default state */ memset(&watchdog, 0, sizeof watchdog); sched.items[SCHED_WATCHDOG].clock = CLOCK_CPU; sched.items[SCHED_WATCHDOG].second = -1; sched.items[SCHED_WATCHDOG].proc = watchdog_event; watchdog.load = 0x03EF1480; /* (66MHz) */ watchdog.count = 0x03EF1480; gui_console_printf("Watchdog Timer Reset.\n"); }
// TODO : Make sure it works with the recent commits. void emu_inner_loop(void) { while (!exiting) { sched_process_pending_events(); if (cpu_events & EVENT_RESET) { gui_console_printf("CPU Reset triggered..."); emu_reset(); } if (cycle_count_delta < 0) { cpu_execute(); // execute instructions with available clock cycles } } }
eZ80portrange_t init_flash(void) { int i; /* Initialize device to default state */ for(i = 0; i<0x100; i++) { flash.ports[i] = 0; } flash.ports[0x00] = 0x01; /* From WikiTI */ flash.ports[0x07] = 0xFF; /* From WikiTI */ flash.map = 0x06; /* From WikiTI */ gui_console_printf("Initialized flash device...\n"); return device; }
void control_reset(void) { memset(&control.ports, 0, sizeof control.ports); control.privileged = 0xFFFFFF; control.protectedStart = control.protectedEnd = 0xD1887C; control.protectionStatus = 0; control.stackLimit = 0; control.cpuSpeed = 0; control.flashUnlocked = false; control.protectedPortsUnlocked = false; control.off = false; gui_console_printf("[CEmu] Control reset.\n"); }
void open_debugger(int reason, uint32_t data) { if (inDebugger) { /* Prevent recurse */ return; } if ((reason == DBG_STEP) && debugger.stepOverFirstStep) { if (((cpuEvents & EVENT_DEBUG_STEP_NEXT) && !(debugger.data.block[cpu.registers.PC] & DBG_TEMP_EXEC_BREAKPOINT)) || (cpuEvents & EVENT_DEBUG_STEP_OUT)) { debugger.stepOverFirstStep = false; gui_debugger_raise_or_disable(inDebugger = false); return; } debug_clear_temp_break(); } debugger.cpu_cycles = cpu.cycles; debugger.cpu_next = cpu.next; debugger.total_cycles = cpu.cycles + cpu.cycles_offset; if (debugger.currentBuffPos) { debugger.buffer[debugger.currentBuffPos] = '\0'; gui_console_printf("%s", debugger.buffer); debugger.currentBuffPos = 0; } if (debugger.currentErrBuffPos) { debugger.errBuffer[debugger.currentErrBuffPos] = '\0'; gui_console_err_printf("%s", debugger.errBuffer); debugger.currentErrBuffPos = 0; } inDebugger = true; gui_debugger_send_command(reason, data); while (inDebugger) { gui_emu_sleep(50); } cpu.next = debugger.cpu_next; cpu.cycles = debugger.cpu_cycles; cpu.cycles_offset = debugger.total_cycles - cpu.cycles; if (cpuEvents & EVENT_DEBUG_STEP) { cpu.next = cpu.cycles + 1; } }
static void watchdog_event(int index) { (void)index; if (watchdog.control & 1) { if (--watchdog.count == 0) { watchdog.status = 1; watchdog.count = watchdog.load; } } if ((watchdog.count == 0) && ((watchdog.control & 2) || (watchdog.control & 1))) { cpu_events |= EVENT_RESET; gui_console_printf("Watchdog reset triggered..."); } else { //intrpt_trigger(INT_WATCHDOG, INTERRUPT_SET); // TODO event_repeat(SCHED_WATCHDOG, watchdog.load); } }
void mem_free(void) { if (mem.ram.block) { free(mem.ram.block); mem.ram.block = NULL; } if (mem.flash.block) { free(mem.flash.block); mem.flash.block = NULL; } if (mem.debug.block) { free(mem.debug.block); mem.debug.block = NULL; } if (mem.debug.ports) { free(mem.debug.ports); mem.debug.ports = NULL; } gui_console_printf("Freed memory...\n"); }
/* Write to the 0xFXXX range of ports */ static void fxxx_write(const uint16_t pio, const uint8_t value) { /* 0xFFE appears to dump the contents of flash. Probably not a good thing to print to a console :) */ if (pio != 0xFFF) { return; } #ifdef DEBUG_SUPPORT debugger.buffer[debugger.currentBuffPos] = (char)value; debugger.currentBuffPos = (debugger.currentBuffPos + 1) % (SIZEOF_DBG_BUFFER); if (value == 0) { unsigned x; debugger.currentBuffPos = 0; gui_console_printf("%s",debugger.buffer); for(x=0; x<6; x++) { gui_emu_sleep(); } } #endif }
static void emu_main_loop_inner(void) { if (!emulationPaused) { if (cpuEvents & EVENT_RESET) { gui_console_printf("[CEmu] Calculator reset triggered...\n"); cpu_reset(); cpuEvents &= ~EVENT_RESET; } #ifdef DEBUG_SUPPORT if (!cpu.halted && (cpuEvents & EVENT_DEBUG_STEP)) { cpuEvents &= ~EVENT_DEBUG_STEP; open_debugger(DBG_STEP, 0); } #endif if (!asic.shipModeEnabled) { sched_process_pending_events(); cpu_execute(); } else { gui_emu_sleep(50); } } else { gui_emu_sleep(50); } }
eZ80portrange_t init_rtc(void) { gui_console_printf("[CEmu] Initialized RTC...\n"); return device; }
eZ80portrange_t init_watchdog(void) { gui_console_printf("Initialized watchdog timer...\n"); return pwatchdog; }
bool emu_start(const char *romImage, const char *savedImage) { bool ret = false; long lSize; FILE *imageFile = NULL; gui_set_busy(true); do { if(savedImage != NULL) { emu_image_t *image; imageFile = fopen_utf8(savedImage, "rb"); if (!imageFile) { break; } if (fseek(imageFile, 0L, SEEK_END) < 0) { break; } lSize = ftell(imageFile); if (lSize < 0) { break; } if (fseek(imageFile, 0L, SEEK_SET) < 0) { break; } if((size_t)lSize < sizeof(emu_image_t)) { break; } image = (emu_image_t*)malloc(lSize); if(!image) { break; } if(fread(image, lSize, 1, imageFile) != 1) { free(image); break; } sched_reset(); sched.items[SCHED_THROTTLE].clock = CLOCK_27M; sched.items[SCHED_THROTTLE].proc = throttle_interval_event; asic_init(); asic_reset(); if(image->version != imageVersion || !asic_restore(image)) { emu_cleanup(); free(image); break; } free(image); ret = true; } else { asic_init(); if (romImage == NULL) { gui_console_printf("[CEmu] No ROM image specified.\n"); break; } else { FILE *romFile = fopen_utf8(romImage, "rb"); do { if (romFile) { uint16_t field_type; const uint8_t *outer; const uint8_t *current; const uint8_t *data; uint32_t outer_field_size; uint32_t data_field_size; ti_device_t device_type; uint32_t offset; /* Get ROM file size */ if (fseek(romFile, 0L, SEEK_END) < 0) { break; } lSize = ftell(romFile); if (lSize < 0) { break; } if (fseek(romFile, 0L, SEEK_SET) < 0) { break; } /* Read whole ROM. */ if (fread(mem.flash.block, 1, lSize, romFile) < (size_t)lSize) { break; } if (mem.flash.block[0x7E] == 0xFE) { break; } /* Parse certificate fields to determine model. */ /* device_type = (ti_device_type)(asic.mem->flash.block[0x20017]); */ /* We've heard of the OS base being at 0x30000 on at least one calculator. */ for (offset = 0x20000U; offset < 0x40000U; offset += 0x10000U) { outer = mem.flash.block; /* Outer 0x800(0) field. */ if (cert_field_get(outer + offset, mem.flash.size - offset, &field_type, &outer, &outer_field_size)) { break; } if (field_type != 0x800F /*|| field_type == 0x800D || field_type == 0x800E*/) { continue; } /*fprintf(stderr, "outer: %p\t%04X\t%p\t%u\n", asic.mem->flash.block, field_type, outer, outer_field_size);*/ /* Inner 0x801(0) field: calculator model */ if (cert_field_get(outer, outer_field_size, &field_type, &data, &data_field_size)) { break; } /*fprintf(stderr, "inner 1: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ if (field_type != 0x8012 || data[0] != 0x13) { break; } /* Inner 0x802(0) field: skip. */ data_field_size = outer_field_size - (data + data_field_size - outer); data = outer; if (cert_field_next(&data, &data_field_size)) { break; } /*fprintf(stderr, "data: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ current = data; if (cert_field_get(current, data_field_size, &field_type, &data, &data_field_size)) { break; } /*fprintf(stderr, "inner 2: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ if (field_type != 0x8021) { break; } /* Inner 0x803(0) field: skip. */ data_field_size = outer_field_size - (data + data_field_size - outer); data = current; if (cert_field_next(&data, &data_field_size)) { break; } current = data; /*fprintf(stderr, "data: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ if (cert_field_get(current, data_field_size, &field_type, &data, &data_field_size)) { break; } /*fprintf(stderr, "inner 3: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ if (field_type != 0x8032) { break; } /* Inner 0x80A(0) field: skip. */ data_field_size = outer_field_size - (data + data_field_size - outer); data = current; if (cert_field_next(&data, &data_field_size)) { break; } current = data; /*fprintf(stderr, "data: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ if (cert_field_get(current, data_field_size, &field_type, &data, &data_field_size)) { break; } /*fprintf(stderr, "inner 4: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ if (field_type != 0x80A1) { break; } /* Inner 0x80C(0) field: keep. */ data_field_size = outer_field_size - (data + data_field_size - outer); data = current; if (cert_field_next(&data, &data_field_size)) { break; } current = data; /*fprintf(stderr, "data: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ if (cert_field_get(current, data_field_size, &field_type, &data, &data_field_size)) { break; } /*fprintf(stderr, "inner 5: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size);*/ if (field_type != 0x80C2) { break; } /*fprintf(stderr, "Found calculator type %02X\n", data[1]);*/ if (data[1] != 0 && data[1] != 1) { break; } device_type = (ti_device_t)(data[1]); /* If we come here, we've found something. */ ret = true; break; } if (ret) { set_device_type(device_type); } } } while(0); if (romFile) { fclose(romFile); } } } } while(0); if (imageFile) { fclose(imageFile); } if (!ret) { gui_console_printf("[CEmu] Error opening image (Corrupted certificate?)\n"); emu_cleanup(); } gui_set_busy(false); return ret; }
bool emu_start() { bool ret = false; long lSize; asic_init(); if (rom_image == NULL) { gui_console_printf("No ROM image specified."); } else { FILE *rom = fopen_utf8(rom_image, "rb"); do { if (rom) { uint16_t field_type; const uint8_t *outer; const uint8_t *current; const uint8_t *data; uint32_t outer_field_size; uint32_t data_field_size; ti_device_type device_type; uint32_t offset; // Get ROM file size if (fseek(rom, 0L, SEEK_END) < 0) { break; } lSize = ftell(rom); if (lSize < 0) { break; } if (fseek(rom, 0L, SEEK_SET) < 0) { break; } // Read whole ROM. if (fread(asic.mem->flash.block, 1, lSize, rom) < (size_t)lSize) { break; } // Parse certificate fields to determine model. //device_type = (ti_device_type)(asic.mem->flash.block[0x20017]); // We've heard of the OS base being at 0x30000 on at least one calculator. for (offset = 0x20000U; offset < 0x40000U; offset += 0x10000U) { outer = asic.mem->flash.block; // Outer 0x800(0) field. if (cert_field_get(outer + offset, asic.mem->flash.size - offset, &field_type, &outer, &outer_field_size)) { break; } if (field_type != 0x800F /*|| field_type == 0x800D || field_type == 0x800E*/) { continue; } //fprintf(stderr, "outer: %p\t%04X\t%p\t%u\n", asic.mem->flash.block, field_type, outer, outer_field_size); // Inner 0x801(0) field: calculator model if (cert_field_get(outer, outer_field_size, &field_type, &data, &data_field_size)) { break; } //fprintf(stderr, "inner 1: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); if (field_type != 0x8012 || data[0] != 0x13) { break; } // Inner 0x802(0) field: skip. data_field_size = outer_field_size - (data + data_field_size - outer); data = outer; if (cert_field_next(&data, &data_field_size)) { break; } //fprintf(stderr, "data: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); current = data; if (cert_field_get(current, data_field_size, &field_type, &data, &data_field_size)) { break; } //fprintf(stderr, "inner 2: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); if (field_type != 0x8021) { break; } // Inner 0x803(0) field: skip. data_field_size = outer_field_size - (data + data_field_size - outer); data = current; if (cert_field_next(&data, &data_field_size)) { break; } current = data; //fprintf(stderr, "data: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); if (cert_field_get(current, data_field_size, &field_type, &data, &data_field_size)) { break; } //fprintf(stderr, "inner 3: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); if (field_type != 0x8032) { break; } // Inner 0x80A(0) field: skip. data_field_size = outer_field_size - (data + data_field_size - outer); data = current; if (cert_field_next(&data, &data_field_size)) { break; } current = data; //fprintf(stderr, "data: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); if (cert_field_get(current, data_field_size, &field_type, &data, &data_field_size)) { break; } //fprintf(stderr, "inner 4: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); if (field_type != 0x80A1) { break; } // Inner 0x80C(0) field: keep. data_field_size = outer_field_size - (data + data_field_size - outer); data = current; if (cert_field_next(&data, &data_field_size)) { break; } current = data; //fprintf(stderr, "data: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); if (cert_field_get(current, data_field_size, &field_type, &data, &data_field_size)) { break; } //fprintf(stderr, "inner 5: %p\t%04X\t%p\t%u\n", outer, field_type, data, data_field_size); if (field_type != 0x80C2) { break; } //fprintf(stderr, "Found calculator type %02X\n", data[1]); if (data[1] != 0 && data[1] != 1) { break; } device_type = (ti_device_type)(data[1]); // If we come here, we've found something. ret = true; break; } if (ret) { control.device_type = device_type; asic.device_type = device_type; } } } while(0); if (!ret) { gui_console_printf("Error opening ROM image.\n", rom_image); emu_cleanup(); } if (rom) { fclose(rom); } } return ret; }
eZ80portrange_t init_protected(void) { gui_console_printf("Initialized protected port range...\n"); return p9xxx; }
/* Write to the 0x0XXX range of ports */ static void control_write(const uint16_t pio, const uint8_t byte) { uint8_t index = pio & 0x7F; switch (index) { case 0x00: control.ports[index] = byte; switch (control.readBatteryStatus) { case 3: /* Battery Level is 0 */ control.readBatteryStatus = (control.setBatteryStatus == BATTERY_0) ? 0 : (byte == 0x83) ? 5 : 0; break; case 5: /* Battery Level is 1 */ control.readBatteryStatus = (control.setBatteryStatus == BATTERY_1) ? 0 : (byte == 0x03) ? 7 : 0; break; case 7: /* Battery Level is 2 */ control.readBatteryStatus = (control.setBatteryStatus == BATTERY_2) ? 0 : (byte == 0x83) ? 9 : 0; break; case 9: /* Battery Level is 3 (Or 4) */ control.readBatteryStatus = (control.setBatteryStatus == BATTERY_3) ? 0 : (byte == 0x03) ? 11 : 0; break; } break; case 0x01: control.cpuSpeed = byte & 19; switch(control.cpuSpeed & 3) { case 0: set_cpu_clock_rate(6e6); /* 6 MHz */ break; case 1: set_cpu_clock_rate(12e6); /* 12 MHz */ break; case 2: set_cpu_clock_rate(24e6); /* 24 MHz */ break; case 3: set_cpu_clock_rate(48e6); /* 48 MHz */ break; default: break; } gui_console_printf("[CEmu] CPU clock rate set to: %d MHz\n", 6*(1<<(control.cpuSpeed & 3))); #ifdef DEBUG_SUPPORT if (cpuEvents & EVENT_DEBUG_STEP) { cpuEvents &= ~EVENT_DEBUG_STEP; open_debugger(DBG_STEP, 0); } #endif break; case 0x06: control.ports[index] = byte & 7; break; case 0x07: control.readBatteryStatus = (byte & 0x90) ? 1 : 0; break; case 0x09: switch (control.readBatteryStatus) { case 1: /* Battery is bad */ control.readBatteryStatus = (control.setBatteryStatus == BATTERY_DISCHARGED) ? 0 : (byte & 0x80) ? 0 : 3; break; } control.ports[index] = byte; /* Appears to enter low-power mode (For now; this will be fine) */ if (byte == 0xD4) { asic.ship_mode_enabled = true; control.ports[0] |= 0x40; // Turn calc off cpuEvents |= EVENT_RESET; } break; case 0x0A: control.readBatteryStatus += (control.readBatteryStatus == 3) ? 1 : 0; control.ports[index] = byte; break; case 0x0B: case 0x0C: control.readBatteryStatus = 0; break; case 0x0D: control.ports[index] = (byte & 0xF) << 4 | (byte & 0xF); break; case 0x0F: control.ports[index] = byte & 3; break; case 0x1D: case 0x1E: case 0x1F: write8(control.privileged, (index - 0x1D) << 3, byte); break; case 0x28: if (cpu.registers.PC < control.privileged) { mem.flash.locked = (byte & 4) == 0; } control.ports[index] = byte & 247; break; default: control.ports[index] = byte; break; } }
void mem_reset(void) { memset(mem.ram.block, 0, ram_size); gui_console_printf("RAM reset.\n"); }
void asic_free(void) { /* make sure the LCD doesn't use unalloced mem */ lcd.upcurr = lcd.upbase = 0; mem_free(); gui_console_printf("[CEmu] Freed ASIC.\n"); }