trunk/src/mess/drivers/laser3k.c
| r31632 | r31633 | |
| 20 | 20 | http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Computers/LASER/LASER%203000/Manuals/The%20Cat%20Technical%20Reference%20Manual.pdf |
| 21 | 21 | |
| 22 | 22 | TODO: |
| 23 | | - keyboard |
| 24 | | - graphics modes |
| 25 | | - 80-column text |
| 26 | | - figure out where the C800 ROM pages for the printer and FDC are (currently the 80-col f/w's pages are mapped there) |
| 23 | - Finish keyboard |
| 24 | - RGB graphics mode |
| 25 | - FDC C800 page appears to be inside the FDC cartridge, need a dump :( (can hack to use IWM in the meantime) |
| 27 | 26 | - Centronics printer port (data at 3c090, read ack at 3c1c0, read busy at 3c1c2) |
| 27 | - cassette |
| 28 | 28 | |
| 29 | 29 | ***************************************************************************/ |
| 30 | 30 | |
| r31632 | r31633 | |
| 32 | 32 | #include "cpu/m6502/m6502.h" |
| 33 | 33 | #include "machine/bankdev.h" |
| 34 | 34 | #include "machine/ram.h" |
| 35 | #include "machine/kb3600.h" |
| 35 | 36 | #include "sound/speaker.h" |
| 36 | 37 | #include "sound/sn76496.h" |
| 37 | 38 | |
| 39 | enum |
| 40 | { |
| 41 | TEXT = 0, |
| 42 | HIRES, |
| 43 | RGB, |
| 44 | DHIRES |
| 45 | }; |
| 46 | |
| 47 | #define BLACK 0 |
| 48 | #define DKRED 1 |
| 49 | #define DKBLUE 2 |
| 50 | #define PURPLE 3 |
| 51 | #define DKGREEN 4 |
| 52 | #define DKGRAY 5 |
| 53 | #define BLUE 6 |
| 54 | #define LTBLUE 7 |
| 55 | #define BROWN 8 |
| 56 | #define ORANGE 9 |
| 57 | #define GRAY 10 |
| 58 | #define PINK 11 |
| 59 | #define GREEN 12 |
| 60 | #define YELLOW 13 |
| 61 | #define AQUA 14 |
| 62 | #define WHITE 15 |
| 63 | |
| 38 | 64 | class laser3k_state : public driver_device |
| 39 | 65 | { |
| 40 | 66 | public: |
| r31632 | r31633 | |
| 46 | 72 | , m_bank1(*this, "bank1") |
| 47 | 73 | , m_bank2(*this, "bank2") |
| 48 | 74 | , m_bank3(*this, "bank3") |
| 75 | , m_ay3600(*this, "ay3600") |
| 49 | 76 | , m_speaker(*this, "speaker") |
| 50 | 77 | , m_sn(*this, "sn76489") |
| 78 | , m_kbspecial(*this, "keyb_special") |
| 51 | 79 | { } |
| 52 | 80 | |
| 53 | 81 | required_device<m6502_device> m_maincpu; |
| r31632 | r31633 | |
| 56 | 84 | required_device<address_map_bank_device> m_bank1; |
| 57 | 85 | required_device<address_map_bank_device> m_bank2; |
| 58 | 86 | required_device<address_map_bank_device> m_bank3; |
| 87 | required_device<ay3600_device> m_ay3600; |
| 59 | 88 | required_device<speaker_sound_device> m_speaker; |
| 60 | 89 | required_device<sn76489_device> m_sn; |
| 90 | required_ioport m_kbspecial; |
| 61 | 91 | |
| 62 | 92 | READ8_MEMBER( ram_r ); |
| 63 | 93 | WRITE8_MEMBER( ram_w ); |
| r31632 | r31633 | |
| 65 | 95 | WRITE8_MEMBER( io_w ); |
| 66 | 96 | READ8_MEMBER( io2_r ); |
| 67 | 97 | |
| 98 | virtual void machine_start(); |
| 68 | 99 | virtual void machine_reset(); |
| 69 | 100 | DECLARE_PALETTE_INIT(laser3k); |
| 70 | 101 | UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); |
| 102 | void text_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow); |
| 103 | void hgr_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow); |
| 104 | void dhgr_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow); |
| 71 | 105 | |
| 106 | DECLARE_READ_LINE_MEMBER(ay3600_shift_r); |
| 107 | DECLARE_READ_LINE_MEMBER(ay3600_control_r); |
| 108 | DECLARE_WRITE_LINE_MEMBER(ay3600_data_ready_w); |
| 109 | |
| 72 | 110 | private: |
| 73 | 111 | UINT8 m_bank0val, m_bank1val, m_bank2val, m_bank3val; |
| 74 | 112 | int m_flash; |
| 75 | 113 | int m_speaker_state; |
| 76 | 114 | int m_disp_page; |
| 77 | | int m_bg_color; |
| 115 | int m_bg_color, m_fg_color, m_border_color; |
| 116 | UINT16 m_lastchar, m_strobe; |
| 117 | UINT8 m_transchar; |
| 118 | bool m_80col; |
| 119 | bool m_mix; |
| 120 | int m_gfxmode; |
| 121 | UINT16 *m_hires_artifact_map; |
| 122 | UINT16 *m_dhires_artifact_map; |
| 78 | 123 | |
| 79 | 124 | void plot_text_character(bitmap_ind16 &bitmap, int xpos, int ypos, int xscale, UINT32 code, const UINT8 *textgfx_data, UINT32 textgfx_datalen); |
| 125 | void do_io(int offset); |
| 80 | 126 | }; |
| 81 | 127 | |
| 82 | 128 | /*************************************************************************** |
| r31632 | r31633 | |
| 98 | 144 | AM_RANGE(0x3c200, 0x3ffff) AM_ROM AM_REGION("maincpu", 0x4200) |
| 99 | 145 | ADDRESS_MAP_END |
| 100 | 146 | |
| 147 | void laser3k_state::machine_start() |
| 148 | { |
| 149 | static const UINT8 hires_artifact_color_table[] = |
| 150 | { |
| 151 | BLACK, PURPLE, GREEN, WHITE, |
| 152 | BLACK, BLUE, ORANGE, WHITE |
| 153 | }; |
| 154 | |
| 155 | static const UINT8 dhires_artifact_color_table[] = |
| 156 | { |
| 157 | BLACK, DKGREEN, BROWN, GREEN, |
| 158 | DKRED, DKGRAY, ORANGE, YELLOW, |
| 159 | DKBLUE, BLUE, GRAY, AQUA, |
| 160 | PURPLE, LTBLUE, PINK, WHITE |
| 161 | }; |
| 162 | int i, j; |
| 163 | UINT16 c; |
| 164 | |
| 165 | /* 2^3 dependent pixels * 2 color sets * 2 offsets */ |
| 166 | m_hires_artifact_map = auto_alloc_array(machine(), UINT16, 8 * 2 * 2); |
| 167 | |
| 168 | /* 2^4 dependent pixels */ |
| 169 | m_dhires_artifact_map = auto_alloc_array(machine(), UINT16, 16); |
| 170 | |
| 171 | /* build hires artifact map */ |
| 172 | for (i = 0; i < 8; i++) |
| 173 | { |
| 174 | for (j = 0; j < 2; j++) |
| 175 | { |
| 176 | if (i & 0x02) |
| 177 | { |
| 178 | if ((i & 0x05) != 0) |
| 179 | c = 3; |
| 180 | else |
| 181 | c = j ? 2 : 1; |
| 182 | } |
| 183 | else |
| 184 | { |
| 185 | if ((i & 0x05) == 0x05) |
| 186 | c = j ? 1 : 2; |
| 187 | else |
| 188 | c = 0; |
| 189 | } |
| 190 | m_hires_artifact_map[ 0 + j*8 + i] = hires_artifact_color_table[(c + 0) % 8]; |
| 191 | m_hires_artifact_map[16 + j*8 + i] = hires_artifact_color_table[(c + 4) % 8]; |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | /* build double hires artifact map */ |
| 196 | for (i = 0; i < 16; i++) |
| 197 | { |
| 198 | m_dhires_artifact_map[i] = dhires_artifact_color_table[i]; |
| 199 | } |
| 200 | } |
| 201 | |
| 101 | 202 | void laser3k_state::machine_reset() |
| 102 | 203 | { |
| 103 | 204 | m_bank0val = 0; |
| r31632 | r31633 | |
| 117 | 218 | m_speaker_state = 0; |
| 118 | 219 | m_disp_page = 0; |
| 119 | 220 | m_bg_color = 0; |
| 221 | m_fg_color = 15; |
| 222 | m_border_color = 0; |
| 223 | m_strobe = 0; |
| 224 | m_transchar = 0; |
| 225 | m_lastchar = 0; |
| 226 | m_80col = 0; |
| 227 | m_mix = false; |
| 228 | m_gfxmode = TEXT; |
| 120 | 229 | |
| 121 | 230 | UINT8 *rom = (UINT8 *)memregion("maincpu")->base(); |
| 122 | 231 | |
| r31632 | r31633 | |
| 134 | 243 | m_ram->write(offset, data); |
| 135 | 244 | } |
| 136 | 245 | |
| 137 | | READ8_MEMBER( laser3k_state::io_r ) |
| 246 | // most softswitches don't care about read vs write, so handle them here |
| 247 | void laser3k_state::do_io(int offset) |
| 138 | 248 | { |
| 139 | 249 | switch (offset) |
| 140 | 250 | { |
| 141 | | case 0x00: // keyboard latch |
| 142 | | return 0x00; |
| 143 | | |
| 144 | 251 | case 0x08: // set border color to black |
| 252 | m_border_color = 0; |
| 145 | 253 | break; |
| 254 | case 0x09: // set border color to red |
| 255 | m_border_color = 1; |
| 256 | break; |
| 257 | case 0x0a: // set border color to green |
| 258 | m_border_color = 12; |
| 259 | break; |
| 260 | case 0x0b: // set border color to yellow |
| 261 | m_border_color = 13; |
| 262 | break; |
| 263 | case 0x0c: // set border color to blue |
| 264 | m_border_color = 6; |
| 265 | break; |
| 266 | case 0x0d: // set border color to magenta |
| 267 | m_border_color = 3; |
| 268 | break; |
| 269 | case 0x0e: // set border color to cyan |
| 270 | m_border_color = 14; |
| 271 | break; |
| 272 | case 0x0f: // set border color to white |
| 273 | m_border_color = 15; |
| 274 | break; |
| 146 | 275 | |
| 147 | | case 0x10: // keyboard strobe |
| 148 | | return 0x00; |
| 149 | | |
| 150 | 276 | case 0x18: // set bg color to black |
| 151 | 277 | m_bg_color = 0; |
| 152 | 278 | break; |
| r31632 | r31633 | |
| 172 | 298 | m_bg_color = 15; |
| 173 | 299 | break; |
| 174 | 300 | |
| 175 | | case 0x28: // "enable multi-color mode" - not sure what this means |
| 301 | case 0x28: // set fg color to normal |
| 302 | m_fg_color = 15; |
| 176 | 303 | break; |
| 177 | | |
| 178 | | case 0x4c: // low resolution (40 column) |
| 304 | case 0x29: // set fg color to red |
| 305 | m_fg_color = 1; |
| 179 | 306 | break; |
| 307 | case 0x2a: // set fg color to green |
| 308 | m_fg_color = 12; |
| 309 | break; |
| 310 | case 0x2b: // set fg color to yellow |
| 311 | m_fg_color = 13; |
| 312 | break; |
| 313 | case 0x2c: // set fg color to blue |
| 314 | m_fg_color = 6; |
| 315 | break; |
| 316 | case 0x2d: // set fg color to magenta |
| 317 | m_fg_color = 3; |
| 318 | break; |
| 319 | case 0x2e: // set fg color to cyan |
| 320 | m_fg_color = 14; |
| 321 | break; |
| 322 | case 0x2f: // set fg color to white |
| 323 | m_fg_color = 15; |
| 324 | break; |
| 180 | 325 | |
| 181 | 326 | case 0x30: |
| 182 | 327 | m_speaker_state ^= 1; |
| 183 | 328 | m_speaker->level_w(m_speaker_state); |
| 184 | 329 | break; |
| 185 | 330 | |
| 331 | case 0x4c: // low resolution (40 column) |
| 332 | m_80col = false; |
| 333 | m_maincpu->set_unscaled_clock(1021800); |
| 334 | break; |
| 335 | |
| 336 | case 0x4d: // RGB mode |
| 337 | m_gfxmode = RGB; |
| 338 | break; |
| 339 | |
| 340 | case 0x4e: // double hi-res |
| 341 | m_80col = true; |
| 342 | m_gfxmode = DHIRES; |
| 343 | m_maincpu->set_unscaled_clock(1021800*2); |
| 344 | break; |
| 345 | |
| 346 | case 0x4f: // high resolution (80 column). Yes, the CPU clock also doubles when the pixel clock does (!) |
| 347 | m_80col = true; |
| 348 | m_maincpu->set_unscaled_clock(1021800*2); |
| 349 | break; |
| 350 | |
| 351 | case 0x50: // graphics mode |
| 352 | m_gfxmode = HIRES; |
| 353 | break; |
| 354 | |
| 186 | 355 | case 0x51: // text mode |
| 356 | m_gfxmode = TEXT; |
| 187 | 357 | break; |
| 188 | 358 | |
| 359 | case 0x52: // no mix |
| 360 | m_mix = false; |
| 361 | break; |
| 362 | |
| 363 | case 0x53: // mixed mode |
| 364 | m_mix = true; |
| 365 | break; |
| 366 | |
| 189 | 367 | case 0x54: // set page 1 |
| 190 | 368 | m_disp_page = 0; |
| 191 | 369 | break; |
| r31632 | r31633 | |
| 197 | 375 | case 0x56: // disable emulation (?) |
| 198 | 376 | break; |
| 199 | 377 | |
| 378 | default: |
| 379 | printf("do_io: unknown softswitch @ %x\n", offset); |
| 380 | break; |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | READ8_MEMBER( laser3k_state::io_r ) |
| 385 | { |
| 386 | switch (offset) |
| 387 | { |
| 388 | case 0x00: // keyboard latch |
| 389 | return m_transchar | m_strobe; |
| 390 | |
| 391 | case 0x10: // keyboard strobe |
| 392 | { |
| 393 | UINT8 rv = m_transchar | m_strobe; |
| 394 | m_strobe = 0; |
| 395 | return rv; |
| 396 | } |
| 397 | break; |
| 398 | |
| 200 | 399 | case 0x7c: |
| 201 | 400 | return m_bank0val; |
| 202 | 401 | |
| r31632 | r31633 | |
| 210 | 409 | return m_bank3val; |
| 211 | 410 | |
| 212 | 411 | default: |
| 213 | | printf("io_r @ unknown %x\n", offset); |
| 412 | do_io(offset); |
| 214 | 413 | break; |
| 215 | 414 | } |
| 216 | 415 | |
| r31632 | r31633 | |
| 222 | 421 | switch (offset) |
| 223 | 422 | { |
| 224 | 423 | case 0x10: // clear keyboard latch |
| 424 | m_strobe = 0; |
| 225 | 425 | break; |
| 226 | 426 | |
| 227 | | case 0x30: // speaker toggle sound |
| 228 | | m_speaker_state ^= 1; |
| 229 | | m_speaker->level_w(m_speaker_state); |
| 230 | | break; |
| 231 | | |
| 232 | | case 0x4c: // low resolution |
| 233 | | break; |
| 234 | | |
| 235 | 427 | case 0x68: // SN76489 sound |
| 236 | 428 | m_sn->write(space, 0, data); |
| 237 | 429 | break; |
| r31632 | r31633 | |
| 240 | 432 | break; |
| 241 | 433 | |
| 242 | 434 | case 0x7c: // bank 0 |
| 243 | | m_bank0val = data; |
| 435 | m_bank0val = data & 0xf; |
| 244 | 436 | m_bank0->set_bank(m_bank0val); |
| 245 | 437 | break; |
| 246 | 438 | |
| 247 | 439 | case 0x7d: // bank 1 |
| 248 | | m_bank1val = data; |
| 440 | m_bank1val = data & 0xf; |
| 249 | 441 | m_bank1->set_bank(m_bank1val); |
| 250 | 442 | break; |
| 251 | 443 | |
| 252 | 444 | case 0x7e: // bank 2 |
| 253 | | m_bank2val = data; |
| 445 | m_bank2val = data & 0xf; |
| 254 | 446 | m_bank2->set_bank(m_bank2val); |
| 255 | 447 | break; |
| 256 | 448 | |
| 257 | 449 | case 0x7f: // bank 3 |
| 258 | | m_bank3val = data; |
| 450 | m_bank3val = data & 0xf; |
| 259 | 451 | m_bank3->set_bank(m_bank3val); |
| 260 | 452 | break; |
| 261 | 453 | |
| 262 | 454 | default: |
| 263 | | printf("io_w %02x @ unknown %x\n", data, offset); |
| 455 | do_io(offset); |
| 264 | 456 | break; |
| 265 | 457 | } |
| 266 | 458 | } |
| r31632 | r31633 | |
| 290 | 482 | const UINT8 *textgfx_data, UINT32 textgfx_datalen) |
| 291 | 483 | { |
| 292 | 484 | int x, y, i; |
| 293 | | int fg = 15; |
| 485 | int fg = m_fg_color; |
| 294 | 486 | int bg = m_bg_color; |
| 295 | 487 | const UINT8 *chardata; |
| 296 | 488 | UINT16 color; |
| r31632 | r31633 | |
| 320 | 512 | } |
| 321 | 513 | } |
| 322 | 514 | |
| 323 | | UINT32 laser3k_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) |
| 515 | void laser3k_state::text_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow) |
| 324 | 516 | { |
| 325 | 517 | int row, col; |
| 326 | | UINT32 start_address = (m_disp_page == 0) ? 0x400 : 0x800; |
| 518 | UINT32 start_address; |
| 327 | 519 | UINT32 address; |
| 328 | 520 | UINT8 *m_a2_videoram = m_ram->pointer(); |
| 329 | | int beginrow = 0, endrow = 191; |
| 330 | 521 | |
| 522 | if (m_80col) |
| 523 | { |
| 524 | start_address = (m_disp_page == 0) ? 0x1000 : 0x1800; |
| 525 | } |
| 526 | else |
| 527 | { |
| 528 | start_address = (m_disp_page == 0) ? 0x400 : 0x800; |
| 529 | } |
| 530 | |
| 331 | 531 | m_flash = ((machine().time() * 4).seconds & 1) ? 1 : 0; |
| 332 | 532 | |
| 333 | 533 | beginrow = MAX(beginrow, cliprect.min_y - (cliprect.min_y % 8)); |
| r31632 | r31633 | |
| 335 | 535 | |
| 336 | 536 | for (row = beginrow; row <= endrow; row += 8) |
| 337 | 537 | { |
| 538 | if (m_80col) |
| 539 | { |
| 540 | for (col = 0; col < 40; col++) |
| 541 | { |
| 542 | /* calculate address */ |
| 543 | address = start_address + ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)); |
| 544 | |
| 545 | plot_text_character(bitmap, col * 7, row, 1, m_a2_videoram[address], |
| 546 | memregion("gfx1")->base(), memregion("gfx1")->bytes()); |
| 547 | plot_text_character(bitmap, (col + 40) * 7, row, 1, m_a2_videoram[address+0x400], |
| 548 | memregion("gfx1")->base(), memregion("gfx1")->bytes()); |
| 549 | } |
| 550 | } |
| 551 | else |
| 552 | { |
| 553 | for (col = 0; col < 40; col++) |
| 554 | { |
| 555 | /* calculate address */ |
| 556 | address = start_address + ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)); |
| 557 | plot_text_character(bitmap, col * 14, row, 2, m_a2_videoram[address], |
| 558 | memregion("gfx1")->base(), memregion("gfx1")->bytes()); |
| 559 | } |
| 560 | } |
| 561 | } |
| 562 | } |
| 563 | |
| 564 | void laser3k_state::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow) |
| 565 | { |
| 566 | const UINT8 *vram; |
| 567 | int row, col, b; |
| 568 | int offset; |
| 569 | UINT8 vram_row[42] ; |
| 570 | UINT16 v; |
| 571 | UINT16 *p; |
| 572 | UINT32 w; |
| 573 | UINT16 *artifact_map_ptr; |
| 574 | |
| 575 | /* sanity checks */ |
| 576 | if (beginrow < cliprect.min_y) |
| 577 | beginrow = cliprect.min_y; |
| 578 | if (endrow > cliprect.max_y) |
| 579 | endrow = cliprect.max_y; |
| 580 | if (endrow < beginrow) |
| 581 | return; |
| 582 | |
| 583 | vram = m_ram->pointer() + (m_disp_page ? 0x4000 : 0x2000); |
| 584 | |
| 585 | vram_row[0] = 0; |
| 586 | vram_row[41] = 0; |
| 587 | |
| 588 | for (row = beginrow; row <= endrow; row++) |
| 589 | { |
| 338 | 590 | for (col = 0; col < 40; col++) |
| 339 | 591 | { |
| 340 | | /* calculate address */ |
| 341 | | address = start_address + ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)); |
| 592 | offset = ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)) | ((row & 7) << 10); |
| 593 | vram_row[1+col] = vram[offset]; |
| 594 | } |
| 342 | 595 | |
| 343 | | plot_text_character(bitmap, col * 14, row, 2, m_a2_videoram[address], |
| 344 | | memregion("gfx1")->base(), memregion("gfx1")->bytes()); |
| 596 | p = &bitmap.pix16(row); |
| 597 | |
| 598 | for (col = 0; col < 40; col++) |
| 599 | { |
| 600 | w = (((UINT32) vram_row[col+0] & 0x7f) << 0) |
| 601 | | (((UINT32) vram_row[col+1] & 0x7f) << 7) |
| 602 | | (((UINT32) vram_row[col+2] & 0x7f) << 14); |
| 603 | |
| 604 | artifact_map_ptr = &m_hires_artifact_map[((vram_row[col+1] & 0x80) >> 7) * 16]; |
| 605 | for (b = 0; b < 7; b++) |
| 606 | { |
| 607 | v = artifact_map_ptr[((w >> (b + 7-1)) & 0x07) | (((b ^ col) & 0x01) << 3)]; |
| 608 | *(p++) = v; |
| 609 | *(p++) = v; |
| 610 | } |
| 345 | 611 | } |
| 346 | 612 | } |
| 613 | } |
| 347 | 614 | |
| 615 | void laser3k_state::dhgr_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow) |
| 616 | { |
| 617 | const UINT8 *vram; |
| 618 | int row, col, b; |
| 619 | int offset; |
| 620 | UINT8 vram_row[82]; |
| 621 | UINT16 v; |
| 622 | UINT16 *p; |
| 623 | UINT32 w; |
| 624 | |
| 625 | /* sanity checks */ |
| 626 | if (beginrow < cliprect.min_y) |
| 627 | beginrow = cliprect.min_y; |
| 628 | if (endrow > cliprect.max_y) |
| 629 | endrow = cliprect.max_y; |
| 630 | if (endrow < beginrow) |
| 631 | return; |
| 632 | |
| 633 | vram = m_ram->pointer() + (m_disp_page ? 0x8000 : 0x4000); |
| 634 | |
| 635 | vram_row[0] = 0; |
| 636 | vram_row[81] = 0; |
| 637 | |
| 638 | for (row = beginrow; row <= endrow; row++) |
| 639 | { |
| 640 | for (col = 0; col < 40; col++) |
| 641 | { |
| 642 | offset = ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)) | ((row & 7) << 10); |
| 643 | if (col < 40) |
| 644 | { |
| 645 | vram_row[1+(col*2)+0] = vram[offset]; |
| 646 | vram_row[1+(col*2)+1] = vram[offset+1]; |
| 647 | } |
| 648 | else |
| 649 | { |
| 650 | vram_row[1+(col*2)+0] = vram[offset+0x2000]; |
| 651 | vram_row[1+(col*2)+1] = vram[offset+0x2001]; |
| 652 | } |
| 653 | } |
| 654 | |
| 655 | p = &bitmap.pix16(row); |
| 656 | |
| 657 | for (col = 0; col < 80; col++) |
| 658 | { |
| 659 | w = (((UINT32) vram_row[col+0] & 0x7f) << 0) |
| 660 | | (((UINT32) vram_row[col+1] & 0x7f) << 7) |
| 661 | | (((UINT32) vram_row[col+2] & 0x7f) << 14); |
| 662 | |
| 663 | for (b = 0; b < 7; b++) |
| 664 | { |
| 665 | v = m_dhires_artifact_map[((((w >> (b + 7-1)) & 0x0F) * 0x11) >> (((2-(col*7+b))) & 0x03)) & 0x0F]; |
| 666 | *(p++) = v; |
| 667 | } |
| 668 | } |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | UINT32 laser3k_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) |
| 673 | { |
| 674 | switch (m_gfxmode) |
| 675 | { |
| 676 | case TEXT: |
| 677 | text_update(screen, bitmap, cliprect, 0, 191); |
| 678 | break; |
| 679 | |
| 680 | case HIRES: |
| 681 | if (m_mix) |
| 682 | { |
| 683 | hgr_update(screen, bitmap, cliprect, 0, 159); |
| 684 | text_update(screen, bitmap, cliprect, 160, 191); |
| 685 | } |
| 686 | else |
| 687 | { |
| 688 | hgr_update(screen, bitmap, cliprect, 0, 191); |
| 689 | } |
| 690 | break; |
| 691 | |
| 692 | case RGB: |
| 693 | break; |
| 694 | |
| 695 | case DHIRES: |
| 696 | if (m_mix) |
| 697 | { |
| 698 | dhgr_update(screen, bitmap, cliprect, 0, 159); |
| 699 | text_update(screen, bitmap, cliprect, 160, 191); |
| 700 | } |
| 701 | else |
| 702 | { |
| 703 | dhgr_update(screen, bitmap, cliprect, 0, 191); |
| 704 | } |
| 705 | break; |
| 706 | } |
| 707 | |
| 348 | 708 | return 0; |
| 349 | 709 | } |
| 350 | 710 | |
| 711 | READ_LINE_MEMBER(laser3k_state::ay3600_shift_r) |
| 712 | { |
| 713 | // either shift key |
| 714 | if (m_kbspecial->read() & 0x06) |
| 715 | { |
| 716 | return ASSERT_LINE; |
| 717 | } |
| 718 | |
| 719 | return CLEAR_LINE; |
| 720 | } |
| 721 | |
| 722 | READ_LINE_MEMBER(laser3k_state::ay3600_control_r) |
| 723 | { |
| 724 | if (m_kbspecial->read() & 0x08) |
| 725 | { |
| 726 | return ASSERT_LINE; |
| 727 | } |
| 728 | |
| 729 | return CLEAR_LINE; |
| 730 | } |
| 731 | |
| 732 | static const UINT8 key_remap[0x32][4] = |
| 733 | { |
| 734 | /* norm shft ctrl both */ |
| 735 | { 0x33,0x23,0x33,0x23 }, /* 3 # 00 */ |
| 736 | { 0x34,0x24,0x34,0x24 }, /* 4 $ 01 */ |
| 737 | { 0x35,0x25,0x35,0x25 }, /* 5 % 02 */ |
| 738 | { 0x36,0x5e,0x35,0x53 }, /* 6 ^ 03 */ |
| 739 | { 0x37,0x26,0x37,0x26 }, /* 7 & 04 */ |
| 740 | { 0x38,0x2a,0x38,0x2a }, /* 8 * 05 */ |
| 741 | { 0x39,0x28,0x39,0x28 }, /* 9 ( 06 */ |
| 742 | { 0x30,0x29,0x30,0x29 }, /* 0 ) 07 */ |
| 743 | { 0x3b,0x3a,0x3b,0x3a }, /* ; : 08 */ |
| 744 | { 0x2d,0x5f,0x2d,0x1f }, /* - _ 09 */ |
| 745 | { 0x51,0x51,0x11,0x11 }, /* q Q 0a */ |
| 746 | { 0x57,0x57,0x17,0x17 }, /* w W 0b */ |
| 747 | { 0x45,0x45,0x05,0x05 }, /* e E 0c */ |
| 748 | { 0x52,0x52,0x12,0x12 }, /* r R 0d */ |
| 749 | { 0x54,0x54,0x14,0x14 }, /* t T 0e */ |
| 750 | { 0x59,0x59,0x19,0x19 }, /* y Y 0f */ |
| 751 | { 0x55,0x55,0x15,0x15 }, /* u U 10 */ |
| 752 | { 0x49,0x49,0x09,0x09 }, /* i I 11 */ |
| 753 | { 0x4f,0x4f,0x0f,0x0f }, /* o O 12 */ |
| 754 | { 0x50,0x50,0x10,0x10 }, /* p P 13 */ |
| 755 | { 0x44,0x44,0x04,0x04 }, /* d D 14 */ |
| 756 | { 0x46,0x46,0x06,0x06 }, /* f F 15 */ |
| 757 | { 0x47,0x47,0x07,0x07 }, /* g G 16 */ |
| 758 | { 0x48,0x48,0x08,0x08 }, /* h H 17 */ |
| 759 | { 0x4a,0x4a,0x0a,0x0a }, /* j J 18 */ |
| 760 | { 0x4b,0x4b,0x0b,0x0b }, /* k K 19 */ |
| 761 | { 0x4c,0x4c,0x0c,0x0c }, /* l L 1a */ |
| 762 | { 0x3d,0x2b,0x3d,0x2b }, /* = + 1b */ |
| 763 | { 0x08,0x08,0x08,0x08 }, /* Left 1c */ |
| 764 | { 0x15,0x15,0x15,0x15 }, /* Right 1d */ |
| 765 | { 0x5a,0x5a,0x1a,0x1a }, /* z Z 1e */ |
| 766 | { 0x58,0x58,0x18,0x18 }, /* x X 1f */ |
| 767 | { 0x43,0x43,0x03,0x03 }, /* c C 20 */ |
| 768 | { 0x56,0x56,0x16,0x16 }, /* v V 21 */ |
| 769 | { 0x42,0x42,0x02,0x02 }, /* b B 22 */ |
| 770 | { 0x4e,0x4e,0x0e,0x0e }, /* n N 23 */ |
| 771 | { 0x4d,0x4d,0x0d,0x0d }, /* m M 24 */ |
| 772 | { 0x2c,0x3c,0x2c,0x3c }, /* , < 25 */ |
| 773 | { 0x2e,0x3e,0x2e,0x3e }, /* . > 26 */ |
| 774 | { 0x2f,0x3f,0x2f,0x3f }, /* / ? 27 */ |
| 775 | { 0x53,0x53,0x13,0x13 }, /* s S 28 */ |
| 776 | { 0x32,0x40,0x32,0x00 }, /* 2 @ 29 */ |
| 777 | { 0x31,0x21,0x31,0x31 }, /* 1 ! 2a */ |
| 778 | { 0x9b,0x9b,0x9b,0x9b }, /* Escape 2b */ |
| 779 | { 0x41,0x41,0x01,0x01 }, /* a A 2c */ |
| 780 | { 0x20,0x20,0x20,0x20 }, /* Space 2d */ |
| 781 | { 0x27,0x22,0x27,0x22 }, /* ' " 2e */ |
| 782 | { 0x00,0x00,0x00,0x00 }, /* 0x2f unused */ |
| 783 | { 0x00,0x00,0x00,0x00 }, /* 0x30 unused */ |
| 784 | { 0x0d,0x0d,0x0d,0x0d }, /* Enter 31 */ |
| 785 | }; |
| 786 | |
| 787 | WRITE_LINE_MEMBER(laser3k_state::ay3600_data_ready_w) |
| 788 | { |
| 789 | if (state == ASSERT_LINE) |
| 790 | { |
| 791 | int mod = 0; |
| 792 | m_lastchar = m_ay3600->b_r(); |
| 793 | |
| 794 | mod = (m_kbspecial->read() & 0x06) ? 0x01 : 0x00; |
| 795 | mod |= (m_kbspecial->read() & 0x08) ? 0x02 : 0x00; |
| 796 | |
| 797 | // printf("lastchar = %02x\n", m_lastchar & 0x3f); |
| 798 | |
| 799 | m_transchar = key_remap[m_lastchar&0x3f][mod]; |
| 800 | |
| 801 | if (m_transchar != 0) |
| 802 | { |
| 803 | m_strobe = 0x80; |
| 804 | // printf("new char = %04x (%02x)\n", m_lastchar&0x3f, m_transchar); |
| 805 | } |
| 806 | } |
| 807 | } |
| 808 | |
| 351 | 809 | /*************************************************************************** |
| 352 | 810 | INPUT PORTS |
| 353 | 811 | ***************************************************************************/ |
| r31632 | r31633 | |
| 408 | 866 | PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) |
| 409 | 867 | PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CHAR('a') |
| 410 | 868 | PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') |
| 411 | | PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 869 | PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('\"') |
| 412 | 870 | PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 413 | 871 | PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 414 | 872 | PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) |
| r31632 | r31633 | |
| 540 | 998 | MCFG_RAM_ADD("mainram") |
| 541 | 999 | MCFG_RAM_DEFAULT_SIZE("192K") |
| 542 | 1000 | |
| 1001 | /* the 8048 isn't dumped, so substitute modified real Apple II h/w */ |
| 1002 | MCFG_DEVICE_ADD("ay3600", AY3600, 0) |
| 1003 | MCFG_AY3600_MATRIX_X0(IOPORT("X0")) |
| 1004 | MCFG_AY3600_MATRIX_X1(IOPORT("X1")) |
| 1005 | MCFG_AY3600_MATRIX_X2(IOPORT("X2")) |
| 1006 | MCFG_AY3600_MATRIX_X3(IOPORT("X3")) |
| 1007 | MCFG_AY3600_MATRIX_X4(IOPORT("X4")) |
| 1008 | MCFG_AY3600_MATRIX_X5(IOPORT("X5")) |
| 1009 | MCFG_AY3600_MATRIX_X6(IOPORT("X6")) |
| 1010 | MCFG_AY3600_MATRIX_X7(IOPORT("X7")) |
| 1011 | MCFG_AY3600_MATRIX_X8(IOPORT("X8")) |
| 1012 | MCFG_AY3600_SHIFT_CB(READLINE(laser3k_state, ay3600_shift_r)) |
| 1013 | MCFG_AY3600_CONTROL_CB(READLINE(laser3k_state, ay3600_control_r)) |
| 1014 | MCFG_AY3600_DATA_READY_CB(WRITELINE(laser3k_state, ay3600_data_ready_w)) |
| 1015 | |
| 543 | 1016 | /* sound hardware */ |
| 544 | 1017 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 545 | 1018 | MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0) |