39#define COLS TMS9918_PIXELS_X
44#define PATTERNS TMS_DEFAULT_VRAM_PATT_ADDRESS
45#define NAMES TMS_DEFAULT_VRAM_NAME_ADDRESS
46#define COLORS TMS_DEFAULT_VRAM_COLOR_ADDRESS
50static const uint8_t kTile[8] = {
51 0xFF, 0x81, 0xBD, 0xA5, 0xA5, 0xBD, 0x81, 0xFF
57static void writeVram(
PICO9918_INST_ARG uint16_t addr,
const uint8_t* data,
size_t len)
64static int writePpm(
const char* path,
const uint8_t* rgb)
66 FILE* f = fopen(path,
"wb");
72 fprintf(f,
"P6\n%d %d\n255\n", COLS, ROWS);
73 fwrite(rgb, 3, (
size_t)COLS * ROWS, f);
78#if PICO9918_BUILD_RUNTIME_CHIP
82 if (strcmp(name,
"tms9918") == 0)
84 else if (strcmp(name,
"tms9918a") == 0)
86 else if (strcmp(name,
"f18a") == 0)
88 else if (strcmp(name,
"pico9918") == 0)
90 else if (strcmp(name,
"pro") == 0)
94 fprintf(stderr,
"unknown chip '%s'\n", name);
103int main(
int argc,
char** argv)
105 const char* out = argc > 1 ? argv[1] :
"frame.ppm";
106 static uint8_t rgb[ROWS * COLS * 3];
107 uint8_t tiles[8 * 8];
109#if PICO9918_SINGLE_INSTANCE
115 fprintf(stderr,
"pico9918_new failed\n");
120#if PICO9918_BUILD_RUNTIME_CHIP
121 if (argc > 2 && selectPersonality(
PICO9918_INST argv[2]))
return 1;
125 fprintf(stderr,
"this library was built without runtime chip selection\n");
143 for (
int row = 0; row < ROWS / 8; ++row)
145 uint8_t names[COLS / 8];
146 for (
int col = 0; col < COLS / 8; ++col)
148 names[col] = (uint8_t)((row + col) & 1);
150 writeVram(
PICO9918_INST(uint16_t)(NAMES + row * (COLS / 8)), names,
sizeof names);
156 for (uint16_t y = 0; y < ROWS; ++y)
161 uint8_t* px = rgb + (size_t)y * COLS * 3;
162 for (
int x = 0; x < COLS; ++x)
166 *px++ = (uint8_t)(((argb >> 8) & 0xF) * 17);
167 *px++ = (uint8_t)(((argb >> 4) & 0xF) * 17);
168 *px++ = (uint8_t)(((argb) & 0xF) * 17);
172 printf(
"%s: %dx%d, mode %d\n", out, COLS, ROWS,
175#if !PICO9918_SINGLE_INSTANCE
178 return writePpm(out, rgb);
pico9918_mode_t pico9918_display_mode(pico9918_t *tms9918)
current display mode
void pico9918_destroy(pico9918_t *tms9918)
destroy a TMS9918
void pico9918_write_addr(pico9918_t *tms9918, uint8_t data)
write an address (mode = 1) to the tms9918
void pico9918_set_chip(pico9918_t *tms9918, pico9918_chip_t chip)
select which chip this instance answers as
const uint8_t * pico9918_line_source(pico9918_t *tms9918)
where the scanline just generated actually is.
uint8_t pico9918_scan_line(pico9918_t *tms9918, uint16_t y)
generate a scanline
void pico9918_reset(pico9918_t *tms9918)
reset the new TMS9918
uint16_t pico9918_default_palette(int index)
a default palette entry, 0xargb
pico9918-core - core interface
pico9918_t * pico9918_new(void)
create a new TMS9918
#define TMS_R1_RAM_16K
register 1 bits: VRAM size, blanking, interrupt, mode and sprite size
#define PICO9918_INST_ARG
declare the instance ahead of other parameters
#define PICO9918_INST_ONLY
pass the instance as the only argument
#define TMS_R1_DISP_ACTIVE
render the active display
pico9918_chip_t
which chip an instance answers as
@ PICO9918_CHIP_PICO9918
an F18A plus the PICO9918's own extensions
@ PICO9918_CHIP_TMS9918
a pre-A TMS9918: a TMS9918A without Graphics II
@ PICO9918_CHIP_PICO9918_PRO
a PICO9918 PRO: 8bpp 80-column text, its own splash
@ PICO9918_CHIP_TMS9918A
a TMS9918A: locked, no GPU, no extensions
@ PICO9918_CHIP_F18A
an F18A: unlock, enhanced renderer, GPU
#define PICO9918_INST
pass the instance ahead of other arguments
PICO9918_DLLEXPORT void pico9918_initialise_gfx_i(pico9918_t *tms9918)
program Graphics I, the default table addresses and black on cyan, then clear VRAM
pico9918-core - utility / helper functions
static void pico9918_write_bytes(pico9918_t *tms9918, const uint8_t *bytes, size_t numBytes)
write a block of bytes to VRAM from the current address
static void pico9918_write_register_value(pico9918_t *tms9918, pico9918_register_t reg, uint8_t value)
write a VDP register as a host would, value byte first
static uint8_t pico9918_fg_bg_color(pico9918_color_t fg, pico9918_color_t bg)
pack fg into the high nibble and bg into the low nibble of one colour byte