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

Big endian support. Fixes #468 #485

Merged
merged 3 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions core/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ typedef enum eZ80abort {

typedef union eZ80context {
uint8_t opcode;
#if CEMU_BITFIELD_ORDER == CEMU_LITTLE_ENDIAN
struct {
uint8_t z : 3;
uint8_t y : 3;
Expand All @@ -54,7 +55,23 @@ typedef union eZ80context {
uint8_t : 1;
uint8_t q : 1;
uint8_t p : 2;
uint8_t : 2;
};
#else
struct {
uint8_t x : 2;
uint8_t y : 3;
uint8_t z : 3;
};
struct {
uint8_t : 2;
uint8_t p : 2;
uint8_t q : 1;
uint8_t : 1;
uint8_t r : 1;
uint8_t s : 1;
};
#endif
} eZ80context_t;

/* eZ80 CPU State */
Expand Down
47 changes: 47 additions & 0 deletions core/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,53 @@
# define EMSCRIPTEN_KEEPALIVE
#endif

#define CEMU_LITTLE_ENDIAN 1
#define CEMU_BIG_ENDIAN 2
#ifndef CEMU_BYTE_ORDER
# if defined(__BYTE_ORDER__)
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define CEMU_BYTE_ORDER CEMU_LITTLE_ENDIAN
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define CEMU_BYTE_ORDER CEMU_BIG_ENDIAN
# endif
# elif defined(_MSC_VER)
# define CEMU_BYTE_ORDER CEMU_LITTLE_ENDIAN
# endif
#endif
#if CEMU_BYTE_ORDER != CEMU_LITTLE_ENDIAN && CEMU_BYTE_ORDER != CEMU_BIG_ENDIAN
# error Endianness not automatically determined, please define CEMU_BYTE_ORDER as CEMU_LITTLE_ENDIAN or CEMU_BIG_ENDIAN.
#endif
#ifndef CEMU_BITFIELD_ORDER
# define CEMU_BITFIELD_ORDER CEMU_BYTE_ORDER
#endif

#if CEMU_BYTE_ORDER == CEMU_LITTLE_ENDIAN
# define from_le16(w) (w)
# define from_le32(w) (w)
#else
# if __has_builtin(__builtin_bswap16) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
# define from_le16 __builtin_bswap16
# elif defined(_MSVC)
# define from_le16 _byteswap_ushort
# else
static inline uint16_t from_le16(uint16_t w) {
return ((w & UINT16_C(0xFF00) >> 8) | ((w & UINT16_C(0x00FF) << 8);
}
# endif
# if __has_builtin(__builtin_bswap32) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
# define from_le32 __builtin_bswap32
# elif defined(_MSVC)
# define from_le32 _byteswap_ulong
# else
static inline uint32_t from_le32(uint32_t w) {
return ((w & UINT32_C(0xFF000000) >> 24) | ((w & UINT32_C(0x00FF0000) >> 8) |
((w & UINT32_C(0x0000FF00) << 8) | ((w & UINT32_C(0x000000FF) << 24);
}
# endif
#endif
#define to_le16 from_le16
#define to_le32 from_le32

#define GETMASK(index, size) (((1U << (size)) - 1) << (index))
#define READFROM(data, index, size) (((data) & GETMASK((index), (size))) >> (index))
#define WRITE(data, index, size, value) ((data) = ((data) & (~GETMASK((index), (size)))) | ((uint32_t)(value) << (index)))
Expand Down
12 changes: 10 additions & 2 deletions core/keypad.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,21 @@ extern "C" {
typedef struct keypad_state {
union {
struct {
uint16_t mode : 2, rowWait : 14, scanWait;
#if CEMU_BITFIELD_ORDER == CEMU_LITTLE_ENDIAN
uint32_t mode : 2, rowWait : 14, scanWait : 16;
#else
uint32_t scanWait : 16, rowWait : 14, mode : 2;
#endif
};
uint32_t control;
};
union {
struct {
uint8_t rows, cols;
#if CEMU_BITFIELD_ORDER == CEMU_LITTLE_ENDIAN
uint32_t rows : 8, cols : 8, : 16;
#else
uint32_t : 16, cols : 8, rows : 8;
#endif
};
uint32_t size;
};
Expand Down
71 changes: 39 additions & 32 deletions core/lcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ static inline uint32_t rotr32(uint32_t val, uint_fast8_t amount) {
}

static inline uint32_t lcd_next_word(uint32_t **dat) {
uint32_t word = **dat;
uint32_t word = from_le32(**dat);
(*dat)++;
return word;
}
Expand All @@ -42,16 +42,16 @@ static inline uint32_t lcd_bgr888swap(uint32_t bgr888, uint32_t mask) {
return bgr888 ^ diff ^ (diff << 16);
}

static inline uint32_t lcd_abgr8888out(uint32_t abgr8888) {
return abgr8888 | (abgr8888 >> 5 & 0x040004) | (abgr8888 >> 6 & 0x030303);
static inline uint32_t lcd_argb8888out(uint32_t argb8888) {
return argb8888 | (argb8888 >> 5 & 0x040004) | (argb8888 >> 6 & 0x030303);
}

static inline uint32_t lcd_bgr565out(uint32_t bgr565) {
return lcd_abgr8888out(UINT32_C(0xFF000000) | (bgr565 << 8 & 0xF80000) | (bgr565 << 5 & 0xFC00) | (bgr565 << 3 & 0xF8));
static inline uint32_t lcd_rgb565out(uint32_t rgb565) {
return lcd_argb8888out(UINT32_C(0xFF000000) | (rgb565 << 8 & 0xF80000) | (rgb565 << 5 & 0xFC00) | (rgb565 << 3 & 0xF8));
}

static inline uint32_t lcd_bgr888out(uint32_t bgr888) {
return lcd_abgr8888out(UINT32_C(0xFF000000) | (bgr888 & 0xF8FCF8));
static inline uint32_t lcd_rgb888out(uint32_t rgb888) {
return lcd_argb8888out(UINT32_C(0xFF000000) | (rgb888 & 0xF8FCF8));
}

void emu_set_lcd_callback(bool (*callback)(void*), void *data) {
Expand Down Expand Up @@ -86,7 +86,7 @@ void emu_lcd_drawmem(void *output, void *data, void *data_end, uint32_t lcd_cont
uint32_t *dat;
uint32_t *dat_end;

bgr = lcd_control & (1 << 8) ? 0x001F001F : 0;
bgr = lcd_control & (1 << 8) ? 0 : 0x001F001F;
bebo = lcd_control & (1 << 9);
mode = lcd_control >> 1 & 7;
out = output;
Expand All @@ -100,19 +100,19 @@ void emu_lcd_drawmem(void *output, void *data, void *data_end, uint32_t lcd_cont
if (mode < 4) {
uint_fast8_t bpp = 1u << mode;
uint32_t mask = (1 << bpp) - 1;
uint_fast8_t bi = bebo ? 0 : 24;
uint_fast8_t bi = bebo ^ (CEMU_BYTE_ORDER == CEMU_BIG_ENDIAN) ? 0 : 24;
bool bepo = lcd_control & (1 << 10);
if (!bepo) { bi ^= 8 - bpp; }
do {
uint_fast8_t bitpos = 32;
word = lcd_next_word(&dat);
word = *dat++;
do {
color = lcd.palette[word >> ((bitpos -= bpp) ^ bi) & mask];
color |= (uint32_t)lcd.palette[word >> ((bitpos -= bpp) ^ bi) & mask] << 16;
color = lcd_bgr565swap(c1555(color), bgr);
*out++ = lcd_bgr565out(color);
color = lcd_bgr565swap(color, bgr);
*out++ = lcd_rgb565out(color);
if (out == out_end) break;
*out++ = lcd_bgr565out(color >> 16);
*out++ = lcd_rgb565out(color >> 16);
} while (bitpos && out != out_end);
} while (dat < dat_end);

Expand All @@ -121,37 +121,37 @@ void emu_lcd_drawmem(void *output, void *data, void *data_end, uint32_t lcd_cont
do {
word = rotr32(lcd_next_word(&dat), bi);
word = lcd_bgr565swap(c1555(word), bgr);
*out++ = lcd_bgr565out(word);
*out++ = lcd_rgb565out(word);
if (out == out_end) break;
*out++ = lcd_bgr565out(word >> 16);
*out++ = lcd_rgb565out(word >> 16);
} while (dat < dat_end);

} else if (mode == 5) {
bgr = bgr ? 0xFF : 0;
do {
word = lcd_next_word(&dat);
word = lcd_bgr888swap(word, bgr);
*out++ = lcd_bgr888out(word);
*out++ = lcd_rgb888out(word);
} while (dat < dat_end);

} else if (mode == 6) {
uint_fast8_t bi = bebo ? 16 : 0;
do {
word = rotr32(lcd_next_word(&dat), bi);
word = lcd_bgr565swap(word, bgr);
*out++ = lcd_bgr565out(word);
*out++ = lcd_rgb565out(word);
if (out == out_end) break;
*out++ = lcd_bgr565out(word >> 16);
*out++ = lcd_rgb565out(word >> 16);
} while (dat < dat_end);

} else { /* mode == 7 */
uint_fast8_t bi = bebo ? 16 : 0;
do {
word = rotr32(lcd_next_word(&dat), bi);
word = lcd_bgr565swap(c444(word), bgr);
*out++ = lcd_bgr565out(word);
*out++ = lcd_rgb565out(word);
if (out == out_end) break;
*out++ = lcd_bgr565out(word >> 16);
*out++ = lcd_rgb565out(word >> 16);
} while (dat < dat_end);
}

Expand Down Expand Up @@ -271,14 +271,14 @@ static uint32_t lcd_words(uint8_t words) {
default: {
uint_fast8_t bpp = 1 << lcd.LCDBPP;
uint_fast8_t mask = (1 << bpp) - 1;
uint_fast8_t bi = (lcd.BEBO ? 0 : 24) ^ (lcd.BEPO ? 0 : 8 - bpp);
uint_fast8_t bi = (lcd.BEBO ^ (CEMU_BYTE_ORDER == CEMU_BIG_ENDIAN) ? 0 : 24) ^ (lcd.BEPO ? 0 : 8 - bpp);
do {
uint_fast8_t bitpos = 32;
uint32_t word = lcd_next_word(&dat);
uint32_t word = *dat++;
do {
uint32_t pixel = lcd.palette[word >> ((bitpos -= bpp) ^ bi) & mask];
pixel |= (uint32_t)lcd.palette[word >> ((bitpos -= bpp) ^ bi) & mask] << 16;
pixel = lcd_bgr565swap(c1555(pixel), bgr);
pixel = lcd_bgr565swap(pixel, bgr);
ticks = lcd_process_pixel(ticks, pixel);
ticks = lcd_process_pixel(ticks, pixel >> 16);
} while (bitpos);
Expand Down Expand Up @@ -443,9 +443,9 @@ static uint8_t lcd_read(const uint16_t pio, bool peek) {
if (!peek) {
cpu.cycles++;
}
return *((uint8_t *)lcd.palette + index - 0x200);
return lcd.paletteBytes[index - 0x200];
} else if (index < 0xC00) {
if (index >= 0x800) { return read8(lcd.crsrImage[((pio - 0x800) & 0x3FF) >> 2], bit_offset); }
if (index >= 0x800) { return lcd.crsrImageBytes[index - 0x800]; }
} else if (index < 0xE00) {
if (!peek) {
cpu.cycles--;
Expand Down Expand Up @@ -501,13 +501,13 @@ void emu_set_lcd_ptrs(uint32_t **dat, uint32_t **dat_end, int width, int height,
data_start = mem.flash.block + addr;
} else if (addr < 0xE00000) {
mem_end = mem.ram.block + SIZE_RAM;
data_start = mem.ram.block + addr - 0xD00000;
data_start = mem.ram.block + (addr - 0xD00000);
} else if (addr < 0xE30400 && addr >= 0xE30200) {
mem_end = (uint8_t *)lcd.palette + sizeof lcd.palette;
data_start = (uint8_t *)lcd.palette + addr - 0xE30200;
mem_end = lcd.paletteBytes + sizeof lcd.paletteBytes;
data_start = lcd.paletteBytes + (addr - 0xE30200);
} else if (addr < 0xE30C00 && addr >= 0xE30800) {
mem_end = (uint8_t *)lcd.crsrImage + sizeof lcd.crsrImage;
data_start = (uint8_t *)lcd.crsrImage + addr - 0xE30800;
mem_end = lcd.crsrImageBytes + sizeof lcd.crsrImageBytes;
data_start = lcd.crsrImageBytes + (addr - 0xE30800);
} else {
return;
}
Expand Down Expand Up @@ -630,10 +630,17 @@ static void lcd_write(const uint16_t pio, const uint8_t value, bool poke) {
cpu.cycles += (4 - 2);
sched_process_pending_dma(0);
}
write8(lcd.palette[pio >> 1 & 0xFF], (pio & 1) << 3, value);
uint16_t paletteIndex = pio - 0x200;
if (lcd.paletteBytes[paletteIndex] != value) {
lcd.paletteBytes[paletteIndex] = value;
/* Convert to RGB565 in native endianness */
paletteIndex >>= 1;
uint16_t color = lcd.paletteBytes[paletteIndex * 2] | (lcd.paletteBytes[paletteIndex * 2 + 1] << 8);
lcd.palette[paletteIndex] = color + (color & 0xFFE0) + (color >> 10 & 0x0020);
}
} else if (index < 0xC00) {
if (index >= 0x800) {
write8(lcd.crsrImage[((pio - 0x800) & 0x3FF) >> 2], bit_offset, value);
lcd.crsrImageBytes[pio - 0x800] = value;
}
} else if (index < 0xE00) {
if (index == 0xC00) {
Expand Down
11 changes: 9 additions & 2 deletions core/lcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,17 @@ typedef struct lcd_state {

/* 256x16-bit color palette registers */
/* 256 palette entries organized as 128 locations of two entries per word */
uint16_t palette[0x100];
union {
uint32_t paletteWords[0x80]; /* For alignment */
uint8_t paletteBytes[0x200];
};

/* Cursor image RAM registers */
/* 256-word wide values defining images overlaid by the hw cursor mechanism */
uint32_t crsrImage[0x100];
union {
uint32_t crsrImageWords[0x100]; /* For alignment */
uint8_t crsrImageBytes[0x400];
};
uint32_t crsrControl; /* Cursor control register */
uint32_t crsrConfig; /* Cursor configuration register */
uint32_t crsrPalette0; /* Cursor palette registers */
Expand All @@ -62,6 +68,7 @@ typedef struct lcd_state {
enum lcd_comp compare;
uint32_t PPL, HSW, HFP, HBP, LPP, VSW, VFP, VBP, PCD, ACB, CPL, LED, LCDBPP, BPP, PPF;
bool CLKSEL, IVS, IHS, IPC, IOE, LEE, BGR, BEBO, BEPO, WTRMRK;
uint16_t palette[0x100]; /* Palette stored as RGB565 in native endianness */

/* Everything above here goes into the state */
uint32_t *data; /* Pointer to start of data to start extracting from */
Expand Down
27 changes: 16 additions & 11 deletions core/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,13 @@ int EMSCRIPTEN_KEEPALIVE emu_send_variables(const char *const *files, int num, i
return err == 0 ? LINK_GOOD : LINK_ERR;
}

static const char header[] = "**TI83F*\x1A\x0A\0Exported via CEmu ";
static inline size_t write_le16(uint16_t val, FILE *fd) {
uint16_t to_write = to_le16(val);
return fwrite(&to_write, sizeof to_write, 1, fd);
}

int emu_receive_variable(const char *file, const calc_var_t *vars, int count) {
static const char header[] = "**TI83F*\x1A\x0A\0Exported via CEmu ";
FILE *fd;
calc_var_t var;
uint16_t header_size = 13, size = 0, checksum = 0;
Expand All @@ -80,24 +85,24 @@ int emu_receive_variable(const char *file, const calc_var_t *vars, int count) {
if (fseek(fd, FILE_DATA_START, SEEK_SET)) goto w_err;
while (count--) {
if (!vat_search_find(vars++, &var)) goto w_err;
if (fwrite(&header_size, 2, 1, fd) != 1) goto w_err;
if (fwrite(&var.size, 2, 1, fd) != 1) goto w_err;
if (fwrite(&var.type, 1, 1, fd) != 1) goto w_err;
if (fwrite(&var.name, 8, 1, fd) != 1) goto w_err;
if (fwrite(&var.version, 1, 1, fd) != 1) goto w_err;
if (fputc(var.archived << 7, fd) == EOF) goto w_err;
if (fwrite(&var.size, 2, 1, fd) != 1) goto w_err;
if (fwrite(var.data, var.size, 1, fd) != 1) goto w_err;
if (write_le16(header_size, fd) != 1) goto w_err;
if (write_le16(var.size, fd) != 1) goto w_err;
if (fputc(var.type, fd) == EOF) goto w_err;
if (fwrite(&var.name, 8, 1, fd) != 1) goto w_err;
if (fputc(var.version, fd) == EOF) goto w_err;
if (fputc(var.archived << 7, fd) == EOF) goto w_err;
if (write_le16(var.size, fd) != 1) goto w_err;
if (fwrite(var.data, var.size, 1, fd) != 1) goto w_err;
size += 17 + var.size;
}
if (fseek(fd, FILE_DATA, SEEK_SET)) goto w_err;
if (fwrite(&size, 2, 1, fd) != 1) goto w_err;
if (write_le16(size, fd) != 1) goto w_err;
if (fflush(fd)) goto w_err;
while (size--) {
if ((byte = fgetc(fd)) == EOF) goto w_err;
checksum += byte;
}
if (fwrite(&checksum, 2, 1, fd) != 1) goto w_err;
if (write_le16(checksum, fd) != 1) goto w_err;
(void)fclose(fd);

return LINK_GOOD;
Expand Down
8 changes: 4 additions & 4 deletions core/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ static uint32_t addr_block(uint32_t *addr, int32_t size, void **block, uint32_t
*block_size = SIZE_RAM;
} else if (*addr < 0xE30800) {
*addr -= 0xE30200;
*block = lcd.palette;
*block_size = sizeof lcd.palette;
*block = lcd.paletteBytes;
*block_size = sizeof lcd.paletteBytes;
} else {
*addr -= 0xE30800;
*block = lcd.crsrImage;
*block_size = sizeof lcd.crsrImage;
*block = lcd.crsrImageBytes;
*block_size = sizeof lcd.crsrImageBytes;
}
return *addr + (unsigned int)size;
}
Expand Down
4 changes: 2 additions & 2 deletions core/os/os-emscripten.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ void EMSCRIPTEN_KEEPALIVE set_file_to_send(const char* path) {
strcpy(file_buf, path);
}

uint8_t* EMSCRIPTEN_KEEPALIVE lcd_get_frame() {
return &(panel.display[0][0][0]);
uint32_t* EMSCRIPTEN_KEEPALIVE lcd_get_frame() {
return &(panel.display[0][0]);
}

int EMSCRIPTEN_KEEPALIVE emsc_set_main_loop_timing(int mode, int value) {
Expand Down
Loading
Loading