Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revision M+ support #461

Merged
merged 31 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
679cbee
Make HW Rev M boot.
jacobly0 Jun 30, 2019
38645c1
Implement remaining used flash instructions, and make flash self-test…
jacobly0 Jul 1, 2019
836ec43
Support python version checking.
jacobly0 Jul 4, 2019
9ebf6bd
Revision M change to privileged code behavior.
jacobly0 Aug 22, 2019
5939adb
Maybe optimize rawPC.
jacobly0 Aug 22, 2019
8e44ca4
Fix missing mirror.
jacobly0 Nov 27, 2021
02288ca
Add ASIC revision selection options
calc84maniac Jan 13, 2023
09237b8
Disallow parallel flash commands on serial flash
calc84maniac Jan 13, 2023
c057ef2
Fix signal connection
calc84maniac Jan 13, 2023
4c028b1
Improve revision selection interface, ensure consistency with settings
calc84maniac Jan 14, 2023
0c31eb3
Implement improved SPI transfer support with scheduler-based timing
calc84maniac Jan 18, 2023
3dca1e5
Implement Flash cache timing, add Flash reset handler, improve Flash …
calc84maniac Jan 24, 2023
f123ee6
Disallow Flash port writes when locked, fix Flash port mirrors on pre-M
calc84maniac Jan 25, 2023
53444f9
Ignore SPI select bit in write value when entering sleep mode
calc84maniac Jan 25, 2023
c701ab4
Add UART implementation with loopback support
calc84maniac Mar 17, 2023
b91a8ab
Add tracking and display of flash cache misses and average access time
calc84maniac Mar 18, 2023
531884b
Move LCD panel functionality out of the SPI device and refactor names
calc84maniac Mar 19, 2023
b74f5e7
Implement interlaced display, fix some parameter bounds
calc84maniac Mar 20, 2023
f429d07
Add simple (timing-inaccurate) support for MCU and VSYNC display modes
calc84maniac Aug 31, 2023
bb4a2b4
Add certificate check to identify Python models, and fix SPI device s…
calc84maniac Sep 1, 2023
9789b2b
Fix USB transfers failing after power cycle by implementing USB regis…
calc84maniac Oct 15, 2023
56791dd
Update translations
adriweb Oct 15, 2023
63bc1a8
Add Python Edition override option and report system type to user.
adriweb Oct 16, 2023
7a61b64
python: add LCD skins and use them when needed
adriweb Jul 1, 2019
79a3c46
Update README
adriweb Oct 18, 2023
c2fad05
Fix an occasional cycle underflow error in port writes
calc84maniac Oct 18, 2023
77949c0
Fix SPI base clock rate
calc84maniac Oct 20, 2023
eab7121
Implement special wait state timing for LCD ports
calc84maniac Oct 29, 2023
9cb4a1f
Improve interrupt dispatch timing, prevent CPU rewinds from delaying …
calc84maniac Oct 29, 2023
d8fbb9e
Perform LCD panel hardware reset in response to the GPIO reset line
calc84maniac Nov 22, 2023
1b6d9be
Latch the values of GPIO DIR and OUT ports
calc84maniac Nov 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ _Note that Release builds have an update checking feature, which is disabled in
* Full screen modes (F11 key)
* Emulation states for efficient saving / restoring
* CE skins (colors like the real devices)
* Available in English, French, Spanish, and Dutch
* Available in English, French, Spanish, Dutch, and Chinese

### _Developer features_
* Main options available via CLI arguments
* IPC features when launching several CEmu processes
* Choice of ASIC / HW revision emulation (A, pre-I, M+...)
* Import/Export RAM, ROM, images...
* Custom display refresh rate, FPS indicator
* Custom emulation speed/throttling
Expand All @@ -45,18 +46,19 @@ _Note that Release builds have an update checking feature, which is disabled in
* Memory viewer/editor
* CPU state/registers viewer/editor
* LCD state/parameters viewer/editor
* Tracking of flash cache misses and average access time
* Memory visualizer (as fully customizable virtual LCDs)
* Stack viewer
* OP1-7 viewer
* FP and OP stacks viewer/editor
* Variable Allocation Table (VAT) viewer
* Variable list with preview and program launcher
* TI-Basic program viewer with syntax-highlight and reformatting
* TI-Basic program debugger with line-by-line stepping
* Recent files list with ability to quickly resend
* Cycle counter for benchmarking/profiling
* Emulation of DMA and SPI (for optimal accuracy)
* Misc. emulation (backlight, battery...)
* Pre-I HW Rev. emulation toggle (IM 2 compatibility)
* "Autotester" (automated unit testing, light scripting)

## How to build
Expand Down
115 changes: 90 additions & 25 deletions core/asic.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#include "misc.h"
#include "mem.h"
#include "lcd.h"
#include "panel.h"
#include "spi.h"
#include "uart.h"
#include "usb/usb.h"
#include "bus.h"
#include "emu.h"
Expand All @@ -17,7 +19,9 @@
#include "backlight.h"
#include "realclock.h"
#include "defines.h"
#include "cert.h"

#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
Expand Down Expand Up @@ -56,13 +60,14 @@ static void plug_devices(void) {
port_map[0xB] = init_backlight();
port_map[0xC] = init_cxxx();
port_map[0xD] = init_spi();
port_map[0xE] = init_exxx();
port_map[0xE] = init_uart();
port_map[0xF] = init_fxxx();

reset_proc_count = 0;

/* Populate reset callbacks */
add_reset_proc(sched_reset);
add_reset_proc(flash_reset);
add_reset_proc(mem_reset);
add_reset_proc(lcd_reset);
add_reset_proc(keypad_reset);
Expand All @@ -75,11 +80,48 @@ static void plug_devices(void) {
add_reset_proc(usb_reset);
add_reset_proc(control_reset);
add_reset_proc(backlight_reset);
add_reset_proc(panel_reset);
add_reset_proc(spi_reset);
add_reset_proc(uart_reset);

gui_console_printf("[CEmu] Initialized Advanced Peripheral Bus...\n");
}

static asic_rev_t report_reset(asic_rev_t loaded_rev, bool* python) {
/* Parse boot code routines to determine version. */
asic_rev_t default_rev = ASIC_REV_A;
boot_ver_t boot_ver;
bool gotVer = bootver_parse(mem.flash.block, &boot_ver);
if (gotVer) {
gui_console_printf("[CEmu] Boot code version: %u.%u.%u.%04u\n",
boot_ver.major, boot_ver.minor, boot_ver.revision, boot_ver.build);

/* Determine the newest ASIC revision that is compatible */
for (int rev = ASIC_REV_A; rev <= ASIC_REV_M; rev++) {
if (bootver_check_rev(&boot_ver, (asic_rev_t)rev)) {
default_rev = rev;
}
}

/* By default, ignore Python Edition in certificate if boot code is too old */
if (loaded_rev == ASIC_REV_AUTO && default_rev < ASIC_REV_M) {
*python = false;
}
}
else {
gui_console_printf("[CEmu] Could not determine boot code version.\n");
}
gui_console_printf("[CEmu] Default ASIC revision is Rev %c.\n", "AIM"[(int)default_rev - 1]);

loaded_rev = gui_handle_reset((gotVer ? &boot_ver : NULL), loaded_rev, default_rev, python);
return (loaded_rev != ASIC_REV_AUTO) ? loaded_rev : default_rev;
}

static void set_features() {
asic.im2 = (asic.revision < ASIC_REV_I);
asic.serFlash = (asic.revision >= ASIC_REV_M);
}

void asic_init(void) {
/* First, initilize memory and CPU */
mem_init();
Expand All @@ -102,9 +144,13 @@ void asic_free(void) {
}

void asic_reset(void) {
unsigned int i;
/* Update the Python state first, so it can be read by the reset handler if needed */
static const uint16_t path[] = { 0x0330, 0x0430 };
asic.python = !cert_field_find_path(mem.flash.block + 0x3B0001, SIZE_FLASH_SECTOR_64K, path, 2, NULL, NULL);
asic.revision = report_reset(ASIC_REV_AUTO, &asic.python);
set_features();

for(i = 0; i < reset_proc_count; i++) {
for (unsigned int i = 0; i < reset_proc_count; i++) {
reset_procs[i]();
}
}
Expand All @@ -117,35 +163,53 @@ ti_device_t EMSCRIPTEN_KEEPALIVE get_device_type(void) {
return asic.device;
}

asic_rev_t EMSCRIPTEN_KEEPALIVE get_asic_revision(void) {
return asic.revision;
}

bool EMSCRIPTEN_KEEPALIVE get_asic_python(void) {
return asic.python;
}

void set_cpu_clock(uint32_t new_rate) {
sched_set_clock(CLOCK_CPU, new_rate);
}

bool asic_restore(FILE *image) {
return fread(&asic.device, sizeof(asic.device), 1, image) == 1
&& backlight_restore(image)
&& control_restore(image)
&& cpu_restore(image)
&& flash_restore(image)
&& intrpt_restore(image)
&& keypad_restore(image)
&& lcd_restore(image)
&& mem_restore(image)
&& watchdog_restore(image)
&& protect_restore(image)
&& rtc_restore(image)
&& sha256_restore(image)
&& gpt_restore(image)
&& usb_restore(image)
&& cxxx_restore(image)
&& spi_restore(image)
&& exxx_restore(image)
&& sched_restore(image)
&& fgetc(image) == EOF;
if (fread(&asic, offsetof(asic_state_t, im2), 1, image) != 1) {
return false;
}
set_features();
if (backlight_restore(image)
&& control_restore(image)
&& cpu_restore(image)
&& flash_restore(image)
&& intrpt_restore(image)
&& keypad_restore(image)
&& lcd_restore(image)
&& mem_restore(image)
&& watchdog_restore(image)
&& protect_restore(image)
&& rtc_restore(image)
&& sha256_restore(image)
&& gpt_restore(image)
&& usb_restore(image)
&& cxxx_restore(image)
&& panel_restore(image)
&& spi_restore(image)
&& uart_restore(image)
&& sched_restore(image)
&& fgetc(image) == EOF)
{
bool python = asic.python;
(void)report_reset(asic.revision, &python);
return true;
}
return false;
}

bool asic_save(FILE *image) {
return fwrite(&asic.device, sizeof(asic.device), 1, image) == 1
return fwrite(&asic, offsetof(asic_state_t, im2), 1, image) == 1
&& backlight_save(image)
&& control_save(image)
&& cpu_save(image)
Expand All @@ -161,7 +225,8 @@ bool asic_save(FILE *image) {
&& gpt_save(image)
&& usb_save(image)
&& cxxx_save(image)
&& panel_save(image)
&& spi_save(image)
&& exxx_save(image)
&& uart_save(image)
&& sched_save(image);
}
15 changes: 15 additions & 0 deletions core/asic.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,21 @@ typedef enum {
TI83PCE = 1
} ti_device_t;

typedef enum {
ASIC_REV_AUTO = 0, /* Used only with set_asic_revision() */
ASIC_REV_A = 1,
ASIC_REV_I = 2,
ASIC_REV_M = 3
} asic_rev_t;

typedef struct asic_state {
ti_device_t device;
/* Only updated on reset */
asic_rev_t revision;
bool python;
/* Populated based on revision */
bool im2;
bool serFlash;
} asic_state_t;

extern asic_state_t asic;
Expand All @@ -28,6 +41,8 @@ bool asic_save(FILE *image);
void set_cpu_clock(uint32_t new_rate);
void set_device_type(ti_device_t device);
ti_device_t get_device_type(void);
asic_rev_t get_asic_revision(void);
bool get_asic_python(void);

#ifdef __cplusplus
}
Expand Down
125 changes: 125 additions & 0 deletions core/bootver.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include "bootver.h"

static const boot_ver_t asic_min_ver[] = {
{ 5, 0, 0, 0 }, /* Rev A */
{ 5, 0, 0, 0 }, /* Rev I */
{ 5, 3, 6, 0 }, /* Rev M */
};

static const boot_ver_t asic_max_ver[] = {
{ 5, 3, 5, 65535 }, /* Rev A */
{ 5, 3, 5, 65535 }, /* Rev I */
{ 255, 255, 255, 65535 }, /* Rev M */
};

static bool parse_entry(const uint8_t* data, uint32_t entry, uint32_t* addr) {
if (entry + 4 >= SIZE_BOOTCODE) {
return false;
}
data += entry;

/* JP addr */
if (data[0] != 0xC3) {
return false;
}

*addr = data[1] | (((uint32_t)data[2]) << 8) | (((uint32_t)data[3]) << 16);
return true;
}

static bool parse_ver_8(const uint8_t* data, uint32_t addr, uint8_t* ver) {
if (addr + 3 >= SIZE_BOOTCODE) {
return false;
}
data += addr;

/* LD A,version; RET */
if ((data[0] != 0x3E) || (data[2] != 0xC9)) {
return false;
}

*ver = data[1];
return true;
}

static bool parse_ver_16(const uint8_t* data, uint32_t addr, uint16_t* ver) {
if (addr + 5 >= SIZE_BOOTCODE) {
return false;
}
data += addr;

/* LD A,versionHigh; LD B,versionLow; RET */
if ((data[0] != 0x3E) || (data[2] != 0x06) || (data[4] != 0xC9)) {
return false;
}

*ver = (((uint16_t)data[1]) << 8) | data[3];
return true;
}

bool bootver_parse(const uint8_t* data, boot_ver_t* boot_ver) {
uint32_t addr;
uint16_t major_minor, build;
uint8_t revision;

if (!data) {
return false;
}

/* _boot_GetBootVerMajor */
if (!parse_entry(data, 0x000080, &addr)) {
return false;
}
if (!parse_ver_16(data, addr, &major_minor)) {
return false;
}

/* _boot_GetBootVerMinor */
if (!parse_entry(data, 0x00008C, &addr)) {
return false;
}
if (!parse_ver_8(data, addr, &revision)) {
return false;
}

/* _boot_GetBootVerBuild */
if (!parse_entry(data, 0x000090, &addr)) {
return false;
}
if (!parse_ver_16(data, addr, &build)) {
return false;
}

boot_ver->major = (uint8_t)(major_minor >> 8);
boot_ver->minor = (uint8_t)major_minor;
boot_ver->revision = revision;
boot_ver->build = build;
return true;
}

bool bootver_check_ver(const boot_ver_t* ver, const boot_ver_t* check) {
if (ver->major != check->major) {
return ver->major > check->major;
}
if (ver->minor != check->minor) {
return ver->minor > check->minor;
}
if (ver->revision != check->revision) {
return ver->revision > check->revision;
}
return ver->build >= check->build;
}

bool bootver_check_rev(const boot_ver_t* ver, asic_rev_t rev) {
unsigned int index = (unsigned int)rev - 1;
if (index >= sizeof(asic_min_ver) / sizeof(boot_ver_t)) {
return false;
}

if (!ver) {
return true;
}

return bootver_check_ver(ver, asic_min_ver + index)
&& bootver_check_ver(asic_max_ver + index, ver);
}
Loading
Loading