1 /* 2 * libtilemcore - Graphing calculator emulation library 3 * 4 * Copyright (C) 2009-2012 Benjamin Moody 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public License 8 * as published by the Free Software Foundation; either version 2.1 of 9 * the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see 18 * <http://www.gnu.org/licenses/>. 19 */ 20 21 #ifndef _TILEM_H 22 #define _TILEM_H 23 24 #include "tilemint.h" 25 26 #ifdef __cplusplus 27 extern "C" { 28 #endif 29 30 /* Basic integer types */ 31 typedef uint8_t byte; 32 typedef uint16_t word; 33 typedef uint32_t dword; 34 typedef uint64_t qword; 35 36 /* Structure types */ 37 typedef struct _TilemHardware TilemHardware; 38 typedef struct _TilemCalc TilemCalc; 39 40 /* Useful macros */ 41 #if __GNUC__ >= 3 42 # define TILEM_ATTR_PURE __attribute__((__pure__)) 43 # define TILEM_ATTR_UNUSED __attribute__((__unused__)) 44 # define TILEM_ATTR_MALLOC __attribute__((__malloc__)) 45 # define TILEM_ATTR_PRINTF(x,y) __attribute__((__format__(__printf__,x,y))) 46 # define TILEM_LIKELY(xxx) (__builtin_expect((xxx), 1)) 47 # define TILEM_UNLIKELY(xxx) (__builtin_expect((xxx), 0)) 48 #else 49 # define TILEM_ATTR_PURE 50 # define TILEM_ATTR_UNUSED 51 # define TILEM_ATTR_MALLOC 52 # define TILEM_ATTR_PRINTF(x,y) 53 # define TILEM_LIKELY(xxx) (xxx) 54 # define TILEM_UNLIKELY(xxx) (xxx) 55 #endif 56 57 #define TILEM_DWORD_TO_PTR(xxx) ((void*)(uintptr_t)(xxx)) 58 #define TILEM_PTR_TO_DWORD(xxx) ((dword)(uintptr_t)(xxx)) 59 60 /* Memory allocation */ 61 void* tilem_malloc(size_t size) TILEM_ATTR_MALLOC; 62 void* tilem_malloc0(size_t size) TILEM_ATTR_MALLOC; 63 void* tilem_malloc_atomic(size_t size) TILEM_ATTR_MALLOC; 64 void* tilem_try_malloc(size_t size) TILEM_ATTR_MALLOC; 65 void* tilem_try_malloc0(size_t size) TILEM_ATTR_MALLOC; 66 void* tilem_try_malloc_atomic(size_t size) TILEM_ATTR_MALLOC; 67 void* tilem_realloc(void* ptr, size_t size) TILEM_ATTR_MALLOC; 68 void tilem_free(void* ptr); 69 #define tilem_new(ttt, nnn) ((ttt*) tilem_malloc((nnn) * sizeof(ttt))); 70 #define tilem_new0(ttt, nnn) ((ttt*) tilem_malloc0((nnn) * sizeof(ttt))); 71 #define tilem_new_atomic(ttt, nnn) ((ttt*) tilem_malloc_atomic((nnn) * sizeof(ttt))); 72 73 #define tilem_try_new(ttt, nnn) ((ttt*) tilem_try_malloc((nnn) * sizeof(ttt))); 74 #define tilem_try_new0(ttt, nnn) ((ttt*) tilem_try_malloc0((nnn) * sizeof(ttt))); 75 #define tilem_try_new_atomic(ttt, nnn) ((ttt*) tilem_try_malloc_atomic((nnn) * sizeof(ttt))); 76 #define tilem_renew(ttt, ppp, nnn) ((ttt*) tilem_realloc((ppp), (nnn) * sizeof(ttt))) 77 78 /* Message/error logging */ 79 80 /* Write an informative message. This can be used to notify the user 81 of major occurences, such as changes in the Flash protection. 82 These messages can occur regularly in normal operation and are 83 provided chiefly to aid in debugging. */ 84 void tilem_message(TilemCalc* calc, const char* msg, ...) 85 TILEM_ATTR_PRINTF(2, 3); 86 87 /* Write a warning message. These messages occur when the calculator 88 software (either the OS or a user program) performs an invalid 89 operation; these messages often indicate a bug in the calculator 90 software, but are otherwise harmless. */ 91 void tilem_warning(TilemCalc* calc, const char* msg, ...) 92 TILEM_ATTR_PRINTF(2, 3); 93 94 /* Write a warning about an internal error. These messages should 95 never occur and indicate a bug in TilEm. */ 96 void tilem_internal(TilemCalc* calc, const char* msg, ...) 97 TILEM_ATTR_PRINTF(2, 3); 98 99 100 /* Z80 CPU */ 101 102 /* This union allows us to manipulate register pairs as either byte or 103 word values. It may need to be modified for really unusual host 104 CPUs. */ 105 typedef union _TilemZ80Reg { 106 #ifdef WORDS_BIGENDIAN 107 struct { 108 byte h3, h2, h, l; 109 } b; 110 111 struct { 112 word h, l; 113 } w; 114 115 dword d; 116 #else 117 struct { 118 byte l, h, h2, h3; 119 } b; 120 121 struct { 122 word l, h; 123 } w; 124 125 dword d; 126 #endif 127 } TilemZ80Reg; 128 129 typedef struct _TilemZ80Regs { 130 TilemZ80Reg af, bc, de, hl; 131 TilemZ80Reg ix, iy, pc, sp; 132 TilemZ80Reg ir, wz, wz2; 133 TilemZ80Reg af2, bc2, de2, hl2; 134 int iff1, iff2, im; 135 byte r7; 136 } TilemZ80Regs; 137 138 /* Breakpoint types */ 139 enum { 140 TILEM_BREAK_MEM_READ = 1, /* Break after reading from memory */ 141 TILEM_BREAK_MEM_EXEC, /* Break prior to executing from memory */ 142 TILEM_BREAK_MEM_WRITE, /* Break after writing to memory */ 143 TILEM_BREAK_PORT_READ, /* Break after reading from port */ 144 TILEM_BREAK_PORT_WRITE, /* Break after writing to port */ 145 TILEM_BREAK_EXECUTE, /* Break after executing opcode */ 146 147 TILEM_BREAK_TYPE_MASK = 0xffff, 148 149 TILEM_BREAK_PHYSICAL = 0x10000, /* Use physical addresses */ 150 TILEM_BREAK_DISABLED = 0x20000 /* Disabled breakpoint */ 151 }; 152 153 /* Emulation flags */ 154 enum { 155 TILEM_Z80_BREAK_INVALID = 1, /* Break on invalid 156 instructions */ 157 TILEM_Z80_BREAK_UNDOCUMENTED = 2, /* Break on undocumented 158 instructions */ 159 TILEM_Z80_SKIP_UNDOCUMENTED = 4, /* Ignore undocumented 160 instructions entirely 161 (act as two NOPs) */ 162 TILEM_Z80_RESET_UNDOCUMENTED = 8, /* Reset CPU following 163 undocumented instructions */ 164 TILEM_Z80_BREAK_EXCEPTIONS = 16, /* Break on hardware exceptions */ 165 TILEM_Z80_IGNORE_EXCEPTIONS = 32 /* Ignore hardware exceptions */ 166 }; 167 168 /* Reasons for stopping emulation */ 169 enum { 170 TILEM_STOP_TIMEOUT = 0, /* stopped due to timeout */ 171 TILEM_STOP_BREAKPOINT = 1, /* stopped due to breakpoint */ 172 TILEM_STOP_INVALID_INST = 2, /* invalid instruction */ 173 TILEM_STOP_UNDOCUMENTED_INST = 4, /* undocumented instruction */ 174 TILEM_STOP_EXCEPTION = 8, /* hardware exception */ 175 TILEM_STOP_LINK_STATE = 16, /* blacklink state change */ 176 TILEM_STOP_LINK_READ_BYTE = 32, /* graylink finished reading byte */ 177 TILEM_STOP_LINK_WRITE_BYTE = 64, /* graylink finished writing byte */ 178 TILEM_STOP_LINK_ERROR = 128 /* graylink encountered error */ 179 }; 180 181 /* Types of interrupt */ 182 enum { 183 TILEM_INTERRUPT_ON_KEY = 1, /* ON key pressed */ 184 TILEM_INTERRUPT_TIMER1 = 2, /* Main interrupt timer */ 185 TILEM_INTERRUPT_TIMER2 = 4, /* Alt. interrupt timer (83/83+) */ 186 TILEM_INTERRUPT_USER_TIMER1 = 8, /* Programmable timers (83+SE) */ 187 TILEM_INTERRUPT_USER_TIMER2 = 16, 188 TILEM_INTERRUPT_USER_TIMER3 = 32, 189 TILEM_INTERRUPT_LINK_ACTIVE = 512, /* Link port state changed */ 190 TILEM_INTERRUPT_LINK_READ = 1024, /* Link assist read a byte */ 191 TILEM_INTERRUPT_LINK_IDLE = 2048, /* Link assist is idle */ 192 TILEM_INTERRUPT_LINK_ERROR = 4096 /* Link assist failed */ 193 }; 194 195 /* Types of hardware exception */ 196 enum { 197 TILEM_EXC_RAM_EXEC = 1, /* Executing at invalid RAM address */ 198 TILEM_EXC_FLASH_EXEC = 2, /* Executing at invalid Flash address */ 199 TILEM_EXC_FLASH_WRITE = 4, /* Writing to invalid Flash address */ 200 TILEM_EXC_INSTRUCTION = 8 /* Invalid instruction */ 201 }; 202 203 /* Constant hardware timer IDs */ 204 enum { 205 TILEM_TIMER_NONE = 0, 206 TILEM_TIMER_LCD_DELAY, 207 TILEM_TIMER_FLASH_DELAY, 208 TILEM_TIMER_LINK_ASSIST, 209 TILEM_TIMER_USER1, 210 TILEM_TIMER_USER2, 211 TILEM_TIMER_USER3, 212 TILEM_TIMER_HW 213 }; 214 215 #define TILEM_NUM_SYS_TIMERS (TILEM_TIMER_HW - 1) 216 217 /* Type of a timer callback function. Second arg is the callback data 218 passed to tilem_z80_add_timer(). */ 219 typedef void (*TilemZ80TimerFunc)(TilemCalc*, void*); 220 221 /* Type of a breakpoint test function. Second arg is the memory 222 address (or opcode in the case of TILEM_BREAK_EXECUTE breakpoints.) 223 Third arg is the callback data passed to 224 tilem_z80_add_breakpoint(). */ 225 typedef int (*TilemZ80BreakpointFunc)(TilemCalc*, dword, void*); 226 227 typedef struct _TilemZ80Timer TilemZ80Timer; 228 typedef struct _TilemZ80Breakpoint TilemZ80Breakpoint; 229 230 typedef struct _TilemZ80 { 231 TilemZ80Regs r; 232 unsigned int interrupts; /* Currently active interrupts */ 233 int clockspeed; /* Current CPU speed (kHz) */ 234 int halted; 235 unsigned int exception; 236 dword clock; 237 dword lastwrite; 238 dword lastlcdwrite; 239 240 unsigned int emuflags; 241 242 int ntimers; 243 TilemZ80Timer* timers; 244 int timer_cpu; /* Sorted list of timers (CPU-based) */ 245 int timer_rt; /* Sorted list of timers (realtime) */ 246 int timer_free; /* List of free timer structs */ 247 248 int nbreakpoints; 249 TilemZ80Breakpoint* breakpoints; 250 int breakpoint_mr; /* Memory read breakpoints */ 251 int breakpoint_mx; /* Memory exec breakpoints */ 252 int breakpoint_mw; /* Memory write breakpoints */ 253 int breakpoint_pr; /* Port read breakpoints */ 254 int breakpoint_pw; /* Port write breakpoints */ 255 int breakpoint_op; /* Opcode breakpoints */ 256 int breakpoint_mpr; /* Physical mem read breakpoints */ 257 int breakpoint_mpx; /* Physical mem exec breakpoints */ 258 int breakpoint_mpw; /* Physical mem write breakpoints */ 259 int breakpoint_disabled; /* Disabled breakpoints */ 260 int breakpoint_free; /* List of free bp structs */ 261 262 int stopping; 263 dword stop_reason; 264 dword stop_mask; 265 int stop_breakpoint; 266 } TilemZ80; 267 268 /* Reset CPU */ 269 void tilem_z80_reset(TilemCalc* calc); 270 271 /* Halt simulation */ 272 void tilem_z80_stop(TilemCalc* calc, dword reason); 273 274 /* Set CPU speed (kHz) */ 275 void tilem_z80_set_speed(TilemCalc* calc, int speed); 276 277 /* Raise a hardware exception */ 278 void tilem_z80_exception(TilemCalc* calc, unsigned type); 279 280 /* Add a timer with the given callback function and data. The 281 callback function will be called after 'count' time units, and 282 every 'period' time units thereafter. If rt = 0, the time units 283 are CPU clock cycles; if rt = 1, time units are microseconds. 284 285 Note that if a timer is set in response to a memory read or write, 286 the length of the delay may be off by as much as 19 clock cycles; 287 the precise timings for these are not (yet) properly emulated. 288 Timers set in response to port I/O events will be accurate to the 289 nearest CPU clock cycle. 290 291 The timer is considered to have "fired" as soon as the specified 292 amount of time has elapsed. The callback function, however, may 293 not be called until after the instruction finishes. If multiple 294 timers fire during the same instruction, the order in which the 295 callback functions will be called is undefined. 296 297 If you create a timer using this function (either repeating or 298 non-repeating), you must call tilem_z80_remove_timer() when the 299 timer is no longer needed. 300 */ 301 int tilem_z80_add_timer(TilemCalc* calc, dword count, dword period, 302 int rt, TilemZ80TimerFunc func, void* data); 303 304 /* Change settings for an existing timer. Arguments are the same as 305 above. If count = 0, the timer is disabled. */ 306 void tilem_z80_set_timer(TilemCalc* calc, int id, dword count, 307 dword period, int rt); 308 309 /* Change period for an existing timer without affecting the current 310 interval. */ 311 void tilem_z80_set_timer_period(TilemCalc* calc, int id, dword period); 312 313 /* Delete a timer. */ 314 void tilem_z80_remove_timer(TilemCalc* calc, int id); 315 316 /* Check whether a timer is currently running. */ 317 int tilem_z80_timer_running(TilemCalc* calc, int id) 318 TILEM_ATTR_PURE; 319 320 /* Get the number of clock ticks from now until the next time the 321 given timer fires. (This may be negative, if the timer has already 322 fired during this instruction.) NOTE: If the timer is disabled, 323 the return value is undefined. */ 324 int tilem_z80_get_timer_clocks(TilemCalc* calc, int id) 325 TILEM_ATTR_PURE; 326 327 /* Get the number of microseconds from now until the next time the 328 given timer fires. */ 329 int tilem_z80_get_timer_microseconds(TilemCalc* calc, int id) 330 TILEM_ATTR_PURE; 331 332 /* Add a breakpoint. The breakpoint will be triggered if the address, 333 ANDed with the given mask, falls between the given start and end 334 inclusive. If a callback function is specified it acts as an 335 additional filter, to determine whether the simulation should be 336 halted. */ 337 int tilem_z80_add_breakpoint(TilemCalc* calc, int type, 338 dword start, dword end, dword mask, 339 TilemZ80BreakpointFunc func, void* data); 340 341 /* Remove the given breakpoint. */ 342 void tilem_z80_remove_breakpoint(TilemCalc* calc, int id); 343 344 /* Enable the given breakpoint. */ 345 void tilem_z80_enable_breakpoint(TilemCalc* calc, int id); 346 347 /* Disable the given breakpoint. */ 348 void tilem_z80_disable_breakpoint(TilemCalc* calc, int id); 349 350 /* Check whether the given breakpoint is currently enabled. */ 351 int tilem_z80_breakpoint_enabled(TilemCalc* calc, int id); 352 353 /* Get the type of the given breakpoint. */ 354 int tilem_z80_get_breakpoint_type(TilemCalc* calc, int id); 355 356 /* Get the start address of the given breakpoint. */ 357 dword tilem_z80_get_breakpoint_address_start(TilemCalc* calc, int id); 358 359 /* Get the start address of the given breakpoint. */ 360 dword tilem_z80_get_breakpoint_address_end(TilemCalc* calc, int id); 361 362 /* Get the start address of the given breakpoint. */ 363 dword tilem_z80_get_breakpoint_address_mask(TilemCalc* calc, int id); 364 365 /* Get the callback/filter function associated to the given breakpoint. */ 366 TilemZ80BreakpointFunc tilem_z80_get_breakpoint_callback(TilemCalc* calc, 367 int id); 368 369 /* Get the data associated to the given breakpoint. */ 370 void* tilem_z80_get_breakpoint_data(TilemCalc* calc, int id); 371 372 /* Set the type of the given breakpoint. */ 373 void tilem_z80_set_breakpoint_type(TilemCalc* calc, int id, int type); 374 375 /* Set the start address of the given breakpoint. */ 376 void tilem_z80_set_breakpoint_address_start(TilemCalc* calc, int id, 377 dword start); 378 379 /* Set the start address of the given breakpoint. */ 380 void tilem_z80_set_breakpoint_address_end(TilemCalc* calc, int id, dword end); 381 382 /* Set the start address of the given breakpoint. */ 383 void tilem_z80_set_breakpoint_address_mask(TilemCalc* calc, int id, dword mask); 384 385 /* Set the callback/filter function associated to the given breakpoint. */ 386 void tilem_z80_set_breakpoint_callback(TilemCalc* calc, int id, 387 TilemZ80BreakpointFunc func); 388 389 /* Set the data associated to the given breakpoint. */ 390 void tilem_z80_set_breakpoint_data(TilemCalc* calc, int id, void* data); 391 392 393 /* Run the simulated CPU for the given number of clock 394 ticks/microseconds, or until a breakpoint is hit or 395 tilem_z80_stop() is called. */ 396 dword tilem_z80_run(TilemCalc* calc, int clocks, int* remaining); 397 dword tilem_z80_run_time(TilemCalc* calc, int microseconds, int* remaining); 398 399 400 /* LCD driver */ 401 402 /* Emulation flags */ 403 enum { 404 TILEM_LCD_REQUIRE_DELAY = 1, /* Emulate required delay 405 between commands */ 406 TILEM_LCD_REQUIRE_LONG_DELAY = 2 /* Require extra-long delay */ 407 }; 408 409 typedef struct _TilemLCD { 410 /* Common settings */ 411 byte active; /* LCD driver active */ 412 byte contrast; /* Contrast value (0-63) */ 413 int rowstride; /* Number of bytes per row */ 414 unsigned int emuflags; 415 416 /* T6A43 internal driver */ 417 word addr; /* Memory address */ 418 419 /* T6A04 external driver */ 420 byte mode; /* I/O mode (0 = 6bit, 1 = 8bit) */ 421 byte inc; /* Increment mode (4-7) */ 422 byte nextbyte; /* Output register */ 423 int x, y; /* Current position */ 424 int rowshift; /* Starting row for display */ 425 byte busy; 426 } TilemLCD; 427 428 /* Reset LCD driver */ 429 void tilem_lcd_reset(TilemCalc* calc); 430 431 /* Get LCD driver status (port 10 input) */ 432 byte tilem_lcd_t6a04_status(TilemCalc* calc); 433 434 /* Send command to LCD driver (port 10 output) */ 435 void tilem_lcd_t6a04_control(TilemCalc* calc, byte val); 436 437 /* Read data from LCD driver (port 11 input) */ 438 byte tilem_lcd_t6a04_read(TilemCalc* calc); 439 440 /* Write data to LCD driver (port 11 output) */ 441 void tilem_lcd_t6a04_write(TilemCalc* calc, byte val); 442 443 /* Get screen image (T6A04 style) */ 444 void tilem_lcd_t6a04_get_data(TilemCalc* calc, byte* data); 445 446 /* Get screen image (T6A43 style) */ 447 void tilem_lcd_t6a43_get_data(TilemCalc* calc, byte* data); 448 449 /* Callback for TILEM_TIMER_LCD_DELAY */ 450 void tilem_lcd_delay_timer(TilemCalc* calc, void* data); 451 452 453 454 /* DBUS link port driver */ 455 456 /* Link port / assist mode flags */ 457 enum { 458 TILEM_LINK_MODE_ASSIST = 1, /* Enable link assist */ 459 TILEM_LINK_MODE_NO_TIMEOUT = 2, /* Assist doesn't time out (xp) */ 460 TILEM_LINK_MODE_INT_ON_ACTIVE = 4, /* Interrupt on state change */ 461 TILEM_LINK_MODE_INT_ON_READ = 8, /* Interrupt on asst. read */ 462 TILEM_LINK_MODE_INT_ON_IDLE = 16, /* Interrupt when asst. idle */ 463 TILEM_LINK_MODE_INT_ON_ERROR = 32 /* Interrupt on asst. error */ 464 }; 465 466 /* Link port state flags */ 467 enum { 468 TILEM_LINK_ASSIST_READ_BYTE = 1, /* Assisted read finished */ 469 TILEM_LINK_ASSIST_READ_BUSY = 2, /* Assisted read in progress */ 470 TILEM_LINK_ASSIST_READ_ERROR = 4, /* Assisted read failed */ 471 TILEM_LINK_ASSIST_WRITE_BUSY = 8, /* Assisted write in progress */ 472 TILEM_LINK_ASSIST_WRITE_ERROR = 16 /* Assisted write failed */ 473 }; 474 475 /* Link emulation mode */ 476 enum { 477 TILEM_LINK_EMULATOR_NONE = 0, /* Link port disconnected */ 478 TILEM_LINK_EMULATOR_BLACK = 1, /* Connected to virtual BlackLink 479 (exit emulation on state change) */ 480 TILEM_LINK_EMULATOR_GRAY = 2 /* Connected to virtual GrayLink 481 (auto send/receive bytes) */ 482 }; 483 484 typedef struct _TilemLinkport { 485 byte lines, extlines; /* Link line state for TI/PC 486 0 = both lines high 487 1 = red wire low 488 2 = white wire low 489 3 = both wires low */ 490 491 unsigned int mode; /* Mode flags */ 492 493 /* Internal link assist */ 494 unsigned int assistflags; /* Assist state */ 495 byte assistin; /* Input buffer (recv from PC) */ 496 byte assistinbits; /* Input bit count */ 497 byte assistout; /* Output buffer (send to PC) */ 498 byte assistoutbits; /* Output bit count */ 499 byte assistlastbyte; /* Last byte received */ 500 501 /* External link emulator */ 502 byte linkemu; 503 byte graylinkin; /* Input buffer (recv from TI) */ 504 byte graylinkinbits; /* Input bit count */ 505 byte graylinkout; /* Output buffer (send to TI) */ 506 byte graylinkoutbits; /* Output bit count */ 507 } TilemLinkport; 508 509 /* Reset link port */ 510 void tilem_linkport_reset(TilemCalc* calc); 511 512 /* Read link port lines */ 513 byte tilem_linkport_get_lines(TilemCalc* calc); 514 515 /* Set link port lines */ 516 void tilem_linkport_set_lines(TilemCalc* calc, byte lines); 517 518 /* Read from, and clear, link assist input buffer */ 519 byte tilem_linkport_read_byte(TilemCalc* calc); 520 521 /* Write to link assist output buffer */ 522 void tilem_linkport_write_byte(TilemCalc* calc, byte data); 523 524 /* Get assist state */ 525 unsigned int tilem_linkport_get_assist_flags(TilemCalc* calc); 526 527 /* Set link port mode */ 528 void tilem_linkport_set_mode(TilemCalc* calc, unsigned int mode); 529 530 /* Set line states for virtual BlackLink */ 531 void tilem_linkport_blacklink_set_lines(TilemCalc* calc, byte lines); 532 533 /* Get line states from virtual BlackLink */ 534 byte tilem_linkport_blacklink_get_lines(TilemCalc* calc); 535 536 /* Reset GrayLink */ 537 void tilem_linkport_graylink_reset(TilemCalc* calc); 538 539 /* Check if GrayLink is ready to send data */ 540 int tilem_linkport_graylink_ready(TilemCalc* calc); 541 542 /* Send a byte via virtual GrayLink */ 543 int tilem_linkport_graylink_send_byte(TilemCalc* calc, byte value); 544 545 /* Get byte received by virtual GrayLink (-1 = none available) */ 546 int tilem_linkport_graylink_get_byte(TilemCalc* calc); 547 548 /* Callback for TILEM_TIMER_LINK_ASSIST */ 549 void tilem_linkport_assist_timer(TilemCalc* calc, void* data); 550 551 552 /* Keypad */ 553 554 typedef struct _TilemKeypad { 555 byte group; 556 byte onkeydown; 557 byte onkeyint; 558 byte keysdown[8]; 559 } TilemKeypad; 560 561 /* Reset keypad */ 562 void tilem_keypad_reset(TilemCalc* calc); 563 564 /* Set current group (port 1 output) */ 565 void tilem_keypad_set_group(TilemCalc* calc, byte group); 566 567 /* Read keys from current group (port 1 input) */ 568 byte tilem_keypad_read_keys(TilemCalc* calc); 569 570 /* Press a key */ 571 void tilem_keypad_press_key(TilemCalc* calc, int scancode); 572 573 /* Release a key */ 574 void tilem_keypad_release_key(TilemCalc* calc, int scancode); 575 576 577 /* Flash */ 578 579 /* Emulation flags */ 580 enum { 581 TILEM_FLASH_REQUIRE_DELAY = 1 /* Require delay after 582 program/erase */ 583 }; 584 585 typedef struct _TilemFlashSector { 586 dword start; 587 dword size; 588 byte protectgroup; 589 } TilemFlashSector; 590 591 typedef struct _TilemFlash { 592 byte unlock; 593 byte state; 594 unsigned int emuflags; 595 byte busy; 596 dword progaddr; 597 byte progbyte; 598 byte toggles; 599 byte overridegroup; 600 } TilemFlash; 601 602 /* Reset Flash */ 603 void tilem_flash_reset(TilemCalc* calc); 604 605 /* Read a byte from the Flash chip */ 606 byte tilem_flash_read_byte(TilemCalc* calc, dword pa); 607 608 /* Erase a Flash sector */ 609 void tilem_flash_erase_address(TilemCalc* calc, dword pa); 610 611 /* Write a byte to the Flash chip */ 612 void tilem_flash_write_byte(TilemCalc* calc, dword pa, byte v); 613 614 /* Callback for TILEM_TIMER_FLASH_DELAY */ 615 void tilem_flash_delay_timer(TilemCalc* calc, void* data); 616 617 618 /* MD5 assist */ 619 620 enum { 621 TILEM_MD5_REG_A = 0, /* initial 'a' value */ 622 TILEM_MD5_REG_B = 1, /* 'b' value */ 623 TILEM_MD5_REG_C = 2, /* 'c' value */ 624 TILEM_MD5_REG_D = 3, /* 'd' value */ 625 TILEM_MD5_REG_X = 4, /* 'X' (or 'T') value */ 626 TILEM_MD5_REG_T = 5 /* 'T' (or 'X') value */ 627 }; 628 629 enum { 630 TILEM_MD5_FUNC_FF = 0, 631 TILEM_MD5_FUNC_GG = 1, 632 TILEM_MD5_FUNC_HH = 2, 633 TILEM_MD5_FUNC_II = 3 634 }; 635 636 typedef struct _TilemMD5Assist { 637 dword regs[6]; 638 byte shift; 639 byte mode; 640 } TilemMD5Assist; 641 642 /* Reset MD5 assist */ 643 void tilem_md5_assist_reset(TilemCalc* calc); 644 645 /* Get output value */ 646 dword tilem_md5_assist_get_value(TilemCalc* calc); 647 648 649 /* Programmable timers */ 650 651 #define TILEM_MAX_USER_TIMERS 3 652 653 enum { 654 TILEM_USER_TIMER_LOOP = 1, /* loop when counter 655 reaches 0 */ 656 TILEM_USER_TIMER_INTERRUPT = 2, /* generate interrupt when 657 finished */ 658 TILEM_USER_TIMER_OVERFLOW = 4, /* timer has expired at 659 least twice since last 660 mode setting */ 661 TILEM_USER_TIMER_FINISHED = 256, /* timer has expired at 662 least once since last 663 mode setting (port 4 664 status bit) */ 665 TILEM_USER_TIMER_NO_HALT_INT = 512 /* suppress interrupt if 666 CPU is halted */ 667 }; 668 669 typedef struct _TilemUserTimer { 670 byte frequency; 671 byte loopvalue; 672 unsigned int status; 673 } TilemUserTimer; 674 675 /* Reset timers */ 676 void tilem_user_timers_reset(TilemCalc* calc); 677 678 /* Set frequency control register */ 679 void tilem_user_timer_set_frequency(TilemCalc* calc, int n, byte value); 680 681 /* Set status flags */ 682 void tilem_user_timer_set_mode(TilemCalc* calc, int n, byte mode); 683 684 /* Start timer */ 685 void tilem_user_timer_start(TilemCalc* calc, int n, byte value); 686 687 /* Get timer value */ 688 byte tilem_user_timer_get_value(TilemCalc* calc, int n); 689 690 /* Callback function */ 691 void tilem_user_timer_expired(TilemCalc* calc, void* data); 692 693 694 /* Calculators */ 695 696 /* Model IDs */ 697 enum { 698 TILEM_CALC_TI73 = '7', /* TI-73 / TI-73 Explorer */ 699 TILEM_CALC_TI76 = 'f', /* TI-76.fr */ 700 TILEM_CALC_TI81 = '1', /* TI-81 */ 701 TILEM_CALC_TI82 = '2', /* TI-82 */ 702 TILEM_CALC_TI83 = '3', /* TI-83 / TI-82 STATS [.fr] */ 703 TILEM_CALC_TI83P = 'p', /* TI-83 Plus */ 704 TILEM_CALC_TI83P_SE = 's', /* TI-83 Plus Silver Edition */ 705 TILEM_CALC_TI84P = '4', /* TI-84 Plus */ 706 TILEM_CALC_TI84P_SE = 'z', /* TI-84 Plus Silver Edition */ 707 TILEM_CALC_TI84P_NSPIRE = 'n', /* TI-Nspire 84 Plus emulator */ 708 TILEM_CALC_TI85 = '5', /* TI-85 */ 709 TILEM_CALC_TI86 = '6' /* TI-86 */ 710 }; 711 712 /* Calculator flags */ 713 enum { 714 TILEM_CALC_HAS_LINK = 1, /* Has link port */ 715 TILEM_CALC_HAS_LINK_ASSIST = 2, /* Has hardware link assist */ 716 TILEM_CALC_HAS_USB = 4, /* Has USB controller */ 717 TILEM_CALC_HAS_FLASH = 8, /* Has (writable) Flash */ 718 TILEM_CALC_HAS_T6A04 = 16, /* Has separate LCD driver */ 719 TILEM_CALC_HAS_MD5_ASSIST = 32 /* Has hardware MD5 assist */ 720 }; 721 722 /* Calculator hardware description */ 723 struct _TilemHardware { 724 char model_id; /* Single character identifying model */ 725 const char* name; /* Short name (e.g. ti83p) */ 726 const char* desc; /* Full name (e.g. TI-83 Plus) */ 727 728 unsigned int flags; 729 730 int lcdwidth, lcdheight; /* Size of LCD */ 731 dword romsize, ramsize; /* Size of ROM and RAM */ 732 dword lcdmemsize; /* Size of external LCD memory */ 733 byte rampagemask; /* Bit mask used for RAM page */ 734 735 int nflashsectors; 736 const TilemFlashSector* flashsectors; 737 738 int nusertimers; 739 740 int nhwregs; /* Number of hardware registers */ 741 const char** hwregnames; /* Harware register names */ 742 743 int nhwtimers; /* Number of hardware timers */ 744 const char** hwtimernames; /* Hardware timer names*/ 745 746 const char** keynames; 747 748 /* Reset calculator */ 749 void (*reset) (TilemCalc*); 750 751 /* Reinitialize after loading state */ 752 void (*stateloaded) (TilemCalc*, int); 753 754 /* Z80 ports and memory */ 755 byte (*z80_in) (TilemCalc*, dword); 756 void (*z80_out) (TilemCalc*, dword, byte); 757 void (*z80_wrmem) (TilemCalc*, dword, byte); 758 byte (*z80_rdmem) (TilemCalc*, dword); 759 byte (*z80_rdmem_m1) (TilemCalc*, dword); 760 761 /* Evaluate a non-standard instruction */ 762 void (*z80_instr) (TilemCalc*, dword); 763 764 /* Persistent timer callback */ 765 void (*z80_ptimer) (TilemCalc*, int); 766 767 /* Retrieve LCD contents */ 768 void (*get_lcd) (TilemCalc*, byte*); 769 770 /* Convert physical <-> logical addresses */ 771 dword (*mem_ltop) (TilemCalc*, dword); 772 dword (*mem_ptol) (TilemCalc*, dword); 773 }; 774 775 /* Current state of the calculator */ 776 struct _TilemCalc { 777 TilemHardware hw; 778 779 TilemZ80 z80; 780 byte* mem; 781 byte* ram; 782 byte* lcdmem; 783 byte mempagemap[4]; 784 785 TilemLCD lcd; 786 TilemLinkport linkport; 787 TilemKeypad keypad; 788 TilemFlash flash; 789 TilemMD5Assist md5assist; 790 TilemUserTimer usertimers[TILEM_MAX_USER_TIMERS]; 791 792 byte poweronhalt; /* System power control. If this is 793 zero, turn off LCD, timers, 794 etc. when CPU halts */ 795 796 byte battery; /* Battery level (units of 0.1 V) */ 797 798 dword* hwregs; 799 }; 800 801 /* Get a list of supported hardware models */ 802 void tilem_get_supported_hardware(const TilemHardware*** models, 803 int* nmodels); 804 805 /* Create a new calculator. This function returns NULL if 806 insufficient memory is available. */ 807 TilemCalc* tilem_calc_new(char id); 808 809 /* Make an exact copy of an existing calculator (including both 810 internal and external state.) Be careful when using this in 811 conjunction with custom timer/breakpoint callback functions. This 812 function returns NULL if insufficient memory is available. */ 813 TilemCalc* tilem_calc_copy(TilemCalc* calc); 814 815 /* Free a calculator that was previously created by tilem_calc_new() 816 or tilem_calc_copy(). */ 817 void tilem_calc_free(TilemCalc* calc); 818 819 /* Reset calculator (essentially, remove and replace batteries.) */ 820 void tilem_calc_reset(TilemCalc* calc); 821 822 /* Load calculator state from ROM and/or save files. */ 823 int tilem_calc_load_state(TilemCalc* calc, FILE* romfile, FILE* savfile); 824 825 /* Save calculator state to ROM and/or save files. */ 826 int tilem_calc_save_state(TilemCalc* calc, FILE* romfile, FILE* savfile); 827 828 829 /* LCD image conversion/scaling */ 830 831 /* Scaling algorithms */ 832 enum { 833 TILEM_SCALE_FAST = 0, /* Fast scaling (nearest neighbor) - 834 looks lousy unless the scaling 835 factor is fairly large */ 836 TILEM_SCALE_SMOOTH /* Smooth scaling - slower and looks 837 better at small sizes; note that 838 this falls back to using the "fast" 839 algorithm if we are scaling up by 840 an integer factor */ 841 }; 842 843 /* Buffer representing a snapshot of the LCD state */ 844 typedef struct _TilemLCDBuffer { 845 byte width; /* Width of LCD */ 846 byte height; /* Height of LCD */ 847 byte rowstride; /* Offset between rows in buffer */ 848 byte contrast; /* Contrast value (0-63) */ 849 dword stamp; /* Timestamp */ 850 dword tmpbufsize; /* Size of temporary buffer */ 851 byte *data; /* Image data (rowstride*height bytes) */ 852 void *tmpbuf; /* Temporary buffer used for scaling */ 853 } TilemLCDBuffer; 854 855 /* Create new TilemLCDBuffer. */ 856 TilemLCDBuffer* tilem_lcd_buffer_new(void) 857 TILEM_ATTR_MALLOC; 858 859 /* Free a TilemLCDBuffer. */ 860 void tilem_lcd_buffer_free(TilemLCDBuffer *buf); 861 862 /* Convert current LCD memory contents to a TilemLCDBuffer (i.e., a 863 monochrome snapshot.) */ 864 void tilem_lcd_get_frame(TilemCalc * restrict calc, 865 TilemLCDBuffer * restrict buf); 866 867 /* Convert current LCD memory contents to a TilemLCDBuffer (i.e., a 868 monochrome snapshot.) 869 Output is only 0 and 1 */ 870 void tilem_lcd_get_frame1(TilemCalc * restrict calc, 871 TilemLCDBuffer * restrict buf); 872 873 /* Convert and scale image to an 8-bit indexed image buffer. IMGWIDTH 874 and IMGHEIGHT are the width and height of the output image, 875 ROWSTRIDE the number of bytes from the start of one row to the next 876 (often equal to IMGWIDTH), and SCALETYPE the scaling algorithm to 877 use. */ 878 void tilem_draw_lcd_image_indexed(TilemLCDBuffer * restrict frm, 879 byte * restrict buffer, 880 int imgwidth, int imgheight, 881 int rowstride, int scaletype); 882 883 /* Convert and scale image to a 24-bit RGB or 32-bit RGBA image 884 buffer. IMGWIDTH and IMGHEIGHT are the width and height of the 885 output image, ROWSTRIDE the number of bytes from the start of one 886 row to the next (often equal to 3 * IMGWIDTH), PIXBYTES the number 887 of bytes per pixel (3 or 4), and SCALETYPE the scaling algorithm to 888 use. PALETTE is an array of 256 color values. */ 889 void tilem_draw_lcd_image_rgb(TilemLCDBuffer * restrict frm, 890 byte * restrict buffer, 891 int imgwidth, int imgheight, int rowstride, 892 int pixbytes, const dword * restrict palette, 893 int scaletype); 894 895 /* Calculate a color palette for use with the above functions. 896 RLIGHT, GLIGHT, BLIGHT are the RGB components (0 to 255) of the 897 lightest possible color; RDARK, GDARK, BDARK are the RGB components 898 of the darkest possible color. GAMMA is the gamma value for the 899 output device (2.2 for most current computer displays and image 900 file formats.) */ 901 dword* tilem_color_palette_new(int rlight, int glight, int blight, 902 int rdark, int gdark, int bdark, 903 double gamma); 904 905 /* Calculate a color palette, as above, and convert it to a packed 906 array of bytes (R, G, B) */ 907 byte* tilem_color_palette_new_packed(int rlight, int glight, int blight, 908 int rdark, int gdark, int bdark, 909 double gamma); 910 911 912 /* Grayscale LCD simulation */ 913 914 typedef struct _TilemGrayLCD TilemGrayLCD; 915 916 /* Create a new LCD and attach to a calculator. Sampling for 917 grayscale is done across WINDOWSIZE frames, with samples taken 918 every SAMPLEINT microseconds. */ 919 TilemGrayLCD* tilem_gray_lcd_new(TilemCalc *calc, int windowsize, 920 int sampleint); 921 922 /* Detach and free an LCD. */ 923 void tilem_gray_lcd_free(TilemGrayLCD *glcd); 924 925 /* Generate a grayscale image for the next frame, based on current 926 calculator state. This function also updates the frame counter and 927 internal state; for proper grayscale behavior, this function needs 928 to be called at regular intervals. */ 929 void tilem_gray_lcd_get_frame(TilemGrayLCD * restrict glcd, 930 TilemLCDBuffer * restrict frm); 931 932 933 /* Miscellaneous functions */ 934 935 /* Guess calculator type for a ROM file */ 936 char tilem_guess_rom_type(FILE* romfile); 937 938 /* Get calculator type for a SAV file */ 939 char tilem_get_sav_type(FILE* savfile); 940 941 /* Check validity of calculator certificate; repair if necessary */ 942 void tilem_calc_fix_certificate(TilemCalc* calc, byte* cert, 943 int app_start, int app_end, 944 unsigned exptab_offset); 945 946 #ifdef __cplusplus 947 } 948 #endif 949 950 #endif 951