trunk/src/mess/drivers/bml3.c
| r26773 | r26774 | |
| 18 | 18 | #include "cpu/m6809/m6809.h" |
| 19 | 19 | #include "machine/bml3bus.h" |
| 20 | 20 | #include "video/mc6845.h" |
| 21 | | #include "sound/beep.h" |
| 22 | 21 | #include "machine/6821pia.h" |
| 23 | 22 | #include "machine/6850acia.h" |
| 24 | 23 | #include "sound/2203intf.h" |
| 25 | 24 | #include "machine/bml3mp1802.h" |
| 26 | 25 | #include "machine/bml3mp1805.h" |
| 27 | 26 | #include "machine/bml3kanji.h" |
| 28 | | |
| 27 | #include "sound/speaker.h" |
| 28 | //#include "sound/wave.h" |
| 29 | 29 | //#include "imagedev/cassette.h" |
| 30 | 30 | |
| 31 | 31 | // System clock definitions, from the MB-6890 servce manual, p.48: |
| r26773 | r26774 | |
| 67 | 67 | { |
| 68 | 68 | public: |
| 69 | 69 | bml3_state(const machine_config &mconfig, device_type type, const char *tag) |
| 70 | | : driver_device(mconfig, type, tag), |
| 71 | | m_maincpu(*this, "maincpu"), |
| 72 | | m_bml3bus(*this, "bml3bus"), |
| 73 | | m_crtc(*this, "crtc"), |
| 74 | | //m_cass(*this, "cassette"), |
| 75 | | m_beep(*this, "beeper"), |
| 76 | | m_ym2203(*this, "ym2203") |
| 77 | | { |
| 78 | | } |
| 70 | : driver_device(mconfig, type, tag) |
| 71 | , m_maincpu(*this, "maincpu") |
| 72 | , m_bml3bus(*this, "bml3bus") |
| 73 | , m_crtc(*this, "crtc") |
| 74 | //, m_cass(*this, "cassette") |
| 75 | , m_speaker(*this, "speaker") |
| 76 | , m_ym2203(*this, "ym2203") |
| 77 | { } |
| 79 | 78 | |
| 80 | | required_device<cpu_device> m_maincpu; |
| 81 | | required_device<bml3bus_device> m_bml3bus; |
| 82 | | required_device<mc6845_device> m_crtc; |
| 83 | | //required_device<cassette_image_device> m_cass; |
| 84 | | required_device<beep_device> m_beep; |
| 85 | | optional_device<ym2203_device> m_ym2203; |
| 79 | DECLARE_READ8_MEMBER(bml3_6845_r); |
| 86 | 80 | DECLARE_WRITE8_MEMBER(bml3_6845_w); |
| 87 | 81 | DECLARE_READ8_MEMBER(bml3_keyboard_r); |
| 88 | 82 | DECLARE_WRITE8_MEMBER(bml3_keyboard_w); |
| r26773 | r26774 | |
| 115 | 109 | DECLARE_READ8_MEMBER(bml3_f000_r); DECLARE_WRITE8_MEMBER(bml3_f000_w); |
| 116 | 110 | DECLARE_READ8_MEMBER(bml3_fff0_r); DECLARE_WRITE8_MEMBER(bml3_fff0_w); |
| 117 | 111 | |
| 112 | UINT8 *m_p_videoram; |
| 113 | UINT8 *m_p_chargen; |
| 114 | UINT8 m_hres_reg; |
| 115 | UINT8 m_crtc_vreg[0x100]; |
| 116 | // INTERRUPT_GEN_MEMBER(bml3_irq); |
| 117 | INTERRUPT_GEN_MEMBER(bml3_timer_firq); |
| 118 | TIMER_DEVICE_CALLBACK_MEMBER(keyboard_callback); |
| 119 | DECLARE_READ8_MEMBER(bml3_ym2203_r); |
| 120 | DECLARE_WRITE8_MEMBER(bml3_ym2203_w); |
| 121 | private: |
| 122 | UINT8 m_psg_latch; |
| 118 | 123 | UINT8 m_attr_latch; |
| 119 | 124 | UINT8 m_io_latch; |
| 120 | | UINT8 m_hres_reg; |
| 121 | 125 | UINT8 m_vres_reg; |
| 122 | 126 | UINT8 m_keyb_interrupt_disabled; |
| 123 | 127 | UINT8 m_keyb_nmi_disabled; |
| r26773 | r26774 | |
| 127 | 131 | UINT8 m_keyb_capslock_led_on; |
| 128 | 132 | UINT8 m_keyb_hiragana_led_on; |
| 129 | 133 | UINT8 m_keyb_katakana_led_on; |
| 130 | | UINT8 *m_p_chargen; |
| 131 | | UINT8 m_psg_latch; |
| 132 | | void m6845_change_clock(UINT8 setting); |
| 133 | | UINT8 m_crtc_vreg[0x100],m_crtc_index; |
| 134 | | UINT8 *m_extram; |
| 135 | | UINT8 m_firq_mask,m_firq_status; |
| 136 | | |
| 137 | | protected: |
| 138 | 134 | virtual void machine_reset(); |
| 139 | | |
| 140 | 135 | virtual void machine_start(); |
| 141 | | virtual void video_start(); |
| 142 | 136 | virtual void palette_init(); |
| 143 | | public: |
| 144 | | UINT32 screen_update_bml3(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); |
| 145 | | // INTERRUPT_GEN_MEMBER(bml3_irq); |
| 146 | | INTERRUPT_GEN_MEMBER(bml3_timer_firq); |
| 147 | | TIMER_DEVICE_CALLBACK_MEMBER(keyboard_callback); |
| 148 | | DECLARE_READ8_MEMBER(bml3_ym2203_r); |
| 149 | | DECLARE_WRITE8_MEMBER(bml3_ym2203_w); |
| 137 | void m6845_change_clock(UINT8 setting); |
| 138 | UINT8 m_crtc_index; |
| 139 | UINT8 *m_extram; |
| 140 | UINT8 m_firq_mask,m_firq_status; |
| 141 | required_device<cpu_device> m_maincpu; |
| 142 | required_device<bml3bus_device> m_bml3bus; |
| 143 | required_device<mc6845_device> m_crtc; |
| 144 | //required_device<cassette_image_device> m_cass; |
| 145 | required_device<speaker_sound_device> m_speaker; |
| 146 | optional_device<ym2203_device> m_ym2203; |
| 150 | 147 | }; |
| 151 | 148 | |
| 152 | 149 | #define mc6845_h_char_total (m_crtc_vreg[0]) |
| r26773 | r26774 | |
| 167 | 164 | #define mc6845_update_addr (((m_crtc_vreg[0x12]<<8) & 0x3f00) | (m_crtc_vreg[0x13] & 0xff)) |
| 168 | 165 | |
| 169 | 166 | |
| 170 | | void bml3_state::video_start() |
| 171 | | { |
| 172 | | m_p_chargen = memregion("chargen")->base(); |
| 173 | | } |
| 174 | 167 | |
| 175 | | UINT32 bml3_state::screen_update_bml3(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) |
| 168 | READ8_MEMBER( bml3_state::bml3_6845_r ) |
| 176 | 169 | { |
| 177 | | // The MB-6890 has a 5-bit colour RAM region. The meaning of the bits are: |
| 178 | | // 0: blue |
| 179 | | // 1: red |
| 180 | | // 2: green |
| 181 | | // 3: reverse/inverse video |
| 182 | | // 4: graphic (not character) |
| 183 | | |
| 184 | | int x,y,hf,count; |
| 185 | | int xi,yi; |
| 186 | | int width,interlace,lowres; |
| 187 | | int bgcolor; |
| 188 | | int rawbits,dots[2],color,reverse,graphic; |
| 189 | | UINT8 *vram = memregion("vram")->base(); |
| 190 | | |
| 191 | | count = 0x0000; |
| 192 | | |
| 193 | | width = (m_hres_reg & 0x80) ? 80 : 40; |
| 194 | | interlace = (m_vres_reg & 0x08) ? 1 : 0; |
| 195 | | lowres = (m_hres_reg & 0x40) ? 1 : 0; |
| 196 | | bgcolor = m_hres_reg & 0x07; |
| 197 | | |
| 198 | | // redundant initializers to keep compiler happy |
| 199 | | rawbits = dots[0] = dots[1] = color = reverse = graphic = 0; |
| 200 | | |
| 201 | | // popmessage("%02x %02x",m_hres_reg,m_vres_reg); |
| 202 | | |
| 203 | | for(y=0;y<25;y++) |
| 204 | | { |
| 205 | | for(x=0;x<width;x++) |
| 206 | | { |
| 207 | | for(yi=0;yi<8;yi++) |
| 208 | | { |
| 209 | | if (!lowres || yi == 0) { |
| 210 | | int offset = count + yi * (width / 40 * 0x400) + mc6845_start_addr - 0x400; |
| 211 | | if (offset >= 0x0000 && offset < 0x4000) { |
| 212 | | rawbits = vram[offset+0x0000]; |
| 213 | | color = vram[offset+0x4000] & 7; |
| 214 | | reverse = vram[offset+0x4000] & 8; |
| 215 | | graphic = vram[offset+0x4000] & 0x10; |
| 216 | | } |
| 217 | | else { |
| 218 | | // outside vram - don't know what should happen here |
| 219 | | rawbits = color = reverse = graphic = 0; |
| 220 | | } |
| 221 | | } |
| 222 | | if (graphic) { |
| 223 | | if (lowres) { |
| 224 | | // low-res graphics, each tile has 8 bits arranged as follows: |
| 225 | | // 4 0 |
| 226 | | // 5 1 |
| 227 | | // 6 2 |
| 228 | | // 7 3 |
| 229 | | dots[0] = dots[1] = (rawbits >> yi/2 & 0x11) * 0xf; |
| 230 | | } |
| 231 | | else { |
| 232 | | dots[0] = dots[1] = rawbits; |
| 233 | | } |
| 234 | | } |
| 235 | | else { |
| 236 | | // character mode |
| 237 | | int tile = rawbits & 0x7f; |
| 238 | | int tile_bank = (rawbits & 0x80) >> 7; |
| 239 | | if (interlace) { |
| 240 | | dots[0] = m_p_chargen[(tile_bank<<11)|(tile<<4)|(yi<<1)]; |
| 241 | | dots[1] = m_p_chargen[(tile_bank<<11)|(tile<<4)|(yi<<1)|tile_bank]; |
| 242 | | } |
| 243 | | else { |
| 244 | | dots[0] = dots[1] = m_p_chargen[(tile<<4)|(yi<<1)|tile_bank]; |
| 245 | | } |
| 246 | | } |
| 247 | | for(hf=0;hf<=interlace;hf++) |
| 248 | | { |
| 249 | | for(xi=0;xi<8;xi++) |
| 250 | | { |
| 251 | | int pen; |
| 252 | | |
| 253 | | if(reverse) |
| 254 | | pen = (dots[hf] >> (7-xi) & 1) ? bgcolor : color; |
| 255 | | else |
| 256 | | pen = (dots[hf] >> (7-xi) & 1) ? color : bgcolor; |
| 257 | | |
| 258 | | bitmap.pix16((y*8+yi)*(interlace+1)+hf, x*8+xi) = pen; |
| 259 | | } |
| 260 | | } |
| 261 | | } |
| 262 | | |
| 263 | | if(mc6845_cursor_addr-mc6845_start_addr == count) |
| 264 | | { |
| 265 | | int xc,yc,cursor_on; |
| 266 | | |
| 267 | | cursor_on = 0; |
| 268 | | switch(mc6845_cursor_y_start & 0x60) |
| 269 | | { |
| 270 | | case 0x00: cursor_on = 1; break; //always on |
| 271 | | case 0x20: cursor_on = 0; break; //always off |
| 272 | | case 0x40: if(machine().primary_screen->frame_number() & 0x10) { cursor_on = 1; } break; //fast blink |
| 273 | | case 0x60: if(machine().primary_screen->frame_number() & 0x20) { cursor_on = 1; } break; //slow blink |
| 274 | | } |
| 275 | | |
| 276 | | if(cursor_on) |
| 277 | | { |
| 278 | | for(yc=0;yc<(8-(mc6845_cursor_y_start & 7));yc++) |
| 279 | | { |
| 280 | | for(xc=0;xc<8;xc++) |
| 281 | | { |
| 282 | | if(interlace) |
| 283 | | { |
| 284 | | bitmap.pix16((y*8+yc+7)*2+0, x*8+xc) = 7; |
| 285 | | bitmap.pix16((y*8+yc+7)*2+1, x*8+xc) = 7; |
| 286 | | } |
| 287 | | else |
| 288 | | bitmap.pix16(y*8+yc+7, x*8+xc) = 7; |
| 289 | | } |
| 290 | | } |
| 291 | | } |
| 292 | | } |
| 293 | | |
| 294 | | count++; |
| 295 | | } |
| 296 | | } |
| 297 | | |
| 298 | | return 0; |
| 170 | if (offset) |
| 171 | return m_crtc->register_r(space, 0); |
| 172 | else |
| 173 | return m_crtc->status_r(space, 0); |
| 299 | 174 | } |
| 300 | 175 | |
| 301 | 176 | WRITE8_MEMBER( bml3_state::bml3_6845_w ) |
| r26773 | r26774 | |
| 373 | 248 | |
| 374 | 249 | READ8_MEMBER( bml3_state::bml3_vram_r ) |
| 375 | 250 | { |
| 376 | | UINT8 *vram = memregion("vram")->base(); |
| 377 | | |
| 378 | 251 | // Bit 7 masks reading back to the latch |
| 379 | | if ((m_attr_latch & 0x80) == 0) { |
| 380 | | m_attr_latch = vram[offset+0x4000]; |
| 252 | if (!BIT(m_attr_latch, 7)) |
| 253 | { |
| 254 | m_attr_latch = m_p_videoram[offset+0x4000]; |
| 381 | 255 | } |
| 382 | 256 | |
| 383 | | return vram[offset]; |
| 257 | return m_p_videoram[offset]; |
| 384 | 258 | } |
| 385 | 259 | |
| 386 | 260 | WRITE8_MEMBER( bml3_state::bml3_vram_w ) |
| 387 | 261 | { |
| 388 | | UINT8 *vram = memregion("vram")->base(); |
| 389 | | |
| 390 | | vram[offset] = data; |
| 262 | m_p_videoram[offset] = data; |
| 391 | 263 | // color ram is 5-bit |
| 392 | | vram[offset+0x4000] = m_attr_latch & 0x1F; |
| 264 | m_p_videoram[offset+0x4000] = m_attr_latch & 0x1F; |
| 393 | 265 | } |
| 394 | 266 | |
| 395 | 267 | READ8_MEMBER( bml3_state::bml3_psg_latch_r) |
| r26773 | r26774 | |
| 444 | 316 | |
| 445 | 317 | WRITE8_MEMBER( bml3_state::bml3_beep_w) |
| 446 | 318 | { |
| 447 | | m_beep->set_state(!BIT(data, 7)); |
| 319 | m_speaker->level_w(BIT(data, 7)); |
| 448 | 320 | } |
| 449 | 321 | |
| 450 | 322 | READ8_MEMBER( bml3_state::bml3_a000_r) { return m_extram[offset + 0xa000]; } |
| r26773 | r26774 | |
| 505 | 377 | AM_RANGE(0xffc0, 0xffc3) AM_DEVREADWRITE("pia6821", pia6821_device, read, write) |
| 506 | 378 | AM_RANGE(0xffc4, 0xffc4) AM_DEVREADWRITE("acia6850", acia6850_device, status_read, control_write) |
| 507 | 379 | AM_RANGE(0xffc5, 0xffc5) AM_DEVREADWRITE("acia6850", acia6850_device, data_read, data_write) |
| 508 | | AM_RANGE(0xffc6, 0xffc7) AM_WRITE(bml3_6845_w) |
| 380 | AM_RANGE(0xffc6, 0xffc7) AM_READWRITE(bml3_6845_r,bml3_6845_w) |
| 509 | 381 | // KBNMI - Keyboard "Break" key non-maskable interrupt |
| 510 | 382 | AM_RANGE(0xffc8, 0xffc8) AM_READ(bml3_keyb_nmi_r) // keyboard nmi |
| 511 | 383 | // DIPSW - DIP switches on system mainboard |
| r26773 | r26774 | |
| 518 | 390 | AM_RANGE(0xffd0, 0xffd0) AM_WRITE(bml3_hres_reg_w) |
| 519 | 391 | // TRACE - Trace counter |
| 520 | 392 | // AM_RANGE(0xffd1, 0xffd1) |
| 521 | | // REMOTE - Remote relay control for cassette? |
| 393 | // REMOTE - Remote relay control for cassette - bit 7 |
| 522 | 394 | // AM_RANGE(0xffd2, 0xffd2) |
| 523 | 395 | // MUSIC_SEL - Music select: toggle audio output level when rising |
| 524 | 396 | AM_RANGE(0xffd3, 0xffd3) AM_READWRITE(bml3_beep_r,bml3_beep_w) |
| r26773 | r26774 | |
| 699 | 571 | PORT_BIT(0xffe00000,IP_ACTIVE_HIGH,IPT_UNKNOWN) |
| 700 | 572 | INPUT_PORTS_END |
| 701 | 573 | |
| 574 | static MC6845_UPDATE_ROW( update_row ) |
| 575 | { |
| 576 | bml3_state *state = device->machine().driver_data<bml3_state>(); |
| 577 | const rgb_t *palette = palette_entry_list_raw(bitmap.palette()); |
| 578 | // The MB-6890 has a 5-bit colour RAM region. The meaning of the bits are: |
| 579 | // 0: blue |
| 580 | // 1: red |
| 581 | // 2: green |
| 582 | // 3: reverse/inverse video |
| 583 | // 4: graphic (not character) |
| 702 | 584 | |
| 585 | UINT8 x=0,hf=0,xi=0,interlace=0,bgcolor=0,rawbits=0,dots[2],color=0,pen=0; |
| 586 | bool reverse=0,graphic=0,lowres=0; |
| 587 | UINT16 mem=0; |
| 588 | |
| 589 | interlace = (state->m_crtc_vreg[8] & 3) ? 1 : 0; |
| 590 | lowres = BIT(state->m_hres_reg, 6); |
| 591 | bgcolor = state->m_hres_reg & 7; |
| 592 | |
| 593 | if (interlace) |
| 594 | { |
| 595 | ra >>= 1; |
| 596 | if (y > 0x176) return; |
| 597 | } |
| 598 | |
| 599 | // redundant initializers to keep compiler happy |
| 600 | dots[0] = dots[1] = 0; |
| 601 | |
| 602 | for(x=0; x<x_count; x++) |
| 603 | { |
| 604 | if (lowres) |
| 605 | mem = (ma + x - 0x400) & 0x3fff; |
| 606 | else |
| 607 | mem = (ma + x + ra * x_count/40 * 0x400 -0x400) & 0x3fff; |
| 608 | |
| 609 | color = state->m_p_videoram[mem|0x4000] & 7; |
| 610 | reverse = BIT(state->m_p_videoram[mem|0x4000], 3) ^ (x == cursor_x); |
| 611 | graphic = BIT(state->m_p_videoram[mem|0x4000], 4); |
| 612 | |
| 613 | rawbits = state->m_p_videoram[mem]; |
| 614 | |
| 615 | if (graphic) |
| 616 | { |
| 617 | if (lowres) |
| 618 | { |
| 619 | // low-res graphics, each tile has 8 bits arranged as follows: |
| 620 | // 4 0 |
| 621 | // 5 1 |
| 622 | // 6 2 |
| 623 | // 7 3 |
| 624 | dots[0] = dots[1] = (rawbits >> ra/2 & 0x11) * 0xf; |
| 625 | } |
| 626 | else |
| 627 | { |
| 628 | dots[0] = dots[1] = rawbits; |
| 629 | } |
| 630 | } |
| 631 | else |
| 632 | { |
| 633 | // character mode |
| 634 | int tile = rawbits & 0x7f; |
| 635 | int tile_bank = BIT(rawbits, 7); |
| 636 | if (interlace) |
| 637 | { |
| 638 | dots[0] = state->m_p_chargen[(tile_bank<<11)|(tile<<4)|(ra<<1)]; |
| 639 | dots[1] = state->m_p_chargen[(tile_bank<<11)|(tile<<4)|(ra<<1)|tile_bank]; |
| 640 | } |
| 641 | else |
| 642 | { |
| 643 | dots[0] = dots[1] = state->m_p_chargen[(tile<<4)|(ra<<1)|tile_bank]; |
| 644 | } |
| 645 | } |
| 646 | |
| 647 | for(hf=0;hf<=interlace;hf++) |
| 648 | { |
| 649 | for(xi=0;xi<8;xi++) |
| 650 | { |
| 651 | if(reverse) |
| 652 | pen = (dots[hf] >> (7-xi) & 1) ? bgcolor : color; |
| 653 | else |
| 654 | pen = (dots[hf] >> (7-xi) & 1) ? color : bgcolor; |
| 655 | |
| 656 | bitmap.pix32(y, x*8+xi) = palette[pen]; |
| 657 | // when the mc6845 device gains full interlace&video support, replace the line above with the line below |
| 658 | // bitmap.pix32(y*(interlace+1)+hf, x*8+xi) = palette[pen]; |
| 659 | } |
| 660 | } |
| 661 | } |
| 662 | } |
| 663 | |
| 703 | 664 | static MC6845_INTERFACE( mc6845_intf ) |
| 704 | 665 | { |
| 705 | 666 | false, /* show border area */ |
| 706 | 667 | 8, /* number of pixels per video memory address */ |
| 707 | 668 | NULL, /* before pixel update callback */ |
| 708 | | NULL, /* row update callback */ |
| 669 | update_row, /* row update callback */ |
| 709 | 670 | NULL, /* after pixel update callback */ |
| 710 | 671 | DEVCB_NULL, /* callback for display state changes */ |
| 711 | 672 | DEVCB_NULL, /* callback for cursor state changes */ |
| r26773 | r26774 | |
| 788 | 749 | |
| 789 | 750 | void bml3_state::machine_start() |
| 790 | 751 | { |
| 791 | | m_beep->set_frequency(1200); //guesswork |
| 792 | | m_beep->set_state(0); |
| 793 | 752 | m_extram = auto_alloc_array(machine(),UINT8,0x10000); |
| 753 | m_p_chargen = memregion("chargen")->base(); |
| 754 | m_p_videoram = memregion("vram")->base(); |
| 794 | 755 | } |
| 795 | 756 | |
| 796 | 757 | void bml3_state::machine_reset() |
| r26773 | r26774 | |
| 987 | 948 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2400)) /* Service manual specifies "Raster return period" as 2.4 ms (p.64), although the total vertical non-displaying time seems to be 4 ms. */ |
| 988 | 949 | MCFG_SCREEN_SIZE(640, 400) |
| 989 | 950 | MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 0, 200-1) |
| 990 | | MCFG_SCREEN_UPDATE_DRIVER(bml3_state, screen_update_bml3) |
| 951 | MCFG_SCREEN_UPDATE_DEVICE("crtc", mc6845_device, screen_update) |
| 991 | 952 | MCFG_PALETTE_LENGTH(8) |
| 992 | 953 | |
| 993 | 954 | /* Devices */ |
| r26773 | r26774 | |
| 1001 | 962 | |
| 1002 | 963 | /* Audio */ |
| 1003 | 964 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 1004 | | MCFG_SOUND_ADD("beeper", BEEP, 0) |
| 1005 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS,"mono",0.50) |
| 965 | //MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette") |
| 966 | //MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 967 | MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0) |
| 968 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) |
| 1006 | 969 | |
| 1007 | 970 | /* slot devices */ |
| 1008 | 971 | MCFG_BML3BUS_BUS_ADD("bml3bus", "maincpu", bml3bus_intf) |