trunk/src/mess/drivers/ticalc1x.c
| r245222 | r245223 | |
| 2 | 2 | // copyright-holders:hap, Sean Riddle |
| 3 | 3 | /*************************************************************************** |
| 4 | 4 | |
| 5 | ** subclass of hh_tms1k_state (includes/hh_tms1k.h, drivers/hh_tms1k.c) ** |
| 6 | |
| 5 | 7 | Texas Instruments TMS1xxx/0970/0980 handheld calculators (mostly single-chip) |
| 6 | 8 | |
| 7 | 9 | Refer to their official manuals on how to use them. |
| r245222 | r245223 | |
| 13 | 15 | |
| 14 | 16 | ***************************************************************************/ |
| 15 | 17 | |
| 16 | | #include "emu.h" |
| 17 | | #include "cpu/tms0980/tms0980.h" |
| 18 | | #include "sound/speaker.h" |
| 18 | #include "includes/hh_tms1k.h" |
| 19 | 19 | |
| 20 | 20 | // internal artwork |
| 21 | 21 | #include "ti1270.lh" |
| r245222 | r245223 | |
| 24 | 24 | #include "wizatron.lh" |
| 25 | 25 | |
| 26 | 26 | |
| 27 | | class ticalc1x_state : public driver_device |
| 27 | class ticalc1x_state : public hh_tms1k_state |
| 28 | 28 | { |
| 29 | 29 | public: |
| 30 | 30 | ticalc1x_state(const machine_config &mconfig, device_type type, const char *tag) |
| 31 | | : driver_device(mconfig, type, tag), |
| 32 | | m_maincpu(*this, "maincpu"), |
| 33 | | m_inp_matrix(*this, "IN"), |
| 34 | | m_speaker(*this, "speaker"), |
| 35 | | m_display_wait(33), |
| 36 | | m_display_maxy(1), |
| 37 | | m_display_maxx(0) |
| 31 | : hh_tms1k_state(mconfig, type, tag) |
| 38 | 32 | { } |
| 39 | 33 | |
| 40 | | // devices |
| 41 | | required_device<cpu_device> m_maincpu; |
| 42 | | optional_ioport_array<11> m_inp_matrix; // max 11 |
| 43 | | optional_device<speaker_sound_device> m_speaker; |
| 44 | | |
| 45 | | // misc common |
| 46 | | UINT16 m_r; // MCU R-pins data |
| 47 | | UINT16 m_o; // MCU O-pins data |
| 48 | | UINT16 m_inp_mux; // multiplexed inputs mask |
| 49 | | bool m_power_on; |
| 50 | | |
| 51 | | UINT8 read_inputs(int columns); |
| 52 | | DECLARE_INPUT_CHANGED_MEMBER(power_button); |
| 53 | | DECLARE_WRITE_LINE_MEMBER(auto_power_off); |
| 54 | | |
| 55 | | virtual void machine_reset(); |
| 56 | | virtual void machine_start(); |
| 57 | | |
| 58 | | // display common |
| 59 | | int m_display_wait; // led/lamp off-delay in microseconds (default 33ms) |
| 60 | | int m_display_maxy; // display matrix number of rows |
| 61 | | int m_display_maxx; // display matrix number of columns |
| 62 | | |
| 63 | | UINT32 m_display_state[0x20]; // display matrix rows data |
| 64 | | UINT16 m_display_segmask[0x20]; // if not 0, display matrix row is a digit, mask indicates connected segments |
| 65 | | UINT32 m_display_cache[0x20]; // (internal use) |
| 66 | | UINT8 m_display_decay[0x20][0x20]; // (internal use) |
| 67 | | |
| 68 | | TIMER_DEVICE_CALLBACK_MEMBER(display_decay_tick); |
| 69 | | void display_update(); |
| 70 | 34 | void display_matrix_seg(int maxx, int maxy, UINT32 setx, UINT32 sety, UINT16 segmask); |
| 71 | 35 | |
| 72 | 36 | // calculator-specific handlers |
| r245222 | r245223 | |
| 93 | 57 | DECLARE_WRITE16_MEMBER(ti30_write_o); |
| 94 | 58 | DECLARE_WRITE16_MEMBER(ti30_write_r); |
| 95 | 59 | DECLARE_READ8_MEMBER(ti30_read_k); |
| 60 | |
| 61 | protected: |
| 62 | virtual void machine_start(); |
| 96 | 63 | }; |
| 97 | 64 | |
| 98 | 65 | |
| 99 | | // machine_start/reset |
| 100 | | |
| 101 | 66 | void ticalc1x_state::machine_start() |
| 102 | 67 | { |
| 103 | | // zerofill |
| 104 | | memset(m_display_state, 0, sizeof(m_display_state)); |
| 105 | | memset(m_display_cache, ~0, sizeof(m_display_cache)); |
| 106 | | memset(m_display_decay, 0, sizeof(m_display_decay)); |
| 68 | hh_tms1k_state::machine_start(); |
| 107 | 69 | memset(m_display_segmask, ~0, sizeof(m_display_segmask)); // ! |
| 108 | | |
| 109 | | m_o = 0; |
| 110 | | m_r = 0; |
| 111 | | m_inp_mux = 0; |
| 112 | | m_power_on = false; |
| 113 | | |
| 114 | | // register for savestates |
| 115 | | save_item(NAME(m_display_maxy)); |
| 116 | | save_item(NAME(m_display_maxx)); |
| 117 | | save_item(NAME(m_display_wait)); |
| 118 | | |
| 119 | | save_item(NAME(m_display_state)); |
| 120 | | /* save_item(NAME(m_display_cache)); */ // don't save! |
| 121 | | save_item(NAME(m_display_decay)); |
| 122 | | save_item(NAME(m_display_segmask)); |
| 123 | | |
| 124 | | save_item(NAME(m_o)); |
| 125 | | save_item(NAME(m_r)); |
| 126 | | save_item(NAME(m_inp_mux)); |
| 127 | | save_item(NAME(m_power_on)); |
| 128 | 70 | } |
| 129 | 71 | |
| 130 | | void ticalc1x_state::machine_reset() |
| 131 | | { |
| 132 | | m_power_on = true; |
| 133 | | } |
| 134 | | |
| 135 | | |
| 136 | | |
| 137 | | /*************************************************************************** |
| 138 | | |
| 139 | | Helper Functions |
| 140 | | |
| 141 | | ***************************************************************************/ |
| 142 | | |
| 143 | | // The device may strobe the outputs very fast, it is unnoticeable to the user. |
| 144 | | // To prevent flickering here, we need to simulate a decay. |
| 145 | | |
| 146 | | void ticalc1x_state::display_update() |
| 147 | | { |
| 148 | | UINT32 active_state[0x20]; |
| 149 | | |
| 150 | | for (int y = 0; y < m_display_maxy; y++) |
| 151 | | { |
| 152 | | active_state[y] = 0; |
| 153 | | |
| 154 | | for (int x = 0; x < m_display_maxx; x++) |
| 155 | | { |
| 156 | | // turn on powered segments |
| 157 | | if (m_power_on && m_display_state[y] >> x & 1) |
| 158 | | m_display_decay[y][x] = m_display_wait; |
| 159 | | |
| 160 | | // determine active state |
| 161 | | int ds = (m_display_decay[y][x] != 0) ? 1 : 0; |
| 162 | | active_state[y] |= (ds << x); |
| 163 | | } |
| 164 | | } |
| 165 | | |
| 166 | | // on difference, send to output |
| 167 | | for (int y = 0; y < m_display_maxy; y++) |
| 168 | | if (m_display_cache[y] != active_state[y]) |
| 169 | | { |
| 170 | | if (m_display_segmask[y] != 0) |
| 171 | | output_set_digit_value(y, active_state[y] & m_display_segmask[y]); |
| 172 | | |
| 173 | | const int mul = (m_display_maxx <= 10) ? 10 : 100; |
| 174 | | for (int x = 0; x < m_display_maxx; x++) |
| 175 | | { |
| 176 | | int state = active_state[y] >> x & 1; |
| 177 | | output_set_lamp_value(y * mul + x, state); |
| 178 | | |
| 179 | | // bit coords for svg2lay |
| 180 | | char buf[10]; |
| 181 | | sprintf(buf, "%d.%d", y, x); |
| 182 | | output_set_value(buf, state); |
| 183 | | } |
| 184 | | } |
| 185 | | |
| 186 | | memcpy(m_display_cache, active_state, sizeof(m_display_cache)); |
| 187 | | } |
| 188 | | |
| 189 | | TIMER_DEVICE_CALLBACK_MEMBER(ticalc1x_state::display_decay_tick) |
| 190 | | { |
| 191 | | // slowly turn off unpowered segments |
| 192 | | for (int y = 0; y < m_display_maxy; y++) |
| 193 | | for (int x = 0; x < m_display_maxx; x++) |
| 194 | | if (m_display_decay[y][x] != 0) |
| 195 | | m_display_decay[y][x]--; |
| 196 | | |
| 197 | | display_update(); |
| 198 | | } |
| 199 | | |
| 200 | 72 | void ticalc1x_state::display_matrix_seg(int maxx, int maxy, UINT32 setx, UINT32 sety, UINT16 segmask) |
| 201 | 73 | { |
| 202 | | m_display_maxx = maxx; |
| 203 | | m_display_maxy = maxy; |
| 204 | | |
| 205 | | // update current state |
| 206 | | UINT32 colmask = (1 << maxx) - 1; |
| 207 | 74 | for (int y = 0; y < maxy; y++) |
| 208 | | { |
| 209 | 75 | m_display_segmask[y] &= segmask; |
| 210 | | m_display_state[y] = (sety >> y & 1) ? (setx & colmask) : 0; |
| 211 | | } |
| 212 | 76 | |
| 213 | | display_update(); |
| 77 | display_matrix(maxx, maxy, setx, sety); |
| 214 | 78 | } |
| 215 | 79 | |
| 216 | 80 | |
| 217 | | UINT8 ticalc1x_state::read_inputs(int columns) |
| 218 | | { |
| 219 | | UINT8 ret = 0; |
| 220 | 81 | |
| 221 | | // read selected input rows |
| 222 | | for (int i = 0; i < columns; i++) |
| 223 | | if (m_inp_mux >> i & 1) |
| 224 | | ret |= m_inp_matrix[i]->read(); |
| 225 | | |
| 226 | | return ret; |
| 227 | | } |
| 228 | | |
| 229 | | |
| 230 | | // devices with a TMS0980 can auto power-off |
| 231 | | |
| 232 | | WRITE_LINE_MEMBER(ticalc1x_state::auto_power_off) |
| 233 | | { |
| 234 | | if (state) |
| 235 | | { |
| 236 | | m_power_on = false; |
| 237 | | m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); |
| 238 | | } |
| 239 | | } |
| 240 | | |
| 241 | | INPUT_CHANGED_MEMBER(ticalc1x_state::power_button) |
| 242 | | { |
| 243 | | m_power_on = (bool)(FPTR)param; |
| 244 | | m_maincpu->set_input_line(INPUT_LINE_RESET, m_power_on ? CLEAR_LINE : ASSERT_LINE); |
| 245 | | } |
| 246 | | |
| 247 | | |
| 248 | | |
| 249 | 82 | /*************************************************************************** |
| 250 | 83 | |
| 251 | 84 | Minidrivers (I/O, Inputs, Machine Config) |
| r245222 | r245223 | |
| 269 | 102 | m_display_state[11] = m_display_state[10] << 5 & 0x40; |
| 270 | 103 | m_display_state[10] &= 0x40; |
| 271 | 104 | |
| 272 | | m_display_maxx = 8; |
| 273 | | m_display_maxy = 12; |
| 105 | set_display_size(8, 12); |
| 274 | 106 | display_update(); |
| 275 | 107 | } |
| 276 | 108 | |
| r245222 | r245223 | |
| 372 | 204 | MCFG_TMS1XXX_WRITE_O_CB(WRITE16(ticalc1x_state, tisr16_write_o)) |
| 373 | 205 | MCFG_TMS1XXX_WRITE_R_CB(WRITE16(ticalc1x_state, tisr16_write_r)) |
| 374 | 206 | |
| 375 | | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", ticalc1x_state, display_decay_tick, attotime::from_msec(1)) |
| 207 | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_tms1k_state, display_decay_tick, attotime::from_msec(1)) |
| 376 | 208 | MCFG_DEFAULT_LAYOUT(layout_tisr16) |
| 377 | 209 | |
| 378 | 210 | /* no video! */ |
| r245222 | r245223 | |
| 548 | 380 | MCFG_TMS1XXX_WRITE_O_CB(WRITE16(ticalc1x_state, ti1270_write_o)) |
| 549 | 381 | MCFG_TMS1XXX_WRITE_R_CB(WRITE16(ticalc1x_state, ti1270_write_r)) |
| 550 | 382 | |
| 551 | | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", ticalc1x_state, display_decay_tick, attotime::from_msec(1)) |
| 383 | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_tms1k_state, display_decay_tick, attotime::from_msec(1)) |
| 552 | 384 | MCFG_DEFAULT_LAYOUT(layout_ti1270) |
| 553 | 385 | |
| 554 | 386 | /* no video! */ |
| r245222 | r245223 | |
| 632 | 464 | MCFG_TMS1XXX_WRITE_O_CB(WRITE16(ticalc1x_state, wizatron_write_o)) |
| 633 | 465 | MCFG_TMS1XXX_WRITE_R_CB(WRITE16(ticalc1x_state, wizatron_write_r)) |
| 634 | 466 | |
| 635 | | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", ticalc1x_state, display_decay_tick, attotime::from_msec(1)) |
| 467 | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_tms1k_state, display_decay_tick, attotime::from_msec(1)) |
| 636 | 468 | MCFG_DEFAULT_LAYOUT(layout_wizatron) |
| 637 | 469 | |
| 638 | 470 | /* no video! */ |
| r245222 | r245223 | |
| 692 | 524 | MCFG_TMS1XXX_WRITE_O_CB(WRITE16(ticalc1x_state, lilprof_write_o)) |
| 693 | 525 | MCFG_TMS1XXX_WRITE_R_CB(WRITE16(ticalc1x_state, wizatron_write_r)) |
| 694 | 526 | |
| 695 | | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", ticalc1x_state, display_decay_tick, attotime::from_msec(1)) |
| 527 | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_tms1k_state, display_decay_tick, attotime::from_msec(1)) |
| 696 | 528 | MCFG_DEFAULT_LAYOUT(layout_wizatron) |
| 697 | 529 | |
| 698 | 530 | /* no video! */ |
| r245222 | r245223 | |
| 706 | 538 | |
| 707 | 539 | /*************************************************************************** |
| 708 | 540 | |
| 709 | | TI Little Professor (1978 version, same as 1980 version) |
| 541 | TI Little Professor (1978 version) |
| 710 | 542 | * TMS1990 MCU labeled TMC1993NL. die labeled 1990C-c3C |
| 543 | |
| 544 | 1978 re-release, with on/off and level select on buttons instead of |
| 545 | switches. The casing was slightly revised in 1980 again, but same rom. |
| 711 | 546 | |
| 712 | 547 | ***************************************************************************/ |
| 713 | 548 | |
| r245222 | r245223 | |
| 726 | 561 | // 6th digit is a custom 7seg for math symbols (see wizatron_write_r) |
| 727 | 562 | m_display_state[6] = BITSWAP8(m_display_state[6],7,6,1,4,2,3,5,0); |
| 728 | 563 | |
| 729 | | m_display_maxx = 7; |
| 730 | | m_display_maxy = 9; |
| 564 | set_display_size(7, 9); |
| 731 | 565 | display_update(); |
| 732 | 566 | } |
| 733 | 567 | |
| r245222 | r245223 | |
| 788 | 622 | MCFG_TMS1XXX_WRITE_O_CB(WRITE16(ticalc1x_state, lilprof78_write_o)) |
| 789 | 623 | MCFG_TMS1XXX_WRITE_R_CB(WRITE16(ticalc1x_state, lilprof78_write_r)) |
| 790 | 624 | |
| 791 | | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", ticalc1x_state, display_decay_tick, attotime::from_msec(1)) |
| 625 | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_tms1k_state, display_decay_tick, attotime::from_msec(1)) |
| 792 | 626 | MCFG_DEFAULT_LAYOUT(layout_wizatron) |
| 793 | 627 | |
| 794 | 628 | /* no video! */ |
| r245222 | r245223 | |
| 1023 | 857 | MCFG_TMS1XXX_WRITE_R_CB(WRITE16(ticalc1x_state, ti30_write_r)) |
| 1024 | 858 | MCFG_TMS1XXX_POWER_OFF_CB(WRITELINE(ticalc1x_state, auto_power_off)) |
| 1025 | 859 | |
| 1026 | | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", ticalc1x_state, display_decay_tick, attotime::from_msec(1)) |
| 860 | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_tms1k_state, display_decay_tick, attotime::from_msec(1)) |
| 1027 | 861 | MCFG_DEFAULT_LAYOUT(layout_ti30) |
| 1028 | 862 | |
| 1029 | 863 | /* no video! */ |
trunk/src/mess/drivers/tispeak.c
| r245222 | r245223 | |
| 2 | 2 | // copyright-holders:hap, Lord Nightmare |
| 3 | 3 | /*************************************************************************** |
| 4 | 4 | |
| 5 | ** subclass of hh_tms1k_state (includes/hh_tms1k.h, drivers/hh_tms1k.c) ** |
| 6 | |
| 5 | 7 | Texas Instruments 1st-gen. handheld speech devices, |
| 6 | 8 | |
| 7 | 9 | These devices, mostly edu-toys, are based around an MCU(TMS0270/TMS1100), |
| r245222 | r245223 | |
| 275 | 277 | |
| 276 | 278 | ***************************************************************************/ |
| 277 | 279 | |
| 278 | | #include "emu.h" |
| 279 | | #include "cpu/tms0980/tms0980.h" |
| 280 | #include "includes/hh_tms1k.h" |
| 280 | 281 | #include "sound/tms5110.h" |
| 281 | 282 | #include "machine/tms6100.h" |
| 282 | 283 | #include "bus/generic/slot.h" |
| 283 | 284 | #include "bus/generic/carts.h" |
| 284 | 285 | |
| 286 | // internal artwork |
| 285 | 287 | #include "lantutor.lh" |
| 286 | 288 | #include "snspell.lh" |
| 287 | 289 | |
| r245222 | r245223 | |
| 294 | 296 | #define MASTER_CLOCK (640000) |
| 295 | 297 | |
| 296 | 298 | |
| 297 | | class tispeak_state : public driver_device |
| 299 | class tispeak_state : public hh_tms1k_state |
| 298 | 300 | { |
| 299 | 301 | public: |
| 300 | 302 | tispeak_state(const machine_config &mconfig, device_type type, const char *tag) |
| 301 | | : driver_device(mconfig, type, tag), |
| 302 | | m_maincpu(*this, "maincpu"), |
| 303 | : hh_tms1k_state(mconfig, type, tag), |
| 303 | 304 | m_tms5100(*this, "tms5100"), |
| 304 | 305 | m_tms6100(*this, "tms6100"), |
| 305 | | m_cart(*this, "cartslot"), |
| 306 | | m_button_matrix(*this, "IN"), |
| 307 | | m_display_wait(33), |
| 308 | | m_display_maxy(1), |
| 309 | | m_display_maxx(0) |
| 306 | m_cart(*this, "cartslot") |
| 310 | 307 | { } |
| 311 | 308 | |
| 312 | 309 | // devices |
| 313 | | required_device<tms0270_cpu_device> m_maincpu; |
| 314 | 310 | required_device<tms5100_device> m_tms5100; |
| 315 | 311 | required_device<tms6100_device> m_tms6100; |
| 316 | 312 | optional_device<generic_slot_device> m_cart; |
| 317 | | required_ioport_array<9> m_button_matrix; |
| 318 | 313 | |
| 319 | | // misc common |
| 320 | | UINT16 m_r; // MCU R-pins data |
| 321 | | UINT16 m_o; // MCU O-pins data |
| 322 | | int m_power_on; |
| 323 | | int m_filament_on; |
| 324 | | |
| 325 | | // display common |
| 326 | | int m_display_wait; // led/lamp off-delay in microseconds (default 33ms) |
| 327 | | int m_display_maxy; // display matrix number of rows |
| 328 | | int m_display_maxx; // display matrix number of columns |
| 329 | | |
| 330 | | UINT32 m_display_state[0x20]; // display matrix rows data |
| 331 | | UINT16 m_display_segmask[0x20]; // if not 0, display matrix row is a digit, mask indicates connected segments |
| 332 | | UINT32 m_display_cache[0x20]; // (internal use) |
| 333 | | UINT8 m_display_decay[0x20][0x20]; // (internal use) |
| 334 | | |
| 335 | | TIMER_DEVICE_CALLBACK_MEMBER(display_decay_tick); |
| 336 | | void display_update(); |
| 337 | | void display_matrix_seg(int maxx, int maxy, UINT32 setx, UINT32 sety, UINT16 segmask); |
| 338 | | |
| 339 | 314 | // cartridge |
| 340 | 315 | UINT32 m_cart_max_size; |
| 341 | 316 | UINT8* m_cart_base; |
| r245222 | r245223 | |
| 349 | 324 | DECLARE_WRITE16_MEMBER(snspell_write_r); |
| 350 | 325 | DECLARE_WRITE16_MEMBER(lantutor_write_r); |
| 351 | 326 | |
| 352 | | DECLARE_INPUT_CHANGED_MEMBER(power_button); |
| 353 | | void power_off(); |
| 327 | DECLARE_INPUT_CHANGED_MEMBER(snspell_power_button); |
| 328 | void snspell_power_off(); |
| 329 | void snspell_display(); |
| 354 | 330 | |
| 355 | | virtual void machine_reset(); |
| 331 | protected: |
| 356 | 332 | virtual void machine_start(); |
| 357 | 333 | }; |
| 358 | 334 | |
| r245222 | r245223 | |
| 397 | 373 | |
| 398 | 374 | /*************************************************************************** |
| 399 | 375 | |
| 400 | | VFD Display |
| 376 | I/O |
| 401 | 377 | |
| 402 | 378 | ***************************************************************************/ |
| 403 | 379 | |
| 404 | | // The device may strobe the outputs very fast, it is unnoticeable to the user. |
| 405 | | // To prevent flickering here, we need to simulate a decay. |
| 380 | // common/snspell |
| 406 | 381 | |
| 407 | | void tispeak_state::display_update() |
| 382 | void tispeak_state::snspell_display() |
| 408 | 383 | { |
| 409 | | UINT32 active_state[0x20]; |
| 384 | for (int y = 0; y < 16; y++) |
| 385 | m_display_segmask[y] = 0x3fff; |
| 410 | 386 | |
| 411 | | for (int y = 0; y < m_display_maxy; y++) |
| 412 | | { |
| 413 | | active_state[y] = 0; |
| 414 | | |
| 415 | | for (int x = 0; x < m_display_maxx; x++) |
| 416 | | { |
| 417 | | // turn on powered segments |
| 418 | | if (m_power_on && m_filament_on && m_display_state[y] >> x & 1) |
| 419 | | m_display_decay[y][x] = m_display_wait; |
| 420 | | |
| 421 | | // determine active state |
| 422 | | int ds = (m_display_decay[y][x] != 0) ? 1 : 0; |
| 423 | | active_state[y] |= (ds << x); |
| 424 | | } |
| 425 | | } |
| 426 | | |
| 427 | | // on difference, send to output |
| 428 | | for (int y = 0; y < m_display_maxy; y++) |
| 429 | | if (m_display_cache[y] != active_state[y]) |
| 430 | | { |
| 431 | | if (m_display_segmask[y] != 0) |
| 432 | | output_set_digit_value(y, active_state[y] & m_display_segmask[y]); |
| 433 | | |
| 434 | | const int mul = (m_display_maxx <= 10) ? 10 : 100; |
| 435 | | for (int x = 0; x < m_display_maxx; x++) |
| 436 | | { |
| 437 | | int state = active_state[y] >> x & 1; |
| 438 | | output_set_lamp_value(y * mul + x, state); |
| 439 | | |
| 440 | | // bit coords for svg2lay |
| 441 | | char buf[10]; |
| 442 | | sprintf(buf, "%d.%d", y, x); |
| 443 | | output_set_value(buf, state); |
| 444 | | } |
| 445 | | } |
| 446 | | |
| 447 | | memcpy(m_display_cache, active_state, sizeof(m_display_cache)); |
| 387 | display_matrix(16, 16, m_o, (m_r & 0x8000) ? (m_r & 0x21ff) : 0); |
| 448 | 388 | } |
| 449 | 389 | |
| 450 | | TIMER_DEVICE_CALLBACK_MEMBER(tispeak_state::display_decay_tick) |
| 451 | | { |
| 452 | | // slowly turn off unpowered segments |
| 453 | | for (int y = 0; y < m_display_maxy; y++) |
| 454 | | for (int x = 0; x < m_display_maxx; x++) |
| 455 | | if (m_display_decay[y][x] != 0) |
| 456 | | m_display_decay[y][x]--; |
| 457 | | |
| 458 | | display_update(); |
| 459 | | } |
| 460 | | |
| 461 | | void tispeak_state::display_matrix_seg(int maxx, int maxy, UINT32 setx, UINT32 sety, UINT16 segmask) |
| 462 | | { |
| 463 | | m_display_maxx = maxx; |
| 464 | | m_display_maxy = maxy; |
| 465 | | |
| 466 | | // update current state |
| 467 | | UINT32 colmask = (1 << maxx) - 1; |
| 468 | | for (int y = 0; y < maxy; y++) |
| 469 | | { |
| 470 | | m_display_segmask[y] &= segmask; |
| 471 | | m_display_state[y] = (sety >> y & 1) ? (setx & colmask) : 0; |
| 472 | | } |
| 473 | | |
| 474 | | display_update(); |
| 475 | | } |
| 476 | | |
| 477 | | |
| 478 | | |
| 479 | | /*************************************************************************** |
| 480 | | |
| 481 | | I/O |
| 482 | | |
| 483 | | ***************************************************************************/ |
| 484 | | |
| 485 | | // common/snspell |
| 486 | | |
| 487 | 390 | READ8_MEMBER(tispeak_state::snspell_read_k) |
| 488 | 391 | { |
| 489 | | // the Vss row is always on |
| 490 | | UINT8 k = m_button_matrix[8]->read(); |
| 491 | | |
| 492 | | // read selected button rows |
| 493 | | for (int i = 0; i < 8; i++) |
| 494 | | if (m_r >> i & 1) |
| 495 | | k |= m_button_matrix[i]->read(); |
| 496 | | |
| 497 | | return k; |
| 392 | // note: the Vss row is always on |
| 393 | return m_inp_matrix[8]->read() | read_inputs(8); |
| 498 | 394 | } |
| 499 | 395 | |
| 500 | 396 | WRITE16_MEMBER(tispeak_state::snspell_write_r) |
| 501 | 397 | { |
| 502 | | // R15: filament on |
| 503 | | m_filament_on = data & 0x8000; |
| 504 | | |
| 505 | 398 | // R13: power-off request, on falling edge |
| 506 | 399 | if ((m_r >> 13 & 1) && !(data >> 13 & 1)) |
| 507 | | power_off(); |
| 400 | snspell_power_off(); |
| 508 | 401 | |
| 509 | 402 | // R0-R7: input mux and select digit (+R8 if the device has 9 digits) |
| 403 | // R15: filament on |
| 510 | 404 | // other bits: MCU internal use |
| 511 | | m_r = data & 0x21ff; |
| 512 | | display_matrix_seg(16, 16, m_o, m_r, 0x3fff); |
| 405 | m_r = m_inp_mux = data; |
| 406 | snspell_display(); |
| 513 | 407 | } |
| 514 | 408 | |
| 515 | 409 | WRITE16_MEMBER(tispeak_state::snspell_write_o) |
| r245222 | r245223 | |
| 517 | 411 | // reorder opla to led14seg, plus DP as d14 and AP as d15: |
| 518 | 412 | // E,D,C,G,B,A,I,M,L,K,N,J,[AP],H,F,[DP] (sidenote: TI KLMN = MAME MLNK) |
| 519 | 413 | m_o = BITSWAP16(data,12,15,10,7,8,9,11,6,13,3,14,0,1,2,4,5); |
| 520 | | display_matrix_seg(16, 16, m_o, m_r, 0x3fff); |
| 414 | snspell_display(); |
| 521 | 415 | } |
| 522 | 416 | |
| 523 | 417 | |
| 524 | | void tispeak_state::power_off() |
| 418 | void tispeak_state::snspell_power_off() |
| 525 | 419 | { |
| 526 | 420 | m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); |
| 527 | 421 | m_tms5100->reset(); |
| 528 | 422 | m_tms6100->reset(); |
| 529 | 423 | |
| 530 | | m_power_on = 0; |
| 424 | m_power_on = false; |
| 531 | 425 | } |
| 532 | 426 | |
| 533 | 427 | |
| r245222 | r245223 | |
| 538 | 432 | // reorder opla to led14seg, plus DP as d14 and AP as d15: |
| 539 | 433 | // [DP],D,C,H,F,B,I,M,L,K,N,J,[AP],E,G,A (sidenote: TI KLMN = MAME MLNK) |
| 540 | 434 | m_o = BITSWAP16(data,12,0,10,7,8,9,11,6,3,14,4,13,1,2,5,15); |
| 541 | | display_matrix_seg(16, 16, m_o, m_r, 0x3fff); |
| 435 | snspell_display(); |
| 542 | 436 | } |
| 543 | 437 | |
| 544 | 438 | |
| r245222 | r245223 | |
| 547 | 441 | WRITE16_MEMBER(tispeak_state::lantutor_write_r) |
| 548 | 442 | { |
| 549 | 443 | // same as default, except R13 is used for an extra digit |
| 550 | | m_filament_on = data & 0x8000; |
| 551 | | m_r = data & 0x21ff; |
| 552 | | display_matrix_seg(16, 16, m_o, m_r, 0x3fff); |
| 444 | m_r = m_inp_mux = data; |
| 445 | snspell_display(); |
| 553 | 446 | } |
| 554 | 447 | |
| 555 | 448 | |
| r245222 | r245223 | |
| 560 | 453 | |
| 561 | 454 | ***************************************************************************/ |
| 562 | 455 | |
| 563 | | INPUT_CHANGED_MEMBER(tispeak_state::power_button) |
| 456 | INPUT_CHANGED_MEMBER(tispeak_state::snspell_power_button) |
| 564 | 457 | { |
| 565 | 458 | int on = (int)(FPTR)param; |
| 566 | 459 | |
| 567 | 460 | if (on && !m_power_on) |
| 568 | 461 | { |
| 569 | | m_power_on = 1; |
| 462 | m_power_on = true; |
| 570 | 463 | m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); |
| 571 | 464 | } |
| 572 | 465 | else if (!on && m_power_on) |
| 573 | | power_off(); |
| 466 | snspell_power_off(); |
| 574 | 467 | } |
| 575 | 468 | |
| 576 | 469 | static INPUT_PORTS_START( snspell ) |
| r245222 | r245223 | |
| 631 | 524 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_NAME("Secret Code") |
| 632 | 525 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_NAME("Letter") |
| 633 | 526 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_NAME("Say It") |
| 634 | | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CODE(KEYCODE_PGUP) PORT_NAME("Spell/On") PORT_CHANGED_MEMBER(DEVICE_SELF, tispeak_state, power_button, (void *)1) |
| 527 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CODE(KEYCODE_PGUP) PORT_NAME("Spell/On") PORT_CHANGED_MEMBER(DEVICE_SELF, tispeak_state, snspell_power_button, (void *)true) |
| 635 | 528 | INPUT_PORTS_END |
| 636 | 529 | |
| 637 | 530 | |
| r245222 | r245223 | |
| 683 | 576 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_NAME("Write It") |
| 684 | 577 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_NAME("Greater/Less") |
| 685 | 578 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_NAME("Word Problems") |
| 686 | | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CODE(KEYCODE_PGUP) PORT_NAME("Solve It/On") PORT_CHANGED_MEMBER(DEVICE_SELF, tispeak_state, power_button, (void *)1) |
| 579 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CODE(KEYCODE_PGUP) PORT_NAME("Solve It/On") PORT_CHANGED_MEMBER(DEVICE_SELF, tispeak_state, snspell_power_button, (void *)true) |
| 687 | 580 | |
| 688 | 581 | PORT_START("IN.7") |
| 689 | 582 | PORT_BIT( 0x1f, IP_ACTIVE_HIGH, IPT_UNUSED ) |
| r245222 | r245223 | |
| 705 | 598 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_NAME("Picture Read") |
| 706 | 599 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_NAME("Letter Stumper") |
| 707 | 600 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_NAME("Hear It") |
| 708 | | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CODE(KEYCODE_PGUP) PORT_NAME("Word Zap/On") PORT_CHANGED_MEMBER(DEVICE_SELF, tispeak_state, power_button, (void *)1) |
| 601 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CODE(KEYCODE_PGUP) PORT_NAME("Word Zap/On") PORT_CHANGED_MEMBER(DEVICE_SELF, tispeak_state, snspell_power_button, (void *)true) |
| 709 | 602 | INPUT_PORTS_END |
| 710 | 603 | |
| 711 | 604 | |
| r245222 | r245223 | |
| 746 | 639 | |
| 747 | 640 | ***************************************************************************/ |
| 748 | 641 | |
| 749 | | void tispeak_state::machine_reset() |
| 750 | | { |
| 751 | | m_power_on = 1; |
| 752 | | } |
| 753 | | |
| 754 | 642 | void tispeak_state::machine_start() |
| 755 | 643 | { |
| 756 | | // zerofill |
| 757 | | memset(m_display_state, 0, sizeof(m_display_state)); |
| 758 | | memset(m_display_cache, ~0, sizeof(m_display_cache)); |
| 759 | | memset(m_display_decay, 0, sizeof(m_display_decay)); |
| 760 | | memset(m_display_segmask, ~0, sizeof(m_display_segmask)); // ! |
| 644 | hh_tms1k_state::machine_start(); |
| 761 | 645 | |
| 762 | | m_r = 0; |
| 763 | | m_o = 0; |
| 764 | | m_power_on = 0; |
| 765 | | m_filament_on = 0; |
| 766 | | |
| 767 | | // register for savestates |
| 768 | | save_item(NAME(m_display_maxy)); |
| 769 | | save_item(NAME(m_display_maxx)); |
| 770 | | save_item(NAME(m_display_wait)); |
| 771 | | |
| 772 | | save_item(NAME(m_display_state)); |
| 773 | | /* save_item(NAME(m_display_cache)); */ // don't save! |
| 774 | | save_item(NAME(m_display_decay)); |
| 775 | | save_item(NAME(m_display_segmask)); |
| 776 | | |
| 777 | | save_item(NAME(m_r)); |
| 778 | | save_item(NAME(m_o)); |
| 779 | | save_item(NAME(m_power_on)); |
| 780 | | save_item(NAME(m_filament_on)); |
| 781 | | |
| 782 | 646 | // init cartridge |
| 783 | 647 | if (m_cart != NULL && m_cart->exists()) |
| 784 | 648 | { |
| r245222 | r245223 | |
| 802 | 666 | MCFG_TMS0270_WRITE_CTL_CB(DEVWRITE8("tms5100", tms5100_device, ctl_w)) |
| 803 | 667 | MCFG_TMS0270_WRITE_PDC_CB(DEVWRITELINE("tms5100", tms5100_device, pdc_w)) |
| 804 | 668 | |
| 805 | | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", tispeak_state, display_decay_tick, attotime::from_msec(1)) |
| 669 | MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_tms1k_state, display_decay_tick, attotime::from_msec(1)) |
| 806 | 670 | MCFG_DEFAULT_LAYOUT(layout_snspell) // max 9 digits |
| 807 | 671 | |
| 808 | 672 | /* no video! */ |