void io_put_byte(uint32_t addr, uint8_t arg) { addr &= 31; //tihw.io_size-1; switch(addr) { case 0x00: // rw <76...2..> // %5: bit 0 of contrast (TI92) if(tihw.calc_type == TI92) bit_chg(tihw.contrast,0,bit_get(arg,5)); break; case 0x01: // rw <.....2.0> // %0 clr: interleave RAM (allows use of 256K of RAM) if(tihw.hw_type == 1) tihw.ram_size = bit_tst(arg, 0) ? 128*KB : 256*KB; // %2 set: protected memory violation triggered when memory below [$000120] is written break; case 0x02: // ?? break; case 0x03: // -w <.654.210> // Bus waitstates break; case 0x04: break; case 0x05: // -w <...43210> // turn off OSC1 (CPU), wake on int level 6 (ON key) and int level [5..1] m68k_setstopped(1); break; case 0x06: case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: break; case 0x0c: // rw <765.3210> // %[3:0]: Trigger interrupt level 4 on error, activity, tx empty, rx full // see hardware.c // %6: link disable (usually reset link port or direct access to wires) if(bit_get(arg, 6)) hw_dbus_reset(); break; case 0x0d: // r- <76543210> break; case 0x0e: // rw <....3210> // set red/white wires (if direct access) if(io_bit_tst(0x0c,6)) { lc.set_red_wire(!bit_get(arg,0)); lc.set_white_wire(!bit_get(arg,1)); } break; case 0x0f: // rw <76543210> // write a byte to the transmit buffer (1 byte buffer) io_bit_clr(0x0d, 0); // STX=0 (tx reg is full) hw_dbus_putbyte(arg); break; case 0x10: // -w <76543210> (hw1) // address of LCD memory divided by 8 (msb) if(tihw.hw_type == HW1) tihw.lcd_adr = ((arg << 8) | tihw.io[0x11]) << 3; break; case 0x11: // -w <76543210> (hw1) // address of LCD memory divided by 8 (lsb) if(tihw.hw_type == HW1) tihw.lcd_adr = ((tihw.io[0x10] << 8) | arg) << 3; break; case 0x12: // -w <76543210> // LCD logical width = (64-n)*2 bytes = (64-n)*16 pixels <=> n = 64-w/16 tihw.log_w = (64 - arg) * 16; break; case 0x13: // -w <..543210> // LCD logical height = (256-n) <=> n = 256-h tihw.log_h = 0x100 - arg; break; case 0x14: break; case 0x15: // rw <7.6543210> // %7 set: Master disable timer interrupts (level 1, 3 and 5) // see hardware.c // %[5-4]: Increment rate of $600017 (prescaler) set_prescaler((arg >> 4) & 3); // %3 set: Enable incrementing of $600017 // see hardware.c // %2 set: Trigger interrupt level 3 at OSC2/2^19 (~1 Hz on HW2) // see hardware.c // %1 set: OSC2 (and OSC3?) enable (bit clear means oscillator stopped!) // see hardware.c // %0 set: LCD controller DMA enable else LCD blank ("white") // could be implemented but redundant with tihw.on_off break; case 0x16: break; case 0x17: // rw <76543210> // programmable rate generator break; case 0x18: // rw <......10> // keyboard row mask (see keyboard.c) break; case 0x19: // rw <76543210> // keyboard row mask (see keyboard.c) break; case 0x1a: // r- <......10> // ON key status (see keyboard.c) // Write any value to $60001A to acknowledge this interrupt (AutoInt6) break; case 0x1b: // r- <76543210> // keyboard column status (see keyboard.c) // Write any value to $60001B to acknowledge this interrupt (AutoInt2) break; case 0x1c: // -w <..5432..> // %[5-2] set: LCD RS (row sync) frequency, OSC2/((16-n)*8) // %1111 turns off the RS completely (used when LCD is off) tihw.on_off = ((arg & 0x3c) == 0x3c) ? 0 : 1; break; case 0x1d: // -w <7..43210> // %[3-0]: contrast if(tihw.calc_type == TI92) { // %[3-0]: bits <4321.> of contrast static int avg = 0; avg = (avg + arg)/2; // filter value tihw.contrast = (tihw.contrast & 1) | ((avg & 15) << 1); } else { // %[4/3-0]: LCD contrast bits 4/3-0 (bit 4/3 is msb on HW2/HW1) tihw.contrast = arg & (io2_bit_tst(0x1f,0) ? 0x1f : 0x0f); if(tihw.calc_type == TI89 || tihw.calc_type == TI89t) { if(tihw.hw_type == HW1) tihw.contrast = 31 - 2*tihw.contrast; else tihw.contrast = 31 - tihw.contrast; } } break; case 0x1e: break; case 0x1f: break; } tihw.io[addr] = arg; }
/* This function is called by do_cycles to regularly updates the hardware. Rate is the same as the timer tick rate. */ void hw_update(void) { static unsigned int timer; //time_t curr_clock; // OSC2 enable (bit clear means oscillator stopped!) int osc2_enabled = io_bit_tst(0x15,1); timer++; if (osc2_enabled) { // Increment timer if(!(timer & timer_mask) && io_bit_tst(0x15,3)) { if (tihw.timer_value == 0x00) tihw.timer_value = tihw.io[0x17]; else tihw.timer_value++; } } // Increment HW2 RTC timer every 8192 seconds if ((tihw.hw_type >= HW2) && io2_bit_tst(0x1f, 2) && io2_bit_tst(0x1f, 1)) { static struct timeval ref = {0, 0}; struct timeval tmp = {0, 0}; gettimeofday(&tmp, NULL); // Check if 8192 seconds elapsed, avoiding 32-bit overflow if((unsigned)(tmp.tv_sec-ref.tv_sec)*500000u + ((unsigned)(tmp.tv_usec-ref.tv_usec)>>1u) >= 4096000000u) { gettimeofday(&ref, NULL); tihw.rtc_value++; } } // Toggles every FS (every time the LCD restarts at line 0) -> 90 Hz ~ timer/192 // Don't use the actual LCD count (and use 192 rather than 182) to keep exposure // times consistent if(!(timer % 192) && tihw.hw_type >= HW2) tihw.io2[0x1d] ^= 0x80; /* Auto-int management */ if (osc2_enabled) { // Auto-int 1: 1/2^6 of timer rate // Triggered at a fixed rate: OSC2/2^11 = (OSC2/2^5)/2^6 if(!(timer & 63)) { if(!io_bit_tst(0x15,7)) if((tihw.hw_type == HW1) || !(io2_bit_tst(0x1f, 2) && !io2_bit_tst(0x1f, 1))) hw_m68k_irq(1); } // Auto-int 2: keyboard scan // see keyboard.c } if(osc2_enabled || tihw.hw_type == HW2) { // Auto-int 3: disabled by default by AMS // When enabled, it is triggered at a fixed rate: OSC2/2^19 = 1/16384 of timer rate = 1Hz if(!(timer & 16383)) { if(!io_bit_tst(0x15,7) && io_bit_tst(0x15,2)) if((tihw.hw_type == HW1) || !(io2_bit_tst(0x1f, 2) && !io2_bit_tst(0x1f, 1))) hw_m68k_irq(3); } } // DBus: External link activity ? /* if(!ticables_cable_get_d0(cable_handle) || !ticables_cable_get_d1(cable_handle)) { io_bit_set(0x0d,3); //SA io_bit_set(0x0d,2); //EA } */ // DBUS enabled ? if(!io_bit_tst(0x0c,6)) { // Check for data arrival (link cable) hw_dbus_checkread(); // Auto-int 4: triggered by linkport (error, link act, txbuf empty or rxbuf full) if((io_bit_tst(0x0c,3) && io_bit_tst(0x0d,7)) || (io_bit_tst(0x0c,2) && io_bit_tst(0x0d,3)) || (io_bit_tst(0x0c,1) && io_bit_tst(0x0d,6)) || (io_bit_tst(0x0c,0) && io_bit_tst(0x0d,5))) { hw_m68k_irq(4); } } if (osc2_enabled) { // Auto-int 5: triggered by the programmable timer. // The default rate is OSC2/(K*2^9), where K=79 for HW1 and K=53 for HW2 // Make sure AI5 is triggered only if the timer was actually incremented. if(!(timer & timer_mask) && io_bit_tst(0x15,3) && tihw.timer_value == 0) { if(!io_bit_tst(0x15,7)) if((tihw.hw_type == HW1) || !(io2_bit_tst(0x1f, 2) && !io2_bit_tst(0x1f, 1))) hw_m68k_irq(5); } } // Auto-int 6: triggered when [ON] is pressed. // see keyboard.c // Auto-int 7: "vector table write protection" & "stack overflow" // see memory.c /* Hardware refresh */ // Update keyboard (~600Hz). Not related to timer but as a convenience if(!(timer & 127)) // 31 and 63 don't work, 127 and 255 are ok hw_kbd_update(); // Update LCD (HW1: every 256th timer tick, HW2: unrelated) if((tihw.hw_type == HW1) && !(timer & 255)) { G_LOCK(lcd_flag); lcd_flag = !0; G_UNLOCK(lcd_flag); lcd_hook_hw1(); } }
uint8_t io_get_byte(uint32_t addr) { int v; addr &= 31; //tihw.io_size-1; v = tihw.io[addr]; switch(addr) { case 0x00: // rw <76...2..> // %0: bits <....0> of contrast if(tihw.calc_type == TI92) v = ((tihw.contrast & 1) << 5); // %2: Battery voltage level is *above* the trig level v |= 4; // %[7-6]: keep clear break; case 0x01: // rw <.....2.0> break; case 0x02: break; case 0x03: // -w <.654.210> break; case 0x04: // ?? break; case 0x05: // -w <...43210> break; case 0x06: // ?? case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: return 0x14; case 0x0c: // rw <765.3210> // linkport status // see hardware.c or dbus.c break; case 0x0d: // r- <76543210> // reading the DBus status register resets that register tihw.io[0x0d] = 0x40; break; case 0x0e: // rw <....3210> // %[2-3]: read red/white wires if raw access if(io_bit_tst(0x0c,6)) { v |= lc.get_white_wire() << 3; v |= lc.get_white_wire() << 2; } break; case 0x0f: // rw <76543210> // read one byte from receive (incoming) buffer v = hw_dbus_getbyte(); io_bit_clr(0x0d, 5); // SRX=0 (rx reg is empty) break; case 0x10: // -w <76543210> (hw1) return 0x14; case 0x11: // -w <76543210> (hw1) return 0x14; case 0x12: // -w <76543210> return 0x14; case 0x13: // -w <..543210> return 0x14; case 0x14: // ?? break; case 0x15: // rw <7.6543210> break; case 0x16: // ?? break; case 0x17: // rw <76543210> // Programmable rate generator return tihw.timer_value; case 0x18: // rw <76543210> break; case 0x19: // rw <......10> break; case 0x1a: // rw <......10> // ON key status (0=down, 1=up) bit_chg(v,1,!tihw.on_key); break; case 0x1b: // r- <76543210> // keyboard column status v = hw_kbd_read_cols(); case 0x1c: // -w <..5432..> break; case 0x1d: // -w <7..43210> break; case 0x1e: // ?? return 0x14; case 0x1f: // ?? return 0x14; default: return 0x14; } return v; }