| Previous | 199869 Revisions | Next |
| r24065 Thursday 4th July, 2013 at 10:43:00 UTC by Miodrag Milanović |
|---|
| (MESS)bml3: Add stub variants bml3mk2 (for MB-6891) and bml3mk5 [jedwidz] (for MB-6892). For now these behave the same as bml3 (MB-6890). Refactor disk controllers and kanji ROM as slot devices. This allows switching between MP-1802 and MP-1805 disk controllers. MP-1805 disk controller now works. Kanji ROM now works. Keyboard scanning in 'counter disabled' mode now works. imgtool: Add bml3 driver, supporting both single-density (MP-1805 controller) and double-density (MP-1802 controller) disks in D88 format. mc6843: Work around floppy_get_device() not finding drives attached to a slot device.Store all 8 bits in CTAR current track register, rather than excluding bit 7 (needed for bml3 MP-1805 boot) |
| [src/emu/machine] | mc6843.c |
| [src/mess] | mess.lst mess.mak |
| [src/mess/drivers] | bml3.c |
| [src/mess/machine] | bml3bus.c* bml3bus.h* bml3kanji.c* bml3kanji.h* bml3mp1802.c* bml3mp1802.h* bml3mp1805.c* bml3mp1805.h* |
| [src/mess/tools/imgtool] | filtbas.c filter.c filter.h imgtool.mak modules.c |
| [src/mess/tools/imgtool/modules] | bml3.c* |
| r24064 | r24065 | |
|---|---|---|
| 118 | 118 | |
| 119 | 119 | |
| 120 | 120 | |
| 121 | static device_t* mc6843_floppy_image ( device_t *device, UINT8 drive ) | |
| 122 | { | |
| 123 | device_t *img = floppy_get_device( device->machine(), drive ); | |
| 124 | if (!img && device->owner()) { | |
| 125 | // For slot devices, drives are typically attached to the slot rather than the machine | |
| 126 | const char *floppy_name = NULL; | |
| 127 | switch (drive) { | |
| 128 | case 0: | |
| 129 | floppy_name = FLOPPY_0; | |
| 130 | break; | |
| 131 | case 1: | |
| 132 | floppy_name = FLOPPY_1; | |
| 133 | break; | |
| 134 | case 2: | |
| 135 | floppy_name = FLOPPY_2; | |
| 136 | break; | |
| 137 | case 3: | |
| 138 | floppy_name = FLOPPY_3; | |
| 139 | break; | |
| 140 | } | |
| 141 | img = device->owner()->subdevice(floppy_name); | |
| 142 | } | |
| 143 | return img; | |
| 144 | } | |
| 145 | ||
| 146 | ||
| 121 | 147 | static device_t* mc6843_floppy_image ( device_t *device ) |
| 122 | 148 | { |
| 123 | 149 | mc6843_t* mc6843 = get_safe_token( device ); |
| 124 | return floppy_ge | |
| 150 | return mc6843_floppy_image( device, mc6843->drive ); | |
| 125 | 151 | } |
| 126 | 152 | |
| 127 | 153 | |
| 128 | ||
| 129 | 154 | void mc6843_set_drive( device_t *device, int drive ) |
| 130 | 155 | { |
| 131 | 156 | mc6843_t* mc6843 = get_safe_token( device ); |
| r24064 | r24065 | |
| 234 | 259 | device_t* img = mc6843_floppy_image( device ); |
| 235 | 260 | |
| 236 | 261 | /* seek to track */ |
| 237 | floppy_drive_seek( img, mc6843->GCR - mc6843->CTAR ); | |
| 262 | // TODO: not sure how CTAR bit 7 is handled here, but this is the safest approach for now | |
| 263 | floppy_drive_seek( img, mc6843->GCR - (mc6843->CTAR & 0x7F) ); | |
| 238 | 264 | |
| 239 | LOG(( "%f mc6843_finish_SEK: from %i to %i (actual=%i)\n", device->machine().time().as_double(), mc6843->CTAR, mc6843->GCR, floppy_drive_get_current_track( img ) )); | |
| 265 | LOG(( "%f mc6843_finish_SEK: from %i to %i (actual=%i)\n", device->machine().time().as_double(), (mc6843->CTAR & 0x7F), mc6843->GCR, floppy_drive_get_current_track( img ) )); | |
| 240 | 266 | |
| 241 | 267 | /* update state */ |
| 242 | 268 | mc6843->CTAR = mc6843->GCR; |
| r24064 | r24065 | |
| 672 | 698 | } |
| 673 | 699 | |
| 674 | 700 | case 1: /* Current-Track Address Register (CTAR) */ |
| 675 | mc6843->CTAR = data | |
| 701 | mc6843->CTAR = data; | |
| 676 | 702 | LOG(( "%f $%04x mc6843_w: set CTAR to %i %02X (actual=%i) \n", |
| 677 | 703 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->CTAR, data, |
| 678 | 704 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); |
| r24064 | r24065 | |
| 776 | 802 | /* setup/reset floppy drive */ |
| 777 | 803 | for ( i = 0; i < 4; i++ ) |
| 778 | 804 | { |
| 779 | device_t * img = floppy_ge | |
| 805 | device_t * img = mc6843_floppy_image( device, i ); | |
| 780 | 806 | floppy_mon_w(img, CLEAR_LINE); |
| 781 | 807 | floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 ); |
| 782 | 808 | floppy_drive_set_rpm( img, 300. ); |
| r24064 | r24065 | |
|---|---|---|
| 1447 | 1447 | $(MESSOBJ)/hitachi.a: \ |
| 1448 | 1448 | $(MESS_DRIVERS)/bmjr.o \ |
| 1449 | 1449 | $(MESS_DRIVERS)/bml3.o \ |
| 1450 | $(MESS_MACHINE)/bml3bus.o \ | |
| 1451 | $(MESS_MACHINE)/bml3mp1802.o\ | |
| 1452 | $(MESS_MACHINE)/bml3mp1805.o\ | |
| 1453 | $(MESS_MACHINE)/bml3kanji.o \ | |
| 1450 | 1454 | $(MESS_DRIVERS)/b16.o \ |
| 1451 | 1455 | |
| 1452 | 1456 | $(MESSOBJ)/homebrew.a: \ |
| r24064 | r24065 | |
|---|---|---|
| 1 | 1 | /************************************************************************************** |
| 2 | 2 | |
| 3 | Basic Master Level 3 (MB-689 | |
| 3 | Basic Master Level 3 (MB-689x) (c) 1980 Hitachi | |
| 4 | 4 | |
| 5 | 5 | Driver by Angelo Salese, Jonathan Edwards and Christopher Edwards |
| 6 | 6 | |
| 7 | 7 | TODO: |
| 8 | 8 | - tape support |
| 9 | - disk support in bml3b machine | |
| 9 | - implement sound as a bml3bus slot device | |
| 10 | - account for hardware differences between MB-6890, MB-6891 and MB-6892 | |
| 11 | (e.g. custom font support on the MB-6892) | |
| 10 | 12 | |
| 11 | 13 | **************************************************************************************/ |
| 12 | 14 | |
| 13 | 15 | #include "emu.h" |
| 14 | 16 | #include "cpu/m6809/m6809.h" |
| 17 | #include "machine/bml3bus.h" | |
| 15 | 18 | #include "video/mc6845.h" |
| 16 | #include "machine/wd_fdc.h" | |
| 17 | #include "machine/mc6843.h" | |
| 18 | 19 | #include "sound/beep.h" |
| 19 | 20 | #include "machine/6821pia.h" |
| 20 | 21 | #include "machine/6850acia.h" |
| 21 | 22 | #include "sound/2203intf.h" |
| 23 | #include "machine/bml3mp1802.h" | |
| 24 | #include "machine/bml3mp1805.h" | |
| 25 | #include "machine/bml3kanji.h" | |
| 22 | 26 | |
| 23 | 27 | //#include "imagedev/cassette.h" |
| 24 | #include "imagedev/flopdrv.h" | |
| 25 | //#include "formats/basicdsk.h" | |
| 26 | //#include "imagedev/floppy.h" | |
| 27 | 28 | |
| 28 | 29 | // System clock definitions, from the MB-6890 servce manual, p.48: |
| 29 | 30 | |
| r24064 | r24065 | |
| 66 | 67 | bml3_state(const machine_config &mconfig, device_type type, const char *tag) |
| 67 | 68 | : driver_device(mconfig, type, tag), |
| 68 | 69 | m_maincpu(*this, "maincpu"), |
| 70 | m_bml3bus(*this, "bml3bus"), | |
| 69 | 71 | m_crtc(*this, "crtc"), |
| 70 | 72 | //m_cass(*this, "cassette"), |
| 71 | 73 | m_beep(*this, "beeper"), |
| 72 | m_ym2203(*this, "ym2203"), | |
| 73 | m_wd17xx(*this, "wd17xx"), | |
| 74 | m_wd17xx_0(*this, "wd17xx:0"), | |
| 75 | m_wd17xx_1(*this, "wd17xx:1"), | |
| 76 | m_mc6843(*this, "mc6843") | |
| 74 | m_ym2203(*this, "ym2203") | |
| 77 | 75 | { |
| 78 | 76 | } |
| 79 | 77 | |
| 80 | 78 | required_device<cpu_device> m_maincpu; |
| 79 | required_device<bml3bus_device> m_bml3bus; | |
| 81 | 80 | required_device<mc6845_device> m_crtc; |
| 82 | 81 | //required_device<cassette_image_device> m_cass; |
| 83 | 82 | required_device<beep_device> m_beep; |
| 84 | 83 | optional_device<ym2203_device> m_ym2203; |
| 85 | optional_device<mb8866_t> m_wd17xx; | |
| 86 | optional_device<floppy_connector> m_wd17xx_0; | |
| 87 | optional_device<floppy_connector> m_wd17xx_1; | |
| 88 | optional_device<mc6843_device> m_mc6843; | |
| 89 | 84 | DECLARE_WRITE8_MEMBER(bml3_6845_w); |
| 90 | 85 | DECLARE_READ8_MEMBER(bml3_keyboard_r); |
| 91 | 86 | DECLARE_WRITE8_MEMBER(bml3_keyboard_w); |
| r24064 | r24065 | |
| 93 | 88 | DECLARE_WRITE8_MEMBER(bml3_vres_reg_w); |
| 94 | 89 | DECLARE_READ8_MEMBER(bml3_vram_r); |
| 95 | 90 | DECLARE_WRITE8_MEMBER(bml3_vram_w); |
| 96 | DECLARE_READ8_MEMBER(bml3_mp1802_r); | |
| 97 | DECLARE_WRITE8_MEMBER(bml3_mp1802_w); | |
| 98 | DECLARE_READ8_MEMBER(bml3_mp1805_r); | |
| 99 | DECLARE_WRITE8_MEMBER(bml3_mp1805_w); | |
| 100 | DECLARE_READ8_MEMBER(bml3_kanji_r); | |
| 101 | DECLARE_WRITE8_MEMBER(bml3_kanji_w); | |
| 102 | 91 | DECLARE_READ8_MEMBER(bml3_psg_latch_r); |
| 103 | 92 | DECLARE_WRITE8_MEMBER(bml3_psg_latch_w); |
| 104 | 93 | DECLARE_READ8_MEMBER(bml3_vram_attr_r); |
| r24064 | r24065 | |
| 110 | 99 | DECLARE_WRITE8_MEMBER(bml3_firq_mask_w); |
| 111 | 100 | DECLARE_READ8_MEMBER(bml3_firq_status_r); |
| 112 | 101 | |
| 102 | DECLARE_WRITE8_MEMBER(bml3bus_nmi_w); | |
| 103 | DECLARE_WRITE8_MEMBER(bml3bus_irq_w); | |
| 104 | DECLARE_WRITE8_MEMBER(bml3bus_firq_w); | |
| 113 | 105 | |
| 114 | 106 | DECLARE_READ_LINE_MEMBER( bml3_acia_rx_r ); |
| 115 | 107 | DECLARE_WRITE_LINE_MEMBER( bml3_acia_tx_w ); |
| r24064 | r24065 | |
| 140 | 132 | UINT8 m_psg_latch; |
| 141 | 133 | void m6845_change_clock(UINT8 setting); |
| 142 | 134 | UINT8 m_crtc_vreg[0x100],m_crtc_index; |
| 143 | UINT16 m_kanji_addr; | |
| 144 | 135 | UINT8 *m_extram; |
| 145 | 136 | UINT8 m_firq_mask,m_firq_status; |
| 146 | 137 | |
| r24064 | r24065 | |
| 157 | 148 | TIMER_DEVICE_CALLBACK_MEMBER(keyboard_callback); |
| 158 | 149 | DECLARE_READ8_MEMBER(bml3_ym2203_r); |
| 159 | 150 | DECLARE_WRITE8_MEMBER(bml3_ym2203_w); |
| 160 | void bml3_wd17xx_intrq_w(bool state); | |
| 161 | 151 | }; |
| 162 | 152 | |
| 163 | 153 | #define mc6845_h_char_total (m_crtc_vreg[0]) |
| r24064 | r24065 | |
| 403 | 393 | vram[offset+0x4000] = m_attr_latch & 0x1F; |
| 404 | 394 | } |
| 405 | 395 | |
| 406 | READ8_MEMBER( bml3_state::bml3_mp1802_r) | |
| 407 | { | |
| 408 | return m_wd17xx->drq_r() ? 0x00 : 0x80; | |
| 409 | } | |
| 410 | ||
| 411 | WRITE8_MEMBER( bml3_state::bml3_mp1802_w) | |
| 412 | { | |
| 413 | int drive = data & 0x03; | |
| 414 | int side = BIT(data, 4); | |
| 415 | int motor = BIT(data, 3); | |
| 416 | ||
| 417 | // drive select | |
| 418 | floppy_image_device *floppy = (drive == 0 ? m_wd17xx_0 : m_wd17xx_1)->get_device(); | |
| 419 | ||
| 420 | // side select | |
| 421 | if(floppy) { | |
| 422 | floppy->ss_w(side); | |
| 423 | floppy->mon_w(!motor); | |
| 424 | } | |
| 425 | ||
| 426 | m_wd17xx->set_floppy(floppy); | |
| 427 | } | |
| 428 | ||
| 429 | READ8_MEMBER( bml3_state::bml3_mp1805_r ) | |
| 430 | { | |
| 431 | //logerror("FDD 0xff20 R\n"); | |
| 432 | return -1; | |
| 433 | } | |
| 434 | ||
| 435 | WRITE8_MEMBER( bml3_state::bml3_mp1805_w ) | |
| 436 | { | |
| 437 | //logerror("FDD 0xff20 W %02x\n",data); | |
| 438 | // ? something here, gets 0x81 written to it if latch found at FF19, or 0x00 if not | |
| 439 | // don't know which bits are what | |
| 440 | // int drive = ?; | |
| 441 | // int side = ?; | |
| 442 | // int motor = ?; | |
| 443 | // mc6843_set_drive( machine().device("mc6843"), drive ); | |
| 444 | // mc6843_set_side( machine().device("mc6843"), side ); | |
| 445 | // floppy_mon_w(floppy_get_device(machine(),drive), motor); | |
| 446 | // floppy_drive_set_ready_state(floppy_get_device(machine(), drive), ASSERT_LINE, 0); | |
| 447 | } | |
| 448 | ||
| 449 | READ8_MEMBER( bml3_state::bml3_kanji_r ) | |
| 450 | { | |
| 451 | // return m_kanji_rom[m_kanji_addr << 1 + offset]; | |
| 452 | return machine().rand(); | |
| 453 | } | |
| 454 | ||
| 455 | WRITE8_MEMBER( bml3_state::bml3_kanji_w ) | |
| 456 | { | |
| 457 | m_kanji_addr &= (0xff << (offset*8)); | |
| 458 | m_kanji_addr |= (data << ((offset^1)*8)); | |
| 459 | } | |
| 460 | ||
| 461 | 396 | READ8_MEMBER( bml3_state::bml3_psg_latch_r) |
| 462 | 397 | { |
| 463 | 398 | return 0x7f; |
| r24064 | r24065 | |
| 547 | 482 | return res; |
| 548 | 483 | } |
| 549 | 484 | |
| 485 | WRITE8_MEMBER(bml3_state::bml3bus_nmi_w) | |
| 486 | { | |
| 487 | m_maincpu->set_input_line(INPUT_LINE_NMI, data); | |
| 488 | } | |
| 489 | ||
| 490 | WRITE8_MEMBER(bml3_state::bml3bus_irq_w) | |
| 491 | { | |
| 492 | m_maincpu->set_input_line(M6809_IRQ_LINE, data); | |
| 493 | } | |
| 494 | ||
| 495 | WRITE8_MEMBER(bml3_state::bml3bus_firq_w) | |
| 496 | { | |
| 497 | m_maincpu->set_input_line(M6809_FIRQ_LINE, data); | |
| 498 | } | |
| 499 | ||
| 500 | ||
| 550 | 501 | static ADDRESS_MAP_START(bml3_mem, AS_PROGRAM, 8, bml3_state) |
| 551 | 502 | ADDRESS_MAP_UNMAP_HIGH |
| 552 | 503 | AM_RANGE(0x0000, 0x03ff) AM_RAM |
| 553 | 504 | AM_RANGE(0x0400, 0x43ff) AM_READWRITE(bml3_vram_r,bml3_vram_w) |
| 554 | 505 | AM_RANGE(0x4400, 0x9fff) AM_RAM |
| 555 | AM_RANGE(0xff75, 0xff76) AM_READWRITE(bml3_kanji_r,bml3_kanji_w)// kanji i/f | |
| 556 | 506 | AM_RANGE(0xffc0, 0xffc3) AM_DEVREADWRITE("pia6821", pia6821_device, read, write) |
| 557 | 507 | AM_RANGE(0xffc4, 0xffc4) AM_DEVREADWRITE("acia6850", acia6850_device, status_read, control_write) |
| 558 | 508 | AM_RANGE(0xffc5, 0xffc5) AM_DEVREADWRITE("acia6850", acia6850_device, data_read, data_write) |
| r24064 | r24065 | |
| 594 | 544 | AM_RANGE(0xe000, 0xefff) AM_WRITE(bml3_e000_w) |
| 595 | 545 | AM_RANGE(0xf000, 0xfeff) AM_WRITE(bml3_f000_w) |
| 596 | 546 | AM_RANGE(0xfff0, 0xffff) AM_WRITE(bml3_fff0_w) |
| 547 | ||
| 548 | #if 0 | |
| 549 | AM_RANGE(0xff00, 0xff00) AM_READWRITE(bml3_ym2203_r,bml3_ym2203_w) | |
| 550 | AM_RANGE(0xff02, 0xff02) AM_READWRITE(bml3_psg_latch_r,bml3_psg_latch_w) // PSG address/data select | |
| 551 | #endif | |
| 597 | 552 | ADDRESS_MAP_END |
| 598 | 553 | |
| 599 | static ADDRESS_MAP_START(bml3 | |
| 554 | static ADDRESS_MAP_START(bml3mk2_mem, AS_PROGRAM, 8, bml3_state) | |
| 600 | 555 | AM_IMPORT_FROM(bml3_mem) |
| 556 | // TODO: anything to add here? | |
| 601 | 557 | |
| 602 | AM_RANGE(0xff00, 0xff03) AM_DEVREADWRITE("wd17xx", mb8866_t, read, write) | |
| 603 | AM_RANGE(0xff04, 0xff04) AM_READWRITE(bml3_mp1802_r,bml3_mp1802_w) | |
| 604 | 558 | ADDRESS_MAP_END |
| 605 | 559 | |
| 606 | static ADDRESS_MAP_START(bml3 | |
| 560 | static ADDRESS_MAP_START(bml3mk5_mem, AS_PROGRAM, 8, bml3_state) | |
| 607 | 561 | AM_IMPORT_FROM(bml3_mem) |
| 562 | // TODO: anything to add here? | |
| 608 | 563 | |
| 609 | AM_RANGE(0xff00, 0xff00) AM_READWRITE(bml3_ym2203_r,bml3_ym2203_w) | |
| 610 | // TODO: what's this? | |
| 611 | // AM_RANGE(0xff02, 0xff02) AM_READWRITE(bml3_psg_latch_r,bml3_psg_latch_w) // PSG address/data select | |
| 612 | AM_RANGE(0xff18, 0xff1f) AM_DEVREADWRITE_LEGACY("mc6843",mc6843_r,mc6843_w) | |
| 613 | AM_RANGE(0xff20, 0xff20) AM_READWRITE(bml3_mp1805_r,bml3_mp1805_w) // FDD drive select | |
| 614 | 564 | ADDRESS_MAP_END |
| 615 | 565 | |
| 616 | ||
| 617 | 566 | /* Input ports */ |
| 618 | 567 | |
| 619 | 568 | static INPUT_PORTS_START( bml3 ) |
| r24064 | r24065 | |
| 767 | 716 | NULL /* update address callback */ |
| 768 | 717 | }; |
| 769 | 718 | |
| 770 | void bml3_state::bml3_wd17xx_intrq_w(bool state) | |
| 771 | { | |
| 772 | if (state) | |
| 773 | m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); | |
| 774 | } | |
| 775 | ||
| 776 | 719 | TIMER_DEVICE_CALLBACK_MEMBER(bml3_state::keyboard_callback) |
| 777 | 720 | { |
| 778 | 721 | static const char *const portnames[3] = { "key1","key2","key3" }; |
| r24064 | r24065 | |
| 782 | 725 | { |
| 783 | 726 | m_keyb_scancode = (m_keyb_scancode + 1) & 0x7F; |
| 784 | 727 | if (m_keyb_counter_operation_disabled) { |
| 785 | m_keyb_scancode &= 0x | |
| 728 | m_keyb_scancode &= 0x7; | |
| 786 | 729 | } |
| 787 | 730 | |
| 788 | 731 | if (m_keyb_scancode == 0x7F) |
| r24064 | r24065 | |
| 850 | 793 | m_beep->set_frequency(1200); //guesswork |
| 851 | 794 | m_beep->set_state(0); |
| 852 | 795 | m_extram = auto_alloc_array(machine(),UINT8,0x10000); |
| 853 | ||
| 854 | // floppy callbacks | |
| 855 | if (m_wd17xx) { | |
| 856 | m_wd17xx->setup_intrq_cb(wd_fdc_t::line_cb(FUNC(bml3_state::bml3_wd17xx_intrq_w), this)); | |
| 857 | } | |
| 858 | 796 | } |
| 859 | 797 | |
| 860 | 798 | void bml3_state::machine_reset() |
| r24064 | r24065 | |
| 873 | 811 | m_firq_mask = -1; // disable firq |
| 874 | 812 | } |
| 875 | 813 | |
| 876 | const mc6843_interface bml3_6843_if = { NULL }; | |
| 877 | ||
| 878 | 814 | WRITE8_MEMBER(bml3_state::bml3_piaA_w) |
| 879 | 815 | { |
| 880 | 816 | address_space &mem = m_maincpu->space(AS_PROGRAM); |
| r24064 | r24065 | |
| 1045 | 981 | DEVCB_NULL // write B |
| 1046 | 982 | }; |
| 1047 | 983 | |
| 1048 | static const floppy_format_type bml3_floppy_formats[] = { | |
| 1049 | FLOPPY_D88_FORMAT, | |
| 1050 | NULL | |
| 984 | static const struct bml3bus_interface bml3bus_intf = | |
| 985 | { | |
| 986 | // interrupt lines | |
| 987 | DEVCB_DRIVER_MEMBER(bml3_state,bml3bus_nmi_w), | |
| 988 | DEVCB_DRIVER_MEMBER(bml3_state,bml3bus_irq_w), | |
| 989 | DEVCB_DRIVER_MEMBER(bml3_state,bml3bus_firq_w), | |
| 1051 | 990 | }; |
| 1052 | 991 | |
| 1053 | static SLOT_INTERFACE_START( bml3_mp1802_floppies ) | |
| 1054 | SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) | |
| 992 | static SLOT_INTERFACE_START(bml3_cards) | |
| 993 | SLOT_INTERFACE("bml3mp1802", BML3BUS_MP1802) /* MP-1802 Floppy Controller Card */ | |
| 994 | SLOT_INTERFACE("bml3mp1805", BML3BUS_MP1805) /* MP-1805 Floppy Controller Card */ | |
| 995 | SLOT_INTERFACE("bml3kanji", BML3BUS_KANJI) | |
| 1055 | 996 | SLOT_INTERFACE_END |
| 1056 | 997 | |
| 1057 | static const floppy_interface bml3_mp1805_floppy_interface = | |
| 1058 | { | |
| 1059 | DEVCB_NULL, | |
| 1060 | DEVCB_NULL, | |
| 1061 | DEVCB_NULL, | |
| 1062 | DEVCB_NULL, | |
| 1063 | DEVCB_NULL, | |
| 1064 | FLOPPY_STANDARD_3_SSDD, | |
| 1065 | LEGACY_FLOPPY_OPTIONS_NAME(default), | |
| 1066 | NULL | |
| 1067 | }; | |
| 1068 | 998 | |
| 1069 | //static SLOT_INTERFACE_START( bml3_mp1805_floppies ) | |
| 1070 | // SLOT_INTERFACE( "3ssdd", FLOPPY_3_SSDD ) | |
| 1071 | //SLOT_INTERFACE_END | |
| 1072 | ||
| 1073 | 999 | static MACHINE_CONFIG_START( bml3_common, bml3_state ) |
| 1074 | 1000 | /* basic machine hardware */ |
| 1075 | 1001 | MCFG_CPU_ADD("maincpu",M6809, CPU_CLOCK) |
| r24064 | r24065 | |
| 1101 | 1027 | MCFG_SOUND_ADD("beeper", BEEP, 0) |
| 1102 | 1028 | MCFG_SOUND_ROUTE(ALL_OUTPUTS,"mono",0.50) |
| 1103 | 1029 | |
| 1104 | MCFG_SOFTWARE_LIST_ADD("disk_list","bml3_flop") | |
| 1030 | /* slot devices */ | |
| 1031 | MCFG_BML3BUS_BUS_ADD("bml3bus", "maincpu", bml3bus_intf) | |
| 1032 | /* Default to MP-1805 disk (3" or 5.25" SS/SD), as our MB-6892 ROM dump includes | |
| 1033 | the MP-1805 ROM. | |
| 1034 | User may want to switch this to MP-1802 (5.25" DS/DD). | |
| 1035 | Note it isn't feasible to use both, as they each place boot ROM at F800. | |
| 1036 | */ | |
| 1037 | MCFG_BML3BUS_SLOT_ADD("bml3bus", "sl1", bml3_cards, "bml3mp1805") | |
| 1038 | MCFG_BML3BUS_SLOT_ADD("bml3bus", "sl2", bml3_cards, NULL) | |
| 1039 | MCFG_BML3BUS_SLOT_ADD("bml3bus", "sl3", bml3_cards, NULL) | |
| 1040 | MCFG_BML3BUS_SLOT_ADD("bml3bus", "sl4", bml3_cards, NULL) | |
| 1041 | MCFG_BML3BUS_SLOT_ADD("bml3bus", "sl5", bml3_cards, NULL) | |
| 1042 | MCFG_BML3BUS_SLOT_ADD("bml3bus", "sl6", bml3_cards, "bml3kanji") | |
| 1105 | 1043 | |
| 1106 | 1044 | MACHINE_CONFIG_END |
| 1107 | 1045 | |
| r24064 | r24065 | |
| 1109 | 1047 | MCFG_CPU_MODIFY( "maincpu" ) |
| 1110 | 1048 | MCFG_CPU_PROGRAM_MAP(bml3_mem) |
| 1111 | 1049 | |
| 1112 | // MCFG_MACHINE_START_OVERRIDE( bml3_state, bml3 ) | |
| 1113 | MACHINE_CONFIG_END | |
| 1114 | ||
| 1115 | static MACHINE_CONFIG_DERIVED( bml3a, bml3_common ) | |
| 1116 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1117 | MCFG_CPU_PROGRAM_MAP(bml3a_mem) | |
| 1118 | /* floppy */ | |
| 1119 | MCFG_MB8866x_ADD("wd17xx", CPU_CLOCK ) | |
| 1120 | MCFG_FLOPPY_DRIVE_ADD("wd17xx:0", bml3_mp1802_floppies, "525dd", bml3_floppy_formats) | |
| 1121 | MCFG_FLOPPY_DRIVE_ADD("wd17xx:1", bml3_mp1802_floppies, "525dd", bml3_floppy_formats) | |
| 1122 | MACHINE_CONFIG_END | |
| 1123 | ||
| 1124 | static MACHINE_CONFIG_DERIVED( bml3b, bml3_common ) | |
| 1125 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1126 | MCFG_CPU_PROGRAM_MAP(bml3b_mem) | |
| 1127 | /* floppy */ | |
| 1128 | MCFG_MC6843_ADD( "mc6843", bml3_6843_if ) | |
| 1129 | MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(bml3_mp1805_floppy_interface) | |
| 1130 | // MCFG_FLOPPY_DRIVE_ADD("mc6843:0", bml3_mp1805_floppies, "3ssdd", bml3_floppy_formats) | |
| 1131 | // MCFG_FLOPPY_DRIVE_ADD("mc6843:1", bml3_mp1805_floppies, "3ssdd", bml3_floppy_formats) | |
| 1132 | ||
| 1050 | #if 0 | |
| 1051 | // TODO: slot device for sound card | |
| 1133 | 1052 | // audio |
| 1134 | 1053 | MCFG_SOUND_ADD("ym2203", YM2203, 2000000) //unknown clock / divider |
| 1135 | 1054 | MCFG_YM2203_AY8910_INTF(&ay8910_config) |
| r24064 | r24065 | |
| 1137 | 1056 | MCFG_SOUND_ROUTE(1, "mono", 0.25) |
| 1138 | 1057 | MCFG_SOUND_ROUTE(2, "mono", 0.50) |
| 1139 | 1058 | MCFG_SOUND_ROUTE(3, "mono", 0.50) |
| 1059 | #endif | |
| 1140 | 1060 | MACHINE_CONFIG_END |
| 1141 | 1061 | |
| 1062 | static MACHINE_CONFIG_DERIVED( bml3mk2, bml3_common ) | |
| 1063 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1064 | MCFG_CPU_PROGRAM_MAP(bml3mk2_mem) | |
| 1142 | 1065 | |
| 1066 | // TODO: anything to add here? | |
| 1067 | MACHINE_CONFIG_END | |
| 1143 | 1068 | |
| 1069 | static MACHINE_CONFIG_DERIVED( bml3mk5, bml3_common ) | |
| 1070 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1071 | MCFG_CPU_PROGRAM_MAP(bml3mk5_mem) | |
| 1072 | ||
| 1073 | // TODO: anything to add here? | |
| 1074 | MACHINE_CONFIG_END | |
| 1075 | ||
| 1076 | ||
| 1077 | ||
| 1144 | 1078 | /* ROM definition */ |
| 1145 | 1079 | ROM_START( bml3 ) |
| 1146 | 1080 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) |
| 1147 | 1081 | // ROM_LOAD( "l3bas.rom", 0xa000, 0x6000, BAD_DUMP CRC(d81baa07) SHA1(a8fd6b29d8c505b756dbf5354341c48f9ac1d24d)) //original, 24k isn't a proper rom size! |
| 1148 | / | |
| 1082 | // TODO: replace with MB-6890 ROMs (these are from an MB-6892) | |
| 1149 | 1083 | ROM_LOAD( "598 p16611.ic3", 0xa000, 0x2000, BAD_DUMP CRC(954b9bad) SHA1(047948fac6808717c60a1d0ac9205a5725362430)) |
| 1150 | 1084 | ROM_LOAD( "599 p16561.ic4", 0xc000, 0x2000, BAD_DUMP CRC(b27a48f5) SHA1(94cb616df4caa6415c5076f9acdf675acb7453e2)) |
| 1151 | 1085 | // TODO: Replace checksums with a ROM dump without a disk controller patch (checksums here are inclusive of the MP1805 patch) |
| r24064 | r24065 | |
| 1155 | 1089 | ROM_LOAD("font.rom", 0x00000, 0x1000, BAD_DUMP CRC(0b6f2f10) SHA1(dc411b447ca414e94843636d8b5f910c954581fb) ) // handcrafted |
| 1156 | 1090 | |
| 1157 | 1091 | ROM_REGION( 0x8000, "vram", ROMREGION_ERASEFF ) |
| 1158 | ||
| 1159 | ROM_REGION( 0x20000, "kanji", ROMREGION_ERASEFF ) | |
| 1160 | ROM_LOAD("kanji.rom", 0x00000, 0x20000, NO_DUMP ) | |
| 1161 | 1092 | ROM_END |
| 1162 | 1093 | |
| 1163 | ROM_START( bml3 | |
| 1094 | ROM_START( bml3mk2 ) | |
| 1164 | 1095 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) |
| 1165 | 1096 | // ROM_LOAD( "l3bas.rom", 0xa000, 0x6000, BAD_DUMP CRC(d81baa07) SHA1(a8fd6b29d8c505b756dbf5354341c48f9ac1d24d)) //original, 24k isn't a proper rom size! |
| 1166 | / | |
| 1097 | // TODO: replace with MB-6891 ROMs (these are from an MB-6892) | |
| 1167 | 1098 | ROM_LOAD( "598 p16611.ic3", 0xa000, 0x2000, BAD_DUMP CRC(954b9bad) SHA1(047948fac6808717c60a1d0ac9205a5725362430)) |
| 1168 | 1099 | ROM_LOAD( "599 p16561.ic4", 0xc000, 0x2000, BAD_DUMP CRC(b27a48f5) SHA1(94cb616df4caa6415c5076f9acdf675acb7453e2)) |
| 1169 | // TODO: Replace checksums with a ROM dump without a disk controller patch (checksums here are inclusive of the MP1805 patch) | |
| 1170 | 1100 | ROM_LOAD( "600 p16681.ic5", 0xe000, 0x2000, BAD_DUMP CRC(fe3988a5) SHA1(edc732f1cd421e0cf45ffcfc71c5589958ceaae7)) |
| 1171 | 1101 | |
| 1172 | // MP-1502 disk controller ROM, which replaces part of the system ROM | |
| 1173 | ROM_LOAD( "mp1802.rom", 0xf800, 0x0800, BAD_DUMP CRC(8d0dc101) SHA1(92f7d1cebecafa7472e45c4999520de5c01c6dbc)) | |
| 1174 | ||
| 1175 | 1102 | ROM_REGION( 0x1000, "chargen", 0 ) |
| 1176 | 1103 | ROM_LOAD("font.rom", 0x00000, 0x1000, BAD_DUMP CRC(0b6f2f10) SHA1(dc411b447ca414e94843636d8b5f910c954581fb) ) // handcrafted |
| 1177 | 1104 | |
| 1178 | 1105 | ROM_REGION( 0x8000, "vram", ROMREGION_ERASEFF ) |
| 1179 | ||
| 1180 | ROM_REGION( 0x20000, "kanji", ROMREGION_ERASEFF ) | |
| 1181 | ROM_LOAD("kanji.rom", 0x00000, 0x20000, NO_DUMP ) | |
| 1182 | 1106 | ROM_END |
| 1183 | 1107 | |
| 1184 | ROM_START( bml3 | |
| 1108 | ROM_START( bml3mk5 ) | |
| 1185 | 1109 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) |
| 1186 | 1110 | // ROM_LOAD( "l3bas.rom", 0xa000, 0x6000, BAD_DUMP CRC(d81baa07) SHA1(a8fd6b29d8c505b756dbf5354341c48f9ac1d24d)) //original, 24k isn't a proper rom size! |
| 1187 | 1111 | /* Handcrafted ROMs, rom labels and contents might not match */ |
| r24064 | r24065 | |
| 1190 | 1114 | // TODO: Replace checksums with a ROM dump without a disk controller patch (checksums here are inclusive of the MP1805 patch) |
| 1191 | 1115 | ROM_LOAD( "600 p16681.ic5", 0xe000, 0x2000, BAD_DUMP CRC(fe3988a5) SHA1(edc732f1cd421e0cf45ffcfc71c5589958ceaae7)) |
| 1192 | 1116 | |
| 1193 | // MP-1505 disk controller ROM, which replaces part of the system ROM | |
| 1194 | ROM_LOAD( "mp1805.rom", 0xf800, 0x0800, BAD_DUMP CRC(b532d8d9) SHA1(6f1160356d5bf64b5926b1fdb60db414edf65f22)) | |
| 1195 | ||
| 1196 | 1117 | ROM_REGION( 0x1000, "chargen", 0 ) |
| 1197 | 1118 | ROM_LOAD("font.rom", 0x00000, 0x1000, BAD_DUMP CRC(0b6f2f10) SHA1(dc411b447ca414e94843636d8b5f910c954581fb) ) // handcrafted |
| 1198 | 1119 | |
| 1199 | 1120 | ROM_REGION( 0x8000, "vram", ROMREGION_ERASEFF ) |
| 1200 | ||
| 1201 | ROM_REGION( 0x20000, "kanji", ROMREGION_ERASEFF ) | |
| 1202 | ROM_LOAD("kanji.rom", 0x00000, 0x20000, NO_DUMP ) | |
| 1203 | 1121 | ROM_END |
| 1204 | 1122 | |
| 1205 | 1123 | /* Driver */ |
| 1206 | 1124 | |
| 1207 | /* Configurations are focussed on disk support rather than computer model. | |
| 1208 | * The following three models were produced: | |
| 1209 | * | |
| 1210 | * <year> / <model> / <name> | |
| 1211 | * 1980 / MB-6890 / Basic Master Level 3 | |
| 1212 | * 1982 / MB-6891 / Basic Master Level 3 Mark 2 | |
| 1213 | * 1983 / MB-6892 / Basic Master Level 3 Mark 5 | |
| 1214 | * | |
| 1215 | * If it turns out that these models had different ROMs or significant base hardware changes, then a model-oriented configuration | |
| 1216 | * set might be more appropriate. | |
| 1217 | */ | |
| 1218 | ||
| 1219 | 1125 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ |
| 1220 | 1126 | COMP( 1980, bml3, 0, 0, bml3, bml3, driver_device, 0, "Hitachi", "MB-6890 Basic Master Level 3", GAME_NOT_WORKING) |
| 1221 | COMP( 1980, bml3a, bml3, 0, bml3a, bml3, driver_device, 0, "Hitachi", "MB-6890 Basic Master Level 3 + MP-1502 (5.25\" disk)", 0) | |
| 1222 | COMP( 1980, bml3b, bml3, 0, bml3b, bml3, driver_device, 0, "Hitachi", "MB-6890 Basic Master Level 3 + MP-1505 (3\" disk) + YM-2203 (sound)", GAME_NOT_WORKING) | |
| 1127 | COMP( 1982, bml3mk2,bml3, 0, bml3mk2, bml3, driver_device, 0, "Hitachi", "MB-6891 Basic Master Level 3 Mark 2", GAME_NOT_WORKING) | |
| 1128 | COMP( 1983, bml3mk5,bml3, 0, bml3mk5, bml3, driver_device, 0, "Hitachi", "MB-6892 Basic Master Level 3 Mark 5", GAME_NOT_WORKING) |
| r24064 | r24065 | |
|---|---|---|
| 60 | 60 | $(IMGTOOL_MODULES)/cybiko.o \ |
| 61 | 61 | $(IMGTOOL_MODULES)/cybikoxt.o \ |
| 62 | 62 | $(IMGTOOL_MODULES)/psion.o \ |
| 63 | $(IMGTOOL_MODULES)/bml3.o \ | |
| 63 | 64 | |
| 64 | 65 | $(LIBIMGTOOL): $(IMGTOOL_LIB_OBJS) |
| 65 | 66 |
| r24064 | r24065 | |
|---|---|---|
| 111 | 111 | MODULE(cybiko) |
| 112 | 112 | MODULE(cybikoxt) |
| 113 | 113 | MODULE(psion) |
| 114 | MODULE(bml3) | |
| 114 | 115 | |
| 115 | 116 | #endif /* MODULES_RECURSIVE */ |
| r24064 | r24065 | |
|---|---|---|
| 807 | 807 | NULL /* 0xff */ |
| 808 | 808 | }; |
| 809 | 809 | |
| 810 | static const char *const bml3bas_statements[] = | |
| 811 | { | |
| 812 | "END", /* 0x80 */ | |
| 813 | "FOR", /* 0x81 */ | |
| 814 | "NEXT", /* 0x82 */ | |
| 815 | "DATA", /* 0x83 */ | |
| 816 | "DIM", /* 0x84 */ | |
| 817 | "READ", /* 0x85 */ | |
| 818 | "LET", /* 0x86 */ | |
| 819 | "GO", /* 0x87 */ | |
| 820 | "RUN", /* 0x88 */ | |
| 821 | "IF", /* 0x89 */ | |
| 822 | "RESTORE", /* 0x8a */ | |
| 823 | "RETURN", /* 0x8b */ | |
| 824 | "REM", /* 0x8c */ | |
| 825 | "'", /* 0x8d */ | |
| 826 | "STOP", /* 0x8e */ | |
| 827 | "ELSE", /* 0x8f */ | |
| 828 | "TRON", /* 0x90 */ | |
| 829 | "TROFF", /* 0x91 */ | |
| 830 | "SWAP", /* 0x92 */ | |
| 831 | "DEFSTR", /* 0x93 */ | |
| 832 | "DEFINT", /* 0x94 */ | |
| 833 | "DEFSNG", /* 0x95 */ | |
| 834 | "DEFDBL", /* 0x96 */ | |
| 835 | "ON", /* 0x97 */ | |
| 836 | "WAIT", /* 0x98 */ | |
| 837 | "RENUM", /* 0x99 */ | |
| 838 | "EDIT", /* 0x9a */ | |
| 839 | "ERROR", /* 0x9b */ | |
| 840 | "RESUME", /* 0x9c */ | |
| 841 | "AUTO", /* 0x9d */ | |
| 842 | "DELETE", /* 0x9e */ | |
| 843 | "TERM", /* 0x9f */ | |
| 844 | "WIDTH", /* 0xa0 */ | |
| 845 | "UNLIST", /* 0xa1 */ | |
| 846 | "MON", /* 0xa2 */ | |
| 847 | "LOCATE", /* 0xa3 */ | |
| 848 | "CLS", /* 0xa4 */ | |
| 849 | "CONSOLE", /* 0xa5 */ | |
| 850 | "PSET", /* 0xa6 */ | |
| 851 | "PRESET", /* 0xa7 */ | |
| 852 | "MOTOR", /* 0xa8 */ | |
| 853 | "SKIPF", /* 0xa9 */ | |
| 854 | "SAVE", /* 0xaa */ | |
| 855 | "LOAD", /* 0xab */ | |
| 856 | "MERGE", /* 0xac */ | |
| 857 | "EXEC", /* 0xad */ | |
| 858 | "OPEN", /* 0xae */ | |
| 859 | "CLOSE", /* 0xaf */ | |
| 860 | "FILES", /* 0xb0 */ | |
| 861 | "COM", /* 0xb1 */ | |
| 862 | "KEY", /* 0xb2 */ | |
| 863 | "PAINT", /* 0xb3 */ | |
| 864 | "BEEP", /* 0xb4 */ | |
| 865 | "COLOR", /* 0xb5 */ | |
| 866 | "LINE", /* 0xb6 */ | |
| 867 | "DEF", /* 0xb7 */ | |
| 868 | "POKE", /* 0xb8 */ | |
| 869 | "PRINT", /* 0xb9 */ | |
| 870 | "CONT", /* 0xba */ | |
| 871 | "LIST", /* 0xbb */ | |
| 872 | "CLEAR", /* 0xbc */ | |
| 873 | "RANDOMIZE",/* 0xbd */ | |
| 874 | "WHILE", /* 0xbe */ | |
| 875 | "WEND", /* 0xbf */ | |
| 876 | "NEW", /* 0xc0 */ | |
| 877 | "TAB(", /* 0xc1 */ | |
| 878 | "TO", /* 0xc2 */ | |
| 879 | "SUB", /* 0xc3 */ | |
| 880 | "FN", /* 0xc4 */ | |
| 881 | "SPC(", /* 0xc5 */ | |
| 882 | "USING", /* 0xc6 */ | |
| 883 | "USR", /* 0xc7 */ | |
| 884 | "ERL", /* 0xc8 */ | |
| 885 | "ERR", /* 0xc9 */ | |
| 886 | "OFF", /* 0xca */ | |
| 887 | "THEN", /* 0xcb */ | |
| 888 | "NOT", /* 0xcc */ | |
| 889 | "STEP", /* 0xcd */ | |
| 890 | "+", /* 0xce */ | |
| 891 | "-", /* 0xcf */ | |
| 892 | "*", /* 0xd0 */ | |
| 893 | "/", /* 0xd1 */ | |
| 894 | "^", /* 0xd2 */ | |
| 895 | "AND", /* 0xd3 */ | |
| 896 | "OR", /* 0xd4 */ | |
| 897 | "XOR", /* 0xd5 */ | |
| 898 | "EQV", /* 0xd6 */ | |
| 899 | "IMP", /* 0xd7 */ | |
| 900 | "MOD", /* 0xd8 */ | |
| 901 | "\\", /* 0xd9 */ | |
| 902 | ">", /* 0xda */ | |
| 903 | "=", /* 0xdb */ | |
| 904 | "<" /* 0xdc */ | |
| 905 | }; | |
| 906 | ||
| 907 | static const char *const bml3bas_functions[] = | |
| 908 | { | |
| 909 | "SGN", /* 0xff80 */ | |
| 910 | "INT", /* 0xff81 */ | |
| 911 | "ABS", /* 0xff82 */ | |
| 912 | "FRE", /* 0xff83 */ | |
| 913 | "POS", /* 0xff84 */ | |
| 914 | "SQR", /* 0xff85 */ | |
| 915 | "LOG", /* 0xff86 */ | |
| 916 | "EXP", /* 0xff87 */ | |
| 917 | "COS", /* 0xff88 */ | |
| 918 | "SIN", /* 0xff89 */ | |
| 919 | "TAN", /* 0xff8a */ | |
| 920 | "ATN", /* 0xff8b */ | |
| 921 | "PEEK", /* 0xff8c */ | |
| 922 | "LEN", /* 0xff8d */ | |
| 923 | "STR$", /* 0xff8e */ | |
| 924 | "VAL", /* 0xff8f */ | |
| 925 | "ASC", /* 0xff90 */ | |
| 926 | "CHR$", /* 0xff91 */ | |
| 927 | "CINT", /* 0xff92 */ | |
| 928 | "CSNG", /* 0xff93 */ | |
| 929 | "CDBL", /* 0xff94 */ | |
| 930 | "FIX", /* 0xff95 */ | |
| 931 | "SPACE$", /* 0xff96 */ | |
| 932 | "HEX$", /* 0xff97 */ | |
| 933 | "OCT$", /* 0xff98 */ | |
| 934 | "LOF", /* 0xff99 */ | |
| 935 | "EOF", /* 0xff9a */ | |
| 936 | "PEN", /* 0xff9b */ | |
| 937 | "LEFT$", /* 0xff9c */ | |
| 938 | "RIGHT$", /* 0xff9d */ | |
| 939 | "MID$", /* 0xff9e */ | |
| 940 | "INSTR", /* 0xff9f */ | |
| 941 | "SCREEN", /* 0xffa0 */ | |
| 942 | "VARPTR", /* 0xffa1 */ | |
| 943 | "STRING$", /* 0xffa2 */ | |
| 944 | "RND", /* 0xffa3 */ | |
| 945 | "INKEY$", /* 0xffa4 */ | |
| 946 | "INPUT", /* 0xffa5 */ | |
| 947 | "CSRLIN", /* 0xffa6 */ | |
| 948 | "POINT", /* 0xffa7 */ | |
| 949 | "TIME", /* 0xffa8 */ | |
| 950 | "DATE" /* 0xffa9 */ | |
| 951 | }; | |
| 952 | ||
| 953 | ||
| 810 | 954 | #ifdef BASIC_ |
| 811 | 955 | /* ----------------------------------------------------------------------- * |
| 812 | 956 | * CBM machines * |
| r24064 | r24065 | |
| 2923 | 3067 | case FILTINFO_PTR_WRITEFILE: info->write_file = vzbas_writefile; break; |
| 2924 | 3068 | } |
| 2925 | 3069 | } |
| 3070 | ||
| 3071 | ||
| 3072 | ||
| 3073 | /*************************************************************************** | |
| 3074 | BML3 BASIC | |
| 3075 | ***************************************************************************/ | |
| 3076 | ||
| 3077 | static const basictoken_tableent bml3bas_tokenents[] = | |
| 3078 | { | |
| 3079 | { 0x00, 0x80, bml3bas_statements, ARRAY_LENGTH(bml3bas_statements) }, | |
| 3080 | { 0xff, 0x80, bml3bas_functions, ARRAY_LENGTH(bml3bas_functions) } | |
| 3081 | }; | |
| 3082 | ||
| 3083 | static const basictokens bml3bas_tokens = | |
| 3084 | { | |
| 3085 | 0x2600, | |
| 3086 | 3, | |
| 3087 | TRUE, | |
| 3088 | bml3bas_tokenents, | |
| 3089 | ARRAY_LENGTH(bml3bas_tokenents) | |
| 3090 | }; | |
| 3091 | ||
| 3092 | static imgtoolerr_t bml3bas_readfile(imgtool_partition *partition, const char *filename, | |
| 3093 | const char *fork, imgtool_stream *destf) | |
| 3094 | { | |
| 3095 | return basic_readfile(&bml3bas_tokens, partition, filename, fork, destf); | |
| 3096 | } | |
| 3097 | ||
| 3098 | static imgtoolerr_t bml3bas_writefile(imgtool_partition *partition, const char *filename, | |
| 3099 | const char *fork, imgtool_stream *sourcef, option_resolution *opts) | |
| 3100 | { | |
| 3101 | return basic_writefile(&bml3bas_tokens, partition, filename, fork, sourcef, opts); | |
| 3102 | } | |
| 3103 | ||
| 3104 | void filter_bml3bas_getinfo(UINT32 state, union filterinfo *info) | |
| 3105 | { | |
| 3106 | switch(state) | |
| 3107 | { | |
| 3108 | case FILTINFO_STR_NAME: info->s = "bml3bas"; break; | |
| 3109 | case FILTINFO_STR_HUMANNAME: info->s = "Basic Master Level 3 Tokenized Basic Files"; break; | |
| 3110 | case FILTINFO_PTR_READFILE: info->read_file = bml3bas_readfile; break; | |
| 3111 | case FILTINFO_PTR_WRITEFILE: info->write_file = bml3bas_writefile; break; | |
| 3112 | } | |
| 3113 | } | |
| 3114 |
| r24064 | r24065 | |
|---|---|---|
| 58 | 58 | filter_thombas7_getinfo, |
| 59 | 59 | filter_thombas128_getinfo, |
| 60 | 60 | filter_thomcrypt_getinfo, |
| 61 | filter_bml3bas_getinfo, | |
| 61 | 62 | NULL |
| 62 | 63 | }; |
| 63 | 64 |
| r0 | r24065 | |
|---|---|---|
| 1 | /**************************************************************************** | |
| 2 | ||
| 3 | bml3.c | |
| 4 | ||
| 5 | Hitachi bml3 disk images | |
| 6 | ||
| 7 | By Jonathan Edwards, based on rsdos.c (both use Microsoft BASIC) | |
| 8 | ||
| 9 | ****************************************************************************/ | |
| 10 | ||
| 11 | /* Supported Hitachi floppy formats are: | |
| 12 | - 3" or 5"1/4 single density, single-sided: 40 tracks, 16 sectors/track, 128 bytes/sector | |
| 13 | - (used with MP-1805 floppy disk controller card) | |
| 14 | - 5"1/4 double density, double-sided: 40 tracks, 16 sectors/track, 256 bytes/sector | |
| 15 | - (first track on first head may be single density) | |
| 16 | - (used with MP-1802 floppy disk controller card) | |
| 17 | */ | |
| 18 | ||
| 19 | #include <stdio.h> | |
| 20 | #include <string.h> | |
| 21 | #include <stdlib.h> | |
| 22 | #include "imgtool.h" | |
| 23 | #include "iflopimg.h" | |
| 24 | ||
| 25 | #define MAX_SECTOR_SIZE 256 | |
| 26 | ||
| 27 | struct bml3_diskinfo | |
| 28 | { | |
| 29 | UINT16 sector_size; /* 128 or 256 */ | |
| 30 | UINT8 heads; /* 1 or 2 */ | |
| 31 | UINT8 fat_start_sector; /* in cylinder 20, start sector of FAT */ | |
| 32 | UINT8 fat_start_offset; /* start byte of FAT in sector */ | |
| 33 | UINT8 fat_sectors; /* the number of sectors in the FAT */ | |
| 34 | UINT8 dirent_start_sector; /* in cylinder 20, start sector of directory entries */ | |
| 35 | UINT8 granule_sectors; /* how many sectors per granule */ | |
| 36 | UINT8 first_granule_cylinder; /* the number of the first cylinder with granule numbers assigned */ | |
| 37 | UINT8 variant; /* 0 - older version, uses EOF to terminate files, 1 - newer version, stores file length */ | |
| 38 | }; | |
| 39 | ||
| 40 | /* this structure mirrors the structure of a directory entry on disk */ | |
| 41 | struct bml3_dirent | |
| 42 | { | |
| 43 | char fname[8]; | |
| 44 | char fext[3]; | |
| 45 | UINT8 ftype; | |
| 46 | UINT8 asciiflag; | |
| 47 | UINT8 first_granule; | |
| 48 | UINT16 lastsectorbytes; | |
| 49 | // TODO there are some 'unused' bytes here that are sometimes used to store a timestamp, maybe support this? | |
| 50 | }; | |
| 51 | ||
| 52 | struct bml3_direnum | |
| 53 | { | |
| 54 | int index; | |
| 55 | int eof; | |
| 56 | }; | |
| 57 | ||
| 58 | #define MAX_GRANULEMAP_SIZE 256 | |
| 59 | ||
| 60 | struct granule_list_t { | |
| 61 | UINT8 granules[MAX_GRANULEMAP_SIZE]; | |
| 62 | UINT8 granule_count; | |
| 63 | UINT8 last_granule_sectors; | |
| 64 | }; | |
| 65 | ||
| 66 | #define BML3_OPTIONS_FTYPE 'T' | |
| 67 | #define BML3_OPTIONS_ASCII 'M' | |
| 68 | ||
| 69 | static imgtoolerr_t bml3_diskimage_deletefile(imgtool_partition *partition, const char *fname); | |
| 70 | ||
| 71 | ||
| 72 | ||
| 73 | /********************************************************************* | |
| 74 | Imgtool module code | |
| 75 | *********************************************************************/ | |
| 76 | ||
| 77 | static bml3_diskinfo *bml3_get_diskinfo(imgtool_image *image) | |
| 78 | { | |
| 79 | return (bml3_diskinfo *) imgtool_floppy_extrabytes(image); | |
| 80 | } | |
| 81 | ||
| 82 | ||
| 83 | ||
| 84 | static int max_dirents(imgtool_image *image) | |
| 85 | { | |
| 86 | bml3_diskinfo *info = bml3_get_diskinfo(image); | |
| 87 | return (16 * info->heads + 1 - info->dirent_start_sector)*(info->sector_size/32); | |
| 88 | } | |
| 89 | ||
| 90 | ||
| 91 | ||
| 92 | static void dirent_location(imgtool_image *image, int index_loc, UINT8 *head, UINT8 *track, UINT8 *sector, UINT8 *offset) | |
| 93 | { | |
| 94 | bml3_diskinfo *info = bml3_get_diskinfo(image); | |
| 95 | *track = 20; | |
| 96 | *sector = info->dirent_start_sector + index_loc / (info->sector_size / 32); | |
| 97 | *head = 0; | |
| 98 | if (*sector > 16) { | |
| 99 | // wrap to second head | |
| 100 | *sector -= 16; | |
| 101 | (*head)++; | |
| 102 | } | |
| 103 | *offset = index_loc % (info->sector_size/32) * 32; | |
| 104 | } | |
| 105 | ||
| 106 | ||
| 107 | ||
| 108 | static floperr_t get_bml3_dirent(imgtool_image *f, int index_loc, struct bml3_dirent *ent) | |
| 109 | { | |
| 110 | floperr_t err; | |
| 111 | UINT8 head, track, sector, offset; | |
| 112 | UINT8 buf[32]; | |
| 113 | bml3_diskinfo *info = bml3_get_diskinfo(f); | |
| 114 | dirent_location(f, index_loc, &head, &track, §or, &offset); | |
| 115 | err = floppy_read_sector(imgtool_floppy(f), head, track, sector, offset, (void *) buf, sizeof(buf)); | |
| 116 | memset(ent, 0, sizeof(*ent)); | |
| 117 | switch (info->variant) { | |
| 118 | case 0: | |
| 119 | memcpy(&ent->fname, &buf[0], 8); | |
| 120 | ent->ftype = buf[11]; | |
| 121 | ent->asciiflag = buf[12]; | |
| 122 | ent->first_granule = buf[14]; | |
| 123 | break; | |
| 124 | case 1: | |
| 125 | memcpy(&ent->fname, &buf[0], 8); | |
| 126 | memcpy(&ent->fext, &buf[8], 3); | |
| 127 | ent->ftype = buf[11]; | |
| 128 | ent->asciiflag = buf[12]; | |
| 129 | ent->first_granule = buf[13]; | |
| 130 | ent->lastsectorbytes = (buf[14] << 8) | buf[15]; | |
| 131 | break; | |
| 132 | default: | |
| 133 | return FLOPPY_ERROR_INVALIDIMAGE; | |
| 134 | } | |
| 135 | return err; | |
| 136 | } | |
| 137 | ||
| 138 | ||
| 139 | ||
| 140 | static floperr_t put_bml3_dirent(imgtool_image *f, int index_loc, const struct bml3_dirent *ent) | |
| 141 | { | |
| 142 | floperr_t err; | |
| 143 | UINT8 head, track, sector, offset; | |
| 144 | UINT8 buf[32]; | |
| 145 | bml3_diskinfo *info = bml3_get_diskinfo(f); | |
| 146 | if (index_loc >= max_dirents(f)) | |
| 147 | return (floperr_t)IMGTOOLERR_FILENOTFOUND; | |
| 148 | dirent_location(f, index_loc, &head, &track, §or, &offset); | |
| 149 | memset(buf, 0, sizeof(buf)); | |
| 150 | switch (info->variant) { | |
| 151 | case 0: | |
| 152 | memcpy(&buf[0], &ent->fname, 8); | |
| 153 | buf[11] = ent->ftype; | |
| 154 | buf[12] = ent->asciiflag; | |
| 155 | buf[14] = ent->first_granule; | |
| 156 | break; | |
| 157 | case 1: | |
| 158 | memcpy(&buf[0], &ent->fname, 8); | |
| 159 | memcpy(&buf[8], &ent->fext, 3); | |
| 160 | buf[11] = ent->ftype; | |
| 161 | buf[12] = ent->asciiflag; | |
| 162 | buf[13] = ent->first_granule; | |
| 163 | buf[14] = ent->lastsectorbytes >> 8; | |
| 164 | buf[15] = ent->lastsectorbytes & 0xff; | |
| 165 | break; | |
| 166 | default: | |
| 167 | return FLOPPY_ERROR_INVALIDIMAGE; | |
| 168 | } | |
| 169 | err = floppy_write_sector(imgtool_floppy(f), head, track, sector, offset, (void *) buf, sizeof(buf), 0); /* TODO: pass ddam argument from imgtool */ | |
| 170 | return err; | |
| 171 | } | |
| 172 | ||
| 173 | ||
| 174 | ||
| 175 | /* fnamebuf must have at least 13 bytes */ | |
| 176 | static void get_dirent_fname(char *fnamebuf, const struct bml3_dirent *ent) | |
| 177 | { | |
| 178 | char *s; | |
| 179 | ||
| 180 | memset(fnamebuf, 0, 13); | |
| 181 | memcpy(fnamebuf, ent->fname, sizeof(ent->fname)); | |
| 182 | rtrim(fnamebuf); | |
| 183 | s = fnamebuf + strlen(fnamebuf); | |
| 184 | *(s++) = '.'; | |
| 185 | memcpy(s, ent->fext, sizeof(ent->fext)); | |
| 186 | rtrim(s); | |
| 187 | ||
| 188 | /* If no extension, remove period */ | |
| 189 | if (*s == '\0') | |
| 190 | s[-1] = '\0'; | |
| 191 | } | |
| 192 | ||
| 193 | ||
| 194 | ||
| 195 | static imgtoolerr_t lookup_bml3_file(imgtool_image *f, const char *fname, struct bml3_dirent *ent, int *position) | |
| 196 | { | |
| 197 | int i; | |
| 198 | floperr_t ferr; | |
| 199 | char fnamebuf[13]; | |
| 200 | ||
| 201 | i = 0; | |
| 202 | fnamebuf[0] = '\0'; | |
| 203 | ||
| 204 | do | |
| 205 | { | |
| 206 | do | |
| 207 | { | |
| 208 | ferr = get_bml3_dirent(f, i++, ent); | |
| 209 | if (ferr) | |
| 210 | return imgtool_floppy_error(ferr); | |
| 211 | } | |
| 212 | while(ent->fname[0] == '\0'); | |
| 213 | ||
| 214 | ||
| 215 | if (ent->fname[0] != -1) | |
| 216 | get_dirent_fname(fnamebuf, ent); | |
| 217 | } | |
| 218 | while((ent->fname[0] != -1) && core_stricmp(fnamebuf, fname)); | |
| 219 | ||
| 220 | if (ent->fname[0] == -1) | |
| 221 | return IMGTOOLERR_FILENOTFOUND; | |
| 222 | ||
| 223 | if (position) | |
| 224 | *position = i - 1; | |
| 225 | return (imgtoolerr_t)0; | |
| 226 | } | |
| 227 | ||
| 228 | ||
| 229 | ||
| 230 | static UINT8 get_granule_count(imgtool_image *img) | |
| 231 | { | |
| 232 | // UINT16 tracks; | |
| 233 | UINT16 disk_granules; | |
| 234 | bml3_diskinfo *info = bml3_get_diskinfo(img); | |
| 235 | ||
| 236 | // This always returns 82 for D88, so not quite right | |
| 237 | // tracks = floppy_get_tracks_per_disk(imgtool_floppy(img)); | |
| 238 | ||
| 239 | // The number of granules is primarily constrained by the disk capacity. | |
| 240 | disk_granules = (40 - 1 - info->first_granule_cylinder) * info->heads * (16 / info->granule_sectors); | |
| 241 | // Also, granule numbers from 0xC0 upwards are reserved for terminating a granule chain | |
| 242 | return (UINT8)((disk_granules < 0xC0) ? disk_granules : 0xC0); | |
| 243 | } | |
| 244 | ||
| 245 | /* granule_map must be an array of MAX_GRANULEMAP_SIZE bytes */ | |
| 246 | static floperr_t get_granule_map(imgtool_image *img, UINT8 *granule_map, UINT8 *granule_count) | |
| 247 | { | |
| 248 | bml3_diskinfo *info = bml3_get_diskinfo(img); | |
| 249 | UINT8 count; | |
| 250 | ||
| 251 | count = get_granule_count(img); | |
| 252 | if (granule_count) | |
| 253 | *granule_count = count; | |
| 254 | ||
| 255 | // The first byte of the granule map sector is ignored (and expected to be 0) | |
| 256 | return floppy_read_sector(imgtool_floppy(img), 0, 20, info->fat_start_sector, info->fat_start_offset, granule_map, count); | |
| 257 | } | |
| 258 | ||
| 259 | ||
| 260 | ||
| 261 | static floperr_t put_granule_map(imgtool_image *img, const UINT8 *granule_map, UINT8 granule_count) | |
| 262 | { | |
| 263 | bml3_diskinfo *info = bml3_get_diskinfo(img); | |
| 264 | return floppy_write_sector(imgtool_floppy(img), 0, 20, info->fat_start_sector, info->fat_start_offset, granule_map, granule_count, 0); /* TODO: pass ddam argument from imgtool */ | |
| 265 | } | |
| 266 | ||
| 267 | ||
| 268 | ||
| 269 | ||
| 270 | static void granule_location(imgtool_image *image, UINT8 granule, UINT8 *head, UINT8 *track, UINT8 *sector) | |
| 271 | { | |
| 272 | bml3_diskinfo *info = bml3_get_diskinfo(image); | |
| 273 | UINT16 abs_track = granule * info->granule_sectors / 16; | |
| 274 | *head = abs_track % info->heads; | |
| 275 | *track = abs_track / info->heads + info->first_granule_cylinder; | |
| 276 | // skip filesystem cylinder | |
| 277 | if (*track >= 20) | |
| 278 | (*track)++; | |
| 279 | *sector = granule * info->granule_sectors % 16 + 1; | |
| 280 | } | |
| 281 | ||
| 282 | ||
| 283 | ||
| 284 | static imgtoolerr_t transfer_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *f, imgtoolerr_t (*proc)(imgtool_image *, int, int, int, int, size_t, imgtool_stream *)) | |
| 285 | { | |
| 286 | imgtoolerr_t err = IMGTOOLERR_SUCCESS; | |
| 287 | UINT8 head, track, sector; | |
| 288 | granule_location(img, granule, &head, &track, §or); | |
| 289 | if (length > 0) | |
| 290 | err = proc(img, head, track, sector, 0, length, f); | |
| 291 | return err; | |
| 292 | } | |
| 293 | ||
| 294 | ||
| 295 | static imgtoolerr_t transfer_from_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *destf) | |
| 296 | { | |
| 297 | return transfer_granule(img, granule, length, destf, imgtool_floppy_read_sector_to_stream); | |
| 298 | } | |
| 299 | ||
| 300 | ||
| 301 | ||
| 302 | static imgtoolerr_t transfer_to_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *sourcef) | |
| 303 | { | |
| 304 | return transfer_granule(img, granule, length, sourcef, imgtool_floppy_write_sector_from_stream); | |
| 305 | } | |
| 306 | ||
| 307 | ||
| 308 | ||
| 309 | static floperr_t read_granule(imgtool_image *img, UINT8 granule, int offset, int length, UINT8 *buf) | |
| 310 | { | |
| 311 | UINT8 head, track, sector; | |
| 312 | granule_location(img, granule, &head, &track, §or); | |
| 313 | return floppy_read_sector(imgtool_floppy(img), head, track, sector, offset, buf, length); | |
| 314 | } | |
| 315 | ||
| 316 | ||
| 317 | ||
| 318 | static floperr_t write_granule(imgtool_image *img, UINT8 granule, int offset, int length, const UINT8 *buf) | |
| 319 | { | |
| 320 | UINT8 head, track, sector; | |
| 321 | granule_location(img, granule, &head, &track, §or); | |
| 322 | return floppy_write_sector(imgtool_floppy(img), head, track, sector, offset, buf, length, 0); /* TODO: pass ddam argument from imgtool */ | |
| 323 | } | |
| 324 | ||
| 325 | ||
| 326 | ||
| 327 | static imgtoolerr_t list_granules(struct bml3_dirent *ent, imgtool_image *img, struct granule_list_t *granule_list) | |
| 328 | { | |
| 329 | floperr_t ferr; | |
| 330 | UINT8 max_granules; | |
| 331 | UINT8 granule; | |
| 332 | UINT8 usedmap[MAX_GRANULEMAP_SIZE]; /* Used to detect infinite loops */ | |
| 333 | UINT8 granule_map[MAX_GRANULEMAP_SIZE]; | |
| 334 | bml3_diskinfo *info = bml3_get_diskinfo(img); | |
| 335 | ||
| 336 | ferr = get_granule_map(img, granule_map, &max_granules); | |
| 337 | if (ferr) | |
| 338 | return imgtool_floppy_error(ferr); | |
| 339 | ||
| 340 | memset(usedmap, 0, max_granules); | |
| 341 | ||
| 342 | granule = ent->first_granule; | |
| 343 | granule_list->granule_count = 0; | |
| 344 | ||
| 345 | while(!usedmap[granule] && granule < max_granules) | |
| 346 | { | |
| 347 | usedmap[granule] = 1; | |
| 348 | granule_list->granules[granule_list->granule_count++] = granule; | |
| 349 | granule = granule_map[granule]; | |
| 350 | } | |
| 351 | ||
| 352 | granule_list->last_granule_sectors = granule - 0xc0; | |
| 353 | if (info->variant == 0) { | |
| 354 | // add final incomplete sector | |
| 355 | granule_list->last_granule_sectors++; | |
| 356 | } | |
| 357 | ||
| 358 | // A value of zero (variant 1) and max (variant 0) seem to indicate a file open for writing. | |
| 359 | // Strictly speaking this means the image is corrupt, although a real system will happily read | |
| 360 | // garbage from the file. | |
| 361 | if (granule_list->last_granule_sectors > info->granule_sectors) | |
| 362 | return IMGTOOLERR_CORRUPTIMAGE; | |
| 363 | ||
| 364 | return IMGTOOLERR_SUCCESS; | |
| 365 | } | |
| 366 | ||
| 367 | ||
| 368 | ||
| 369 | static imgtoolerr_t get_file_size(struct bml3_dirent *ent, imgtool_image *img, const struct granule_list_t *granule_list, size_t *size) | |
| 370 | { | |
| 371 | floperr_t ferr; | |
| 372 | size_t last_sector_bytes = 0; | |
| 373 | bml3_diskinfo *info = bml3_get_diskinfo(img); | |
| 374 | ||
| 375 | // TODO are these special cases valid, or maybe indicate a corrupt image? | |
| 376 | if (granule_list->granule_count == 0) { | |
| 377 | *size = 0; | |
| 378 | return IMGTOOLERR_SUCCESS; | |
| 379 | } | |
| 380 | else if (granule_list->last_granule_sectors == 0) { | |
| 381 | *size = info->sector_size * ((granule_list->granule_count - 1) * info->granule_sectors); | |
| 382 | return IMGTOOLERR_SUCCESS; | |
| 383 | } | |
| 384 | ||
| 385 | // determine size excluding final sector | |
| 386 | *size = info->sector_size * ((granule_list->granule_count - 1) * info->granule_sectors + granule_list->last_granule_sectors - 1); | |
| 387 | ||
| 388 | // determine bytes used in final sector | |
| 389 | switch (info->variant) { | |
| 390 | case 0: | |
| 391 | // look for EOF (ASCII SUB) and trailing NULs in final sector | |
| 392 | { | |
| 393 | UINT8 buf[MAX_SECTOR_SIZE]; | |
| 394 | ferr = read_granule(img, granule_list->granules[granule_list->granule_count-1], info->sector_size * (granule_list->last_granule_sectors - 1), info->sector_size, buf); | |
| 395 | if (ferr) | |
| 396 | return imgtool_floppy_error(ferr); | |
| 397 | for (last_sector_bytes = info->sector_size - 1; last_sector_bytes >= 0; last_sector_bytes--) { | |
| 398 | if (buf[last_sector_bytes] != 0) | |
| 399 | break; | |
| 400 | } | |
| 401 | if (buf[last_sector_bytes] != 0x1a) { | |
| 402 | last_sector_bytes++; | |
| 403 | } | |
| 404 | } | |
| 405 | break; | |
| 406 | case 1: | |
| 407 | last_sector_bytes = ent->lastsectorbytes; | |
| 408 | break; | |
| 409 | } | |
| 410 | ||
| 411 | // TODO is it valid for last_sector_bytes == 0? | |
| 412 | if (last_sector_bytes < 0 || last_sector_bytes > info->sector_size) { | |
| 413 | return IMGTOOLERR_CORRUPTIMAGE; | |
| 414 | } | |
| 415 | *size += last_sector_bytes; | |
| 416 | return IMGTOOLERR_SUCCESS; | |
| 417 | } | |
| 418 | ||
| 419 | ||
| 420 | ||
| 421 | static imgtoolerr_t process_bml3_file(struct bml3_dirent *ent, imgtool_image *img, imgtool_stream *destf, size_t *size) | |
| 422 | { | |
| 423 | imgtoolerr_t err; | |
| 424 | size_t remaining_size, granule_size; | |
| 425 | bml3_diskinfo *info = bml3_get_diskinfo(img); | |
| 426 | struct granule_list_t granule_list; | |
| 427 | granule_list.granule_count = 0; | |
| 428 | ||
| 429 | err = list_granules(ent, img, &granule_list); | |
| 430 | if (err) | |
| 431 | return err; | |
| 432 | err = get_file_size(ent, img, &granule_list, size); | |
| 433 | if (err) | |
| 434 | return err; | |
| 435 | ||
| 436 | if (destf) { | |
| 437 | remaining_size = *size; | |
| 438 | granule_size = info->granule_sectors * info->sector_size; | |
| 439 | ||
| 440 | for (int c = 0; c < granule_list.granule_count; c++) { | |
| 441 | if (granule_size >= remaining_size) | |
| 442 | granule_size = remaining_size; | |
| 443 | transfer_from_granule(img, granule_list.granules[c], granule_size, destf); | |
| 444 | remaining_size -= granule_size; | |
| 445 | } | |
| 446 | } | |
| 447 | return IMGTOOLERR_SUCCESS; | |
| 448 | } | |
| 449 | ||
| 450 | ||
| 451 | ||
| 452 | /* create a new directory entry with a specified name */ | |
| 453 | static imgtoolerr_t prepare_dirent(UINT8 variant, struct bml3_dirent *ent, const char *fname) | |
| 454 | { | |
| 455 | const char *fname_end; | |
| 456 | const char *fname_ext; | |
| 457 | int fname_ext_len; | |
| 458 | ||
| 459 | memset(ent, '\0', sizeof(*ent)); | |
| 460 | memset(ent->fname, ' ', sizeof(ent->fname)); | |
| 461 | memset(ent->fext, ' ', sizeof(ent->fext)); | |
| 462 | ||
| 463 | fname_end = strchr(fname, '.'); | |
| 464 | if (fname_end) | |
| 465 | fname_ext = fname_end + 1; | |
| 466 | else | |
| 467 | fname_end = fname_ext = fname + strlen(fname); | |
| 468 | ||
| 469 | fname_ext_len = strlen(fname_ext); | |
| 470 | ||
| 471 | switch (variant) { | |
| 472 | case 0: | |
| 473 | /* 8-character max filename */ | |
| 474 | if (((fname_end - fname) > 8) || (fname_ext_len > 0)) | |
| 475 | return IMGTOOLERR_BADFILENAME; | |
| 476 | break; | |
| 477 | case 1: | |
| 478 | /*8.3 filename */ | |
| 479 | if (((fname_end - fname) > 8) || (fname_ext_len > 3)) | |
| 480 | return IMGTOOLERR_BADFILENAME; | |
| 481 | break; | |
| 482 | default: | |
| 483 | return IMGTOOLERR_CORRUPTIMAGE; | |
| 484 | } | |
| 485 | ||
| 486 | memcpy(ent->fname, fname, fname_end - fname); | |
| 487 | memcpy(ent->fext, fname_ext, fname_ext_len); | |
| 488 | ||
| 489 | /* By default, set as a type 2 binary file */ | |
| 490 | ent->ftype = 2; | |
| 491 | ent->asciiflag = 0; | |
| 492 | return IMGTOOLERR_SUCCESS; | |
| 493 | } | |
| 494 | ||
| 495 | ||
| 496 | ||
| 497 | static imgtoolerr_t bml3_diskimage_open(imgtool_image *image, imgtool_stream *stream) | |
| 498 | { | |
| 499 | // imgtoolerr_t err; | |
| 500 | floperr_t ferr; | |
| 501 | bml3_diskinfo *info = bml3_get_diskinfo(image); | |
| 502 | floppy_image_legacy *floppy = imgtool_floppy(image); | |
| 503 | const struct FloppyCallbacks *callbacks = floppy_callbacks(floppy); | |
| 504 | ||
| 505 | // probe disk geometry to guess format | |
| 506 | int heads_per_disk = callbacks->get_heads_per_disk(floppy); | |
| 507 | UINT32 sector_length; | |
| 508 | ferr = callbacks->get_sector_length(floppy, 0, 20, 1, §or_length); | |
| 509 | if (ferr) | |
| 510 | return imgtool_floppy_error(ferr); | |
| 511 | int sectors_per_track = callbacks->get_sectors_per_track(floppy, 0, 20); | |
| 512 | ||
| 513 | if (heads_per_disk == 2 && sector_length == 128 && sectors_per_track == 16) { | |
| 514 | // single-sided, single-density | |
| 515 | info->sector_size = 128; | |
| 516 | info->heads = 1; | |
| 517 | info->fat_start_sector = 1; | |
| 518 | info->fat_start_offset = 5; | |
| 519 | info->fat_sectors = 2; | |
| 520 | info->dirent_start_sector = 7; | |
| 521 | info->granule_sectors = 4; | |
| 522 | info->first_granule_cylinder = 0; | |
| 523 | info->variant = 0; | |
| 524 | } | |
| 525 | else if (heads_per_disk == 2 && sector_length == 256 && sectors_per_track == 16) { | |
| 526 | // double-sided, double-density | |
| 527 | info->sector_size = 256; | |
| 528 | info->heads = 2; | |
| 529 | info->fat_start_sector = 2; | |
| 530 | info->fat_start_offset = 1; | |
| 531 | info->fat_sectors = 1; | |
| 532 | info->dirent_start_sector = 5; | |
| 533 | info->granule_sectors = 8; | |
| 534 | info->first_granule_cylinder = 1; | |
| 535 | info->variant = 1; | |
| 536 | } | |
| 537 | else { | |
| 538 | // invalid or unsupported format | |
| 539 | return IMGTOOLERR_CORRUPTIMAGE; | |
| 540 | } | |
| 541 | ||
| 542 | return IMGTOOLERR_SUCCESS; | |
| 543 | } | |
| 544 | ||
| 545 | ||
| 546 | ||
| 547 | static imgtoolerr_t bml3_diskimage_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) | |
| 548 | { | |
| 549 | floperr_t ferr; | |
| 550 | imgtoolerr_t err; | |
| 551 | size_t filesize; | |
| 552 | struct bml3_direnum *rsenum; | |
| 553 | struct bml3_dirent rsent; | |
| 554 | char fname[13]; | |
| 555 | imgtool_image *image; | |
| 556 | ||
| 557 | image = imgtool_directory_image(enumeration); | |
| 558 | rsenum = (struct bml3_direnum *) imgtool_directory_extrabytes(enumeration); | |
| 559 | ||
| 560 | /* Did we hit the end of file before? */ | |
| 561 | if (rsenum->eof) | |
| 562 | goto eof; | |
| 563 | ||
| 564 | do | |
| 565 | { | |
| 566 | if (rsenum->index >= max_dirents(image)) | |
| 567 | goto eof; | |
| 568 | ||
| 569 | ferr = get_bml3_dirent(image, rsenum->index++, &rsent); | |
| 570 | if (ferr) | |
| 571 | return imgtool_floppy_error(ferr); | |
| 572 | } | |
| 573 | while(rsent.fname[0] == '\0'); | |
| 574 | ||
| 575 | /* Now are we at the eof point? */ | |
| 576 | if (rsent.fname[0] == -1) | |
| 577 | { | |
| 578 | rsenum->eof = 1; | |
| 579 | eof: | |
| 580 | ent->eof = 1; | |
| 581 | } | |
| 582 | else | |
| 583 | { | |
| 584 | /* Not the end of file */ | |
| 585 | err = process_bml3_file(&rsent, image, NULL, &filesize); | |
| 586 | if (err) | |
| 587 | return err; | |
| 588 | ||
| 589 | if (filesize == ((size_t) -1)) | |
| 590 | { | |
| 591 | /* corrupt! */ | |
| 592 | ent->filesize = 0; | |
| 593 | ent->corrupt = 1; | |
| 594 | } | |
| 595 | else | |
| 596 | { | |
| 597 | ent->filesize = filesize; | |
| 598 | ent->corrupt = 0; | |
| 599 | } | |
| 600 | ent->eof = 0; | |
| 601 | ||
| 602 | get_dirent_fname(fname, &rsent); | |
| 603 | ||
| 604 | snprintf(ent->filename, ARRAY_LENGTH(ent->filename), "%s", fname); | |
| 605 | snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); | |
| 606 | } | |
| 607 | return IMGTOOLERR_SUCCESS; | |
| 608 | } | |
| 609 | ||
| 610 | ||
| 611 | ||
| 612 | static imgtoolerr_t bml3_diskimage_freespace(imgtool_partition *partition, UINT64 *size) | |
| 613 | { | |
| 614 | floperr_t ferr; | |
| 615 | UINT8 i; | |
| 616 | size_t s = 0; | |
| 617 | UINT8 granule_count; | |
| 618 | UINT8 granule_map[MAX_GRANULEMAP_SIZE]; | |
| 619 | imgtool_image *image = imgtool_partition_image(partition); | |
| 620 | bml3_diskinfo *info = bml3_get_diskinfo(image); | |
| 621 | ||
| 622 | ferr = get_granule_map(image, granule_map, &granule_count); | |
| 623 | if (ferr) | |
| 624 | return imgtool_floppy_error(ferr); | |
| 625 | ||
| 626 | for (i = 0; i < granule_count; i++) | |
| 627 | { | |
| 628 | if (granule_map[i] == 0xff) | |
| 629 | s += (info->granule_sectors * info->sector_size); | |
| 630 | } | |
| 631 | *size = s; | |
| 632 | return (imgtoolerr_t)FLOPPY_ERROR_SUCCESS; | |
| 633 | } | |
| 634 | ||
| 635 | ||
| 636 | ||
| 637 | static imgtoolerr_t delete_entry(imgtool_image *img, struct bml3_dirent *ent, int pos) | |
| 638 | { | |
| 639 | floperr_t ferr; | |
| 640 | unsigned char g, i; | |
| 641 | UINT8 granule_count; | |
| 642 | UINT8 granule_map[MAX_GRANULEMAP_SIZE]; | |
| 643 | ||
| 644 | /* Write a NUL in the filename, marking it deleted */ | |
| 645 | ent->fname[0] = 0; | |
| 646 | ferr = put_bml3_dirent(img, pos, ent); | |
| 647 | if (ferr) | |
| 648 | return imgtool_floppy_error(ferr); | |
| 649 | ||
| 650 | ferr = get_granule_map(img, granule_map, &granule_count); | |
| 651 | if (ferr) | |
| 652 | return imgtool_floppy_error(ferr); | |
| 653 | ||
| 654 | /* Now free up the granules */ | |
| 655 | g = ent->first_granule; | |
| 656 | while (g < granule_count) | |
| 657 | { | |
| 658 | i = granule_map[g]; | |
| 659 | granule_map[g] = 0xff; | |
| 660 | g = i; | |
| 661 | } | |
| 662 | ||
| 663 | ferr = put_granule_map(img, granule_map, granule_count); | |
| 664 | if (ferr) | |
| 665 | return imgtool_floppy_error(ferr); | |
| 666 | ||
| 667 | return IMGTOOLERR_SUCCESS; | |
| 668 | } | |
| 669 | ||
| 670 | ||
| 671 | ||
| 672 | static imgtoolerr_t bml3_diskimage_readfile(imgtool_partition *partition, const char *fname, const char *fork, imgtool_stream *destf) | |
| 673 | { | |
| 674 | imgtoolerr_t err; | |
| 675 | struct bml3_dirent ent; | |
| 676 | size_t size; | |
| 677 | imgtool_image *img = imgtool_partition_image(partition); | |
| 678 | ||
| 679 | err = lookup_bml3_file(img, fname, &ent, NULL); | |
| 680 | if (err) | |
| 681 | return err; | |
| 682 | ||
| 683 | err = process_bml3_file(&ent, img, destf, &size); | |
| 684 | if (err) | |
| 685 | return err; | |
| 686 | ||
| 687 | if (size == (size_t) -1) | |
| 688 | return IMGTOOLERR_CORRUPTIMAGE; | |
| 689 | ||
| 690 | return (imgtoolerr_t)0; | |
| 691 | } | |
| 692 | ||
| 693 | ||
| 694 | ||
| 695 | static imgtoolerr_t bml3_diskimage_writefile(imgtool_partition *partition, const char *fname, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions) | |
| 696 | { | |
| 697 | floperr_t ferr; | |
| 698 | imgtoolerr_t err; | |
| 699 | imgtool_image *img = imgtool_partition_image(partition); | |
| 700 | bml3_diskinfo *info = bml3_get_diskinfo(img); | |
| 701 | struct bml3_dirent ent, ent2; | |
| 702 | size_t i; | |
| 703 | UINT64 sz, read_sz; | |
| 704 | UINT64 freespace = 0; | |
| 705 | unsigned char g; | |
| 706 | unsigned char *gptr; | |
| 707 | UINT8 granule_count; | |
| 708 | UINT8 granule_map[MAX_GRANULEMAP_SIZE]; | |
| 709 | UINT8 eof_buf[MAX_SECTOR_SIZE]; | |
| 710 | ||
| 711 | // one-time setup of eof_buf | |
| 712 | memset(eof_buf, 0, sizeof(eof_buf)); | |
| 713 | eof_buf[0] = 0x1A; | |
| 714 | ||
| 715 | /* can we write to this image? */ | |
| 716 | if (floppy_is_read_only(imgtool_floppy(img))) | |
| 717 | return IMGTOOLERR_READONLY; | |
| 718 | ||
| 719 | err = bml3_diskimage_freespace(partition, &freespace); | |
| 720 | if (err) | |
| 721 | return err; | |
| 722 | ||
| 723 | /* is there enough space? */ | |
| 724 | sz = read_sz = stream_size(sourcef); | |
| 725 | if (info->variant == 0) { | |
| 726 | // also need to write EOF | |
| 727 | sz++; | |
| 728 | } | |
| 729 | if (sz > freespace) | |
| 730 | return IMGTOOLERR_NOSPACE; | |
| 731 | ||
| 732 | /* setup our directory entry */ | |
| 733 | err = prepare_dirent(info->variant, &ent, fname); | |
| 734 | if (err) | |
| 735 | return err; | |
| 736 | ||
| 737 | ent.ftype = option_resolution_lookup_int(writeoptions, BML3_OPTIONS_FTYPE); | |
| 738 | ent.asciiflag = ((UINT8) option_resolution_lookup_int(writeoptions, BML3_OPTIONS_ASCII)) - 1; | |
| 739 | gptr = &ent.first_granule; | |
| 740 | ||
| 741 | ferr = get_granule_map(img, granule_map, &granule_count); | |
| 742 | if (ferr) | |
| 743 | return imgtool_floppy_error(ferr); | |
| 744 | ||
| 745 | g = 0x00; | |
| 746 | ||
| 747 | do | |
| 748 | { | |
| 749 | while (granule_map[g] != 0xff) | |
| 750 | { | |
| 751 | g++; | |
| 752 | if ((g >= granule_count) || (g == 0)) | |
| 753 | return IMGTOOLERR_UNEXPECTED; /* We should have already verified that there is enough space */ | |
| 754 | } | |
| 755 | *gptr = g; | |
| 756 | gptr = &granule_map[g]; | |
| 757 | ||
| 758 | ||
| 759 | i = MIN(read_sz, info->granule_sectors * info->sector_size); | |
| 760 | if (i > 0) { | |
| 761 | err = transfer_to_granule(img, g, i, sourcef); | |
| 762 | if (err) | |
| 763 | return err; | |
| 764 | read_sz -= i; | |
| 765 | sz -= i; | |
| 766 | } | |
| 767 | if (i < info->granule_sectors * info->sector_size && sz > 0) { | |
| 768 | // write EOF and trailing NULs in the final sector | |
| 769 | ferr = write_granule(img, g, i, (info->granule_sectors * info->sector_size - i - 1) % info->sector_size + 1, eof_buf); | |
| 770 | if (ferr) | |
| 771 | return imgtool_floppy_error(ferr); | |
| 772 | sz--; | |
| 773 | i++; | |
| 774 | } | |
| 775 | ||
| 776 | /* Go to next granule */ | |
| 777 | g++; | |
| 778 | } | |
| 779 | while(sz > 0); | |
| 780 | ||
| 781 | /* Now that we are done with the file, we need to specify the final entry | |
| 782 | * in the file allocation table | |
| 783 | */ | |
| 784 | *gptr = 0xc0 + ((i + info->sector_size-1) / info->sector_size) - (info->variant == 0 ? 1 : 0); | |
| 785 | ent.lastsectorbytes = (i - 1) % info->sector_size + 1; | |
| 786 | ||
| 787 | /* delete file if it already exists */ | |
| 788 | err = bml3_diskimage_deletefile(partition, fname); | |
| 789 | if (err && err != IMGTOOLERR_FILENOTFOUND) | |
| 790 | return err; | |
| 791 | ||
| 792 | /* Now we need to find an empty directory entry */ | |
| 793 | i = -1; | |
| 794 | do | |
| 795 | { | |
| 796 | ferr = get_bml3_dirent(img, ++i, &ent2); | |
| 797 | if (ferr) | |
| 798 | return imgtool_floppy_error(ferr); | |
| 799 | } | |
| 800 | while(ent2.fname[0] != '\0' && ent2.fname[0] != -1); | |
| 801 | ||
| 802 | ferr = put_bml3_dirent(img, i, &ent); | |
| 803 | if (ferr) | |
| 804 | return imgtool_floppy_error(ferr); | |
| 805 | ||
| 806 | /* write the granule map back out */ | |
| 807 | ferr = put_granule_map(img, granule_map, granule_count); | |
| 808 | if (ferr) | |
| 809 | return imgtool_floppy_error(ferr); | |
| 810 | ||
| 811 | return IMGTOOLERR_SUCCESS; | |
| 812 | } | |
| 813 | ||
| 814 | ||
| 815 | ||
| 816 | static imgtoolerr_t bml3_diskimage_deletefile(imgtool_partition *partition, const char *fname) | |
| 817 | { | |
| 818 | imgtoolerr_t err; | |
| 819 | imgtool_image *image = imgtool_partition_image(partition); | |
| 820 | int pos; | |
| 821 | struct bml3_dirent ent; | |
| 822 | ||
| 823 | err = lookup_bml3_file(image, fname, &ent, &pos); | |
| 824 | if (err) | |
| 825 | return err; | |
| 826 | ||
| 827 | return delete_entry(image, &ent, pos); | |
| 828 | } | |
| 829 | ||
| 830 | ||
| 831 | ||
| 832 | static imgtoolerr_t bml3_diskimage_suggesttransfer(imgtool_partition *partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) | |
| 833 | { | |
| 834 | imgtoolerr_t err; | |
| 835 | imgtool_image *image = imgtool_partition_image(partition); | |
| 836 | struct bml3_dirent ent; | |
| 837 | int pos; | |
| 838 | ||
| 839 | if (fname) | |
| 840 | { | |
| 841 | err = lookup_bml3_file(image, fname, &ent, &pos); | |
| 842 | if (err) | |
| 843 | return err; | |
| 844 | ||
| 845 | if (ent.asciiflag == 0xFF) | |
| 846 | { | |
| 847 | /* ASCII file */ | |
| 848 | suggestions[0].viability = SUGGESTION_RECOMMENDED; | |
| 849 | suggestions[0].filter = filter_eoln_getinfo; | |
| 850 | suggestions[1].viability = SUGGESTION_POSSIBLE; | |
| 851 | suggestions[1].filter = NULL; | |
| 852 | } | |
| 853 | else if (ent.ftype == 0) | |
| 854 | { | |
| 855 | /* tokenized BASIC file */ | |
| 856 | suggestions[0].viability = SUGGESTION_RECOMMENDED; | |
| 857 | suggestions[0].filter = NULL; | |
| 858 | suggestions[1].viability = SUGGESTION_POSSIBLE; | |
| 859 | suggestions[1].filter = filter_bml3bas_getinfo; | |
| 860 | } | |
| 861 | } | |
| 862 | else | |
| 863 | { | |
| 864 | suggestions[0].viability = SUGGESTION_RECOMMENDED; | |
| 865 | suggestions[0].filter = NULL; | |
| 866 | suggestions[1].viability = SUGGESTION_POSSIBLE; | |
| 867 | suggestions[1].filter = filter_eoln_getinfo; | |
| 868 | suggestions[2].viability = SUGGESTION_POSSIBLE; | |
| 869 | suggestions[2].filter = filter_bml3bas_getinfo; | |
| 870 | } | |
| 871 | ||
| 872 | return IMGTOOLERR_SUCCESS; | |
| 873 | } | |
| 874 | ||
| 875 | ||
| 876 | ||
| 877 | /********************************************************************* | |
| 878 | Imgtool module declaration | |
| 879 | *********************************************************************/ | |
| 880 | ||
| 881 | static OPTION_GUIDE_START( bml3_writefile_optionguide ) | |
| 882 | OPTION_ENUM_START( BML3_OPTIONS_FTYPE, "ftype", "File type" ) | |
| 883 | OPTION_ENUM( 0, "basic", "Basic" ) | |
| 884 | OPTION_ENUM( 1, "data", "Data" ) | |
| 885 | OPTION_ENUM( 2, "binary", "Binary" ) | |
| 886 | OPTION_ENUM( 3, "assembler", "Assembler Source" ) | |
| 887 | OPTION_ENUM_END | |
| 888 | OPTION_ENUM_START( BML3_OPTIONS_ASCII, "ascii", "Ascii flag" ) | |
| 889 | OPTION_ENUM( 0, "ascii", "Ascii" ) | |
| 890 | OPTION_ENUM( 1, "binary", "Binary" ) | |
| 891 | OPTION_ENUM_END | |
| 892 | OPTION_GUIDE_END | |
| 893 | ||
| 894 | ||
| 895 | ||
| 896 | void bml3_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) | |
| 897 | { | |
| 898 | switch(state) | |
| 899 | { | |
| 900 | /* --- the following bits of info are returned as 64-bit signed integers --- */ | |
| 901 | case IMGTOOLINFO_INT_PREFER_UCASE: info->i = 1; break; | |
| 902 | case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(bml3_diskinfo); break; | |
| 903 | case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct bml3_direnum); break; | |
| 904 | ||
| 905 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 906 | case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "bml3"); break; | |
| 907 | case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Basic Master Level 3 format"); break; | |
| 908 | case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; | |
| 909 | case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; | |
| 910 | case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "T0-[2]-3;M0-[1]"); break; | |
| 911 | ||
| 912 | /* --- the following bits of info are returned as pointers to data or functions --- */ | |
| 913 | case IMGTOOLINFO_PTR_MAKE_CLASS: info->make_class = imgtool_floppy_make_class; break; | |
| 914 | case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = bml3_diskimage_open; break; | |
| 915 | case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = bml3_diskimage_nextenum; break; | |
| 916 | case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = bml3_diskimage_freespace; break; | |
| 917 | case IMGTOOLINFO_PTR_READ_FILE: info->read_file = bml3_diskimage_readfile; break; | |
| 918 | case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = bml3_diskimage_writefile; break; | |
| 919 | case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = bml3_diskimage_deletefile; break; | |
| 920 | case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = bml3_diskimage_suggesttransfer; break; | |
| 921 | case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = bml3_writefile_optionguide; break; | |
| 922 | case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_default; break; | |
| 923 | } | |
| 924 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r24064 | r24065 | |
|---|---|---|
| 58 | 58 | extern void filter_thombas7_getinfo(UINT32 state, union filterinfo *info); |
| 59 | 59 | extern void filter_thombas128_getinfo(UINT32 state, union filterinfo *info); |
| 60 | 60 | extern void filter_thomcrypt_getinfo(UINT32 state, union filterinfo *info); |
| 61 | extern void filter_bml3bas_getinfo(UINT32 state, union filterinfo *info); | |
| 61 | 62 | |
| 62 | 63 | |
| 63 | 64 | #endif /* FILTER_H */ |
| r0 | r24065 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | bml3mp1805.c | |
| 4 | ||
| 5 | Hitachi MP-1805 floppy disk controller card for the MB-6890 | |
| 6 | Floppy drive is attached | |
| 7 | ||
| 8 | *********************************************************************/ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "bml3mp1805.h" | |
| 12 | ||
| 13 | ||
| 14 | /*************************************************************************** | |
| 15 | PARAMETERS | |
| 16 | ***************************************************************************/ | |
| 17 | ||
| 18 | //************************************************************************** | |
| 19 | // GLOBAL VARIABLES | |
| 20 | //************************************************************************** | |
| 21 | ||
| 22 | const device_type BML3BUS_MP1805 = &device_creator<bml3bus_mp1805_device>; | |
| 23 | ||
| 24 | static const floppy_interface bml3_mp1805_floppy_interface = | |
| 25 | { | |
| 26 | DEVCB_NULL, | |
| 27 | DEVCB_NULL, | |
| 28 | DEVCB_NULL, | |
| 29 | DEVCB_NULL, | |
| 30 | DEVCB_NULL, | |
| 31 | FLOPPY_STANDARD_3_SSDD, | |
| 32 | LEGACY_FLOPPY_OPTIONS_NAME(default), | |
| 33 | NULL | |
| 34 | }; | |
| 35 | ||
| 36 | static WRITE_LINE_DEVICE_HANDLER( bml3_mc6843_intrq_w ) | |
| 37 | { | |
| 38 | bml3bus_mp1805_device *fdc = dynamic_cast<bml3bus_mp1805_device *>(device->owner()); | |
| 39 | if (state) { | |
| 40 | fdc->m_bml3bus->set_nmi_line(PULSE_LINE); | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 44 | const mc6843_interface bml3_6843_if = | |
| 45 | { | |
| 46 | bml3_mc6843_intrq_w | |
| 47 | }; | |
| 48 | ||
| 49 | ||
| 50 | #define MP1805_ROM_REGION "mp1805_rom" | |
| 51 | ||
| 52 | ROM_START( mp1805 ) | |
| 53 | ROM_REGION(0x10000, MP1805_ROM_REGION, 0) | |
| 54 | // MP-1805 disk controller ROM, which replaces part of the system ROM | |
| 55 | ROM_LOAD( "mp1805.rom", 0xf800, 0x0800, BAD_DUMP CRC(b532d8d9) SHA1(6f1160356d5bf64b5926b1fdb60db414edf65f22)) | |
| 56 | ROM_END | |
| 57 | ||
| 58 | MACHINE_CONFIG_FRAGMENT( mp1805 ) | |
| 59 | MCFG_MC6843_ADD( "mc6843", bml3_6843_if ) | |
| 60 | MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(bml3_mp1805_floppy_interface) | |
| 61 | MACHINE_CONFIG_END | |
| 62 | ||
| 63 | /*************************************************************************** | |
| 64 | FUNCTION PROTOTYPES | |
| 65 | ***************************************************************************/ | |
| 66 | ||
| 67 | //------------------------------------------------- | |
| 68 | // machine_config_additions - device-specific | |
| 69 | // machine configurations | |
| 70 | //------------------------------------------------- | |
| 71 | ||
| 72 | machine_config_constructor bml3bus_mp1805_device::device_mconfig_additions() const | |
| 73 | { | |
| 74 | return MACHINE_CONFIG_NAME( mp1805 ); | |
| 75 | } | |
| 76 | ||
| 77 | //------------------------------------------------- | |
| 78 | // rom_region - device-specific ROM region | |
| 79 | //------------------------------------------------- | |
| 80 | ||
| 81 | const rom_entry *bml3bus_mp1805_device::device_rom_region() const | |
| 82 | { | |
| 83 | return ROM_NAME( mp1805 ); | |
| 84 | } | |
| 85 | ||
| 86 | READ8_MEMBER( bml3bus_mp1805_device::bml3_mp1805_r) | |
| 87 | { | |
| 88 | // TODO: read supported or not? | |
| 89 | // return mc6843_drq_r(m_mc6843) ? 0x00 : 0x80; | |
| 90 | return -1; | |
| 91 | } | |
| 92 | ||
| 93 | WRITE8_MEMBER( bml3bus_mp1805_device::bml3_mp1805_w) | |
| 94 | { | |
| 95 | // b7 b6 b5 b4 b3 b2 b1 b0 | |
| 96 | // MT ? ? ? D3 D2 D1 D0 | |
| 97 | // MT: 0=motor off, 1=motor on | |
| 98 | // Dn: 1=select drive <n> | |
| 99 | int drive_select = data & 0x0f; | |
| 100 | int drive; | |
| 101 | // TODO: MESS UI for flipping disk? Note that D88 images are double-sided, but the physical drive is single-sided | |
| 102 | int side = 0; | |
| 103 | int motor = BIT(data, 7); | |
| 104 | const char *floppy_name = NULL; | |
| 105 | switch (drive_select) { | |
| 106 | case 1: | |
| 107 | drive = 0; | |
| 108 | break; | |
| 109 | case 2: | |
| 110 | drive = 1; | |
| 111 | break; | |
| 112 | case 4: | |
| 113 | drive = 2; | |
| 114 | break; | |
| 115 | case 8: | |
| 116 | drive = 3; | |
| 117 | break; | |
| 118 | default: | |
| 119 | // TODO: what's the correct behaviour if more than one drive select bit is set? Or no bit set? | |
| 120 | drive = 0; | |
| 121 | break; | |
| 122 | } | |
| 123 | switch (drive) { | |
| 124 | case 0: | |
| 125 | floppy_name = FLOPPY_0; | |
| 126 | break; | |
| 127 | case 1: | |
| 128 | floppy_name = FLOPPY_1; | |
| 129 | break; | |
| 130 | case 2: | |
| 131 | floppy_name = FLOPPY_2; | |
| 132 | break; | |
| 133 | case 3: | |
| 134 | floppy_name = FLOPPY_3; | |
| 135 | break; | |
| 136 | } | |
| 137 | device_t *floppy = subdevice(floppy_name); | |
| 138 | mc6843_set_drive(m_mc6843,drive); | |
| 139 | floppy_mon_w(floppy, motor); | |
| 140 | floppy_drive_set_ready_state(floppy, ASSERT_LINE, 0); | |
| 141 | mc6843_set_side(m_mc6843,side); | |
| 142 | } | |
| 143 | ||
| 144 | ||
| 145 | //************************************************************************** | |
| 146 | // LIVE DEVICE | |
| 147 | //************************************************************************** | |
| 148 | ||
| 149 | bml3bus_mp1805_device::bml3bus_mp1805_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 150 | device_t(mconfig, BML3BUS_MP1805, "Hitachi MP-1805 Floppy Controller Card", tag, owner, clock, "bml3mp1805", __FILE__), | |
| 151 | device_bml3bus_card_interface(mconfig, *this), | |
| 152 | m_mc6843(*this, "mc6843") | |
| 153 | { | |
| 154 | } | |
| 155 | ||
| 156 | ||
| 157 | //------------------------------------------------- | |
| 158 | // device_start - device-specific startup | |
| 159 | //------------------------------------------------- | |
| 160 | ||
| 161 | void bml3bus_mp1805_device::device_start() | |
| 162 | { | |
| 163 | // set_bml3bus_device makes m_slot valid | |
| 164 | set_bml3bus_device(); | |
| 165 | ||
| 166 | m_rom = memregion(MP1805_ROM_REGION)->base(); | |
| 167 | ||
| 168 | // install into memory | |
| 169 | address_space &space_prg = machine().firstcpu->space(AS_PROGRAM); | |
| 170 | space_prg.install_legacy_readwrite_handler(m_mc6843, 0xff18, 0xff1f, FUNC(mc6843_r), FUNC(mc6843_w)); | |
| 171 | space_prg.install_readwrite_handler(0xff20, 0xff20, read8_delegate( FUNC(bml3bus_mp1805_device::bml3_mp1805_r), this), write8_delegate(FUNC(bml3bus_mp1805_device::bml3_mp1805_w), this) ); | |
| 172 | // overwriting the main ROM (rather than using e.g. install_rom) should mean that bank switches for RAM expansion still work... | |
| 173 | UINT8 *mainrom = device().machine().root_device().memregion("maincpu")->base(); | |
| 174 | memcpy(mainrom + 0xf800, m_rom + 0xf800, 0x800); | |
| 175 | } | |
| 176 | ||
| 177 | void bml3bus_mp1805_device::device_reset() | |
| 178 | { | |
| 179 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r24065 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | bml3mp1805.h | |
| 4 | ||
| 5 | Hitachi MP-1805 floppy disk controller card for the MB-6890 | |
| 6 | Floppy drive is attached | |
| 7 | ||
| 8 | *********************************************************************/ | |
| 9 | ||
| 10 | #ifndef __BML3BUS_MP1805__ | |
| 11 | #define __BML3BUS_MP1805__ | |
| 12 | ||
| 13 | #include "emu.h" | |
| 14 | #include "machine/bml3bus.h" | |
| 15 | #include "imagedev/flopdrv.h" | |
| 16 | #include "machine/mc6843.h" | |
| 17 | ||
| 18 | //************************************************************************** | |
| 19 | // TYPE DEFINITIONS | |
| 20 | //************************************************************************** | |
| 21 | ||
| 22 | class bml3bus_mp1805_device: | |
| 23 | public device_t, | |
| 24 | public device_bml3bus_card_interface | |
| 25 | { | |
| 26 | public: | |
| 27 | // construction/destruction | |
| 28 | bml3bus_mp1805_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 29 | ||
| 30 | // optional information overrides | |
| 31 | virtual machine_config_constructor device_mconfig_additions() const; | |
| 32 | virtual const rom_entry *device_rom_region() const; | |
| 33 | ||
| 34 | DECLARE_READ8_MEMBER(bml3_mp1805_r); | |
| 35 | DECLARE_WRITE8_MEMBER(bml3_mp1805_w); | |
| 36 | ||
| 37 | protected: | |
| 38 | virtual void device_start(); | |
| 39 | virtual void device_reset(); | |
| 40 | ||
| 41 | required_device<mc6843_device> m_mc6843; | |
| 42 | ||
| 43 | private: | |
| 44 | UINT8 *m_rom; | |
| 45 | }; | |
| 46 | ||
| 47 | // device type definition | |
| 48 | extern const device_type BML3BUS_MP1805; | |
| 49 | ||
| 50 | #endif /* __BML3BUS_MP1805__ */ |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r24065 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | bml3kanji.c | |
| 4 | ||
| 5 | Hitachi MP-9740 (?) kanji character ROM for the MB-689x | |
| 6 | ||
| 7 | *********************************************************************/ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "bml3kanji.h" | |
| 11 | ||
| 12 | ||
| 13 | /*************************************************************************** | |
| 14 | PARAMETERS | |
| 15 | ***************************************************************************/ | |
| 16 | ||
| 17 | //************************************************************************** | |
| 18 | // GLOBAL VARIABLES | |
| 19 | //************************************************************************** | |
| 20 | ||
| 21 | const device_type BML3BUS_KANJI = &device_creator<bml3bus_kanji_device>; | |
| 22 | ||
| 23 | #define KANJI_ROM_REGION "kanji_rom" | |
| 24 | ||
| 25 | ROM_START( kanji ) | |
| 26 | ROM_REGION( 0x20000, KANJI_ROM_REGION, ROMREGION_ERASEFF ) | |
| 27 | ROM_LOAD("kanji.rom", 0x00000, 0x20000, BAD_DUMP CRC(de99a726) SHA1(65fead5d0d779b242f6e0ac25fcc9899dc343101)) | |
| 28 | ROM_END | |
| 29 | ||
| 30 | MACHINE_CONFIG_FRAGMENT( kanji ) | |
| 31 | // nothing to add | |
| 32 | MACHINE_CONFIG_END | |
| 33 | ||
| 34 | /*************************************************************************** | |
| 35 | FUNCTION PROTOTYPES | |
| 36 | ***************************************************************************/ | |
| 37 | ||
| 38 | //------------------------------------------------- | |
| 39 | // machine_config_additions - device-specific | |
| 40 | // machine configurations | |
| 41 | //------------------------------------------------- | |
| 42 | ||
| 43 | machine_config_constructor bml3bus_kanji_device::device_mconfig_additions() const | |
| 44 | { | |
| 45 | return MACHINE_CONFIG_NAME( kanji ); | |
| 46 | } | |
| 47 | ||
| 48 | //------------------------------------------------- | |
| 49 | // rom_region - device-specific ROM region | |
| 50 | //------------------------------------------------- | |
| 51 | ||
| 52 | const rom_entry *bml3bus_kanji_device::device_rom_region() const | |
| 53 | { | |
| 54 | return ROM_NAME( kanji ); | |
| 55 | } | |
| 56 | ||
| 57 | READ8_MEMBER( bml3bus_kanji_device::bml3_kanji_r ) | |
| 58 | { | |
| 59 | return m_rom[((UINT32)m_kanji_addr << 1) + offset]; | |
| 60 | } | |
| 61 | ||
| 62 | WRITE8_MEMBER( bml3bus_kanji_device::bml3_kanji_w ) | |
| 63 | { | |
| 64 | m_kanji_addr &= (0xff << (offset*8)); | |
| 65 | m_kanji_addr |= (data << ((offset^1)*8)); | |
| 66 | } | |
| 67 | ||
| 68 | ||
| 69 | //************************************************************************** | |
| 70 | // LIVE DEVICE | |
| 71 | //************************************************************************** | |
| 72 | ||
| 73 | bml3bus_kanji_device::bml3bus_kanji_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 74 | device_t(mconfig, BML3BUS_KANJI, "Hitachi MP-9740 Kanji Character ROM Card", tag, owner, clock, "bml3kanji", __FILE__), | |
| 75 | device_bml3bus_card_interface(mconfig, *this) | |
| 76 | { | |
| 77 | } | |
| 78 | ||
| 79 | ||
| 80 | //------------------------------------------------- | |
| 81 | // device_start - device-specific startup | |
| 82 | //------------------------------------------------- | |
| 83 | ||
| 84 | void bml3bus_kanji_device::device_start() | |
| 85 | { | |
| 86 | // set_bml3bus_device makes m_slot valid | |
| 87 | set_bml3bus_device(); | |
| 88 | ||
| 89 | m_rom = memregion(KANJI_ROM_REGION)->base(); | |
| 90 | ||
| 91 | // install into memory | |
| 92 | address_space &space_prg = machine().firstcpu->space(AS_PROGRAM); | |
| 93 | space_prg.install_readwrite_handler(0xff75, 0xff76, read8_delegate( FUNC(bml3bus_kanji_device::bml3_kanji_r), this), write8_delegate(FUNC(bml3bus_kanji_device::bml3_kanji_w), this) ); | |
| 94 | } | |
| 95 | ||
| 96 | void bml3bus_kanji_device::device_reset() | |
| 97 | { | |
| 98 | m_kanji_addr = 0; | |
| 99 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r24065 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | bml3kanji.h | |
| 4 | ||
| 5 | Hitachi MP-9740 (?) kanji character ROM for the MB-689x | |
| 6 | ||
| 7 | *********************************************************************/ | |
| 8 | ||
| 9 | #ifndef __BML3BUS_KANJI__ | |
| 10 | #define __BML3BUS_KANJI__ | |
| 11 | ||
| 12 | #include "emu.h" | |
| 13 | #include "machine/bml3bus.h" | |
| 14 | ||
| 15 | //************************************************************************** | |
| 16 | // TYPE DEFINITIONS | |
| 17 | //************************************************************************** | |
| 18 | ||
| 19 | class bml3bus_kanji_device: | |
| 20 | public device_t, | |
| 21 | public device_bml3bus_card_interface | |
| 22 | { | |
| 23 | public: | |
| 24 | // construction/destruction | |
| 25 | bml3bus_kanji_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 26 | ||
| 27 | // optional information overrides | |
| 28 | virtual machine_config_constructor device_mconfig_additions() const; | |
| 29 | virtual const rom_entry *device_rom_region() const; | |
| 30 | ||
| 31 | DECLARE_READ8_MEMBER(bml3_kanji_r); | |
| 32 | DECLARE_WRITE8_MEMBER(bml3_kanji_w); | |
| 33 | ||
| 34 | protected: | |
| 35 | virtual void device_start(); | |
| 36 | virtual void device_reset(); | |
| 37 | ||
| 38 | UINT16 m_kanji_addr; | |
| 39 | ||
| 40 | private: | |
| 41 | UINT8 *m_rom; | |
| 42 | }; | |
| 43 | ||
| 44 | // device type definition | |
| 45 | extern const device_type BML3BUS_KANJI; | |
| 46 | ||
| 47 | #endif /* __BML3BUS_KANJI__ */ |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r24065 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | bml3mp1802.c | |
| 4 | ||
| 5 | Hitachi MP-1802 floppy disk controller card for the MB-6890 | |
| 6 | Hitachi MP-3550 floppy drive is attached | |
| 7 | ||
| 8 | *********************************************************************/ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "bml3mp1802.h" | |
| 12 | ||
| 13 | ||
| 14 | /*************************************************************************** | |
| 15 | PARAMETERS | |
| 16 | ***************************************************************************/ | |
| 17 | ||
| 18 | //************************************************************************** | |
| 19 | // GLOBAL VARIABLES | |
| 20 | //************************************************************************** | |
| 21 | ||
| 22 | const device_type BML3BUS_MP1802 = &device_creator<bml3bus_mp1802_device>; | |
| 23 | ||
| 24 | static const floppy_interface bml3_mp1802_floppy_interface = | |
| 25 | { | |
| 26 | DEVCB_NULL, | |
| 27 | DEVCB_NULL, | |
| 28 | DEVCB_NULL, | |
| 29 | DEVCB_NULL, | |
| 30 | DEVCB_NULL, | |
| 31 | FLOPPY_STANDARD_5_25_DSDD, | |
| 32 | LEGACY_FLOPPY_OPTIONS_NAME(default), | |
| 33 | NULL | |
| 34 | }; | |
| 35 | ||
| 36 | static WRITE_LINE_DEVICE_HANDLER( bml3_wd17xx_intrq_w ) | |
| 37 | { | |
| 38 | bml3bus_mp1802_device *fdc = dynamic_cast<bml3bus_mp1802_device *>(device->owner()); | |
| 39 | if (state) { | |
| 40 | fdc->m_bml3bus->set_nmi_line(PULSE_LINE); | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 44 | const wd17xx_interface bml3_wd17xx_interface = | |
| 45 | { | |
| 46 | DEVCB_NULL, | |
| 47 | DEVCB_LINE(bml3_wd17xx_intrq_w), | |
| 48 | DEVCB_NULL, | |
| 49 | {FLOPPY_0, FLOPPY_1} | |
| 50 | }; | |
| 51 | ||
| 52 | ||
| 53 | #define MP1802_ROM_REGION "mp1802_rom" | |
| 54 | ||
| 55 | ROM_START( mp1802 ) | |
| 56 | ROM_REGION(0x10000, MP1802_ROM_REGION, 0) | |
| 57 | // MP-1802 disk controller ROM, which replaces part of the system ROM | |
| 58 | ROM_LOAD( "mp1802.rom", 0xf800, 0x800, BAD_DUMP CRC(8d0dc101) SHA1(92f7d1cebecafa7472e45c4999520de5c01c6dbc)) | |
| 59 | ROM_END | |
| 60 | ||
| 61 | MACHINE_CONFIG_FRAGMENT( mp1802 ) | |
| 62 | MCFG_MB8866_ADD("wd17xx", bml3_wd17xx_interface ) | |
| 63 | MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(bml3_mp1802_floppy_interface) | |
| 64 | MACHINE_CONFIG_END | |
| 65 | ||
| 66 | /*************************************************************************** | |
| 67 | FUNCTION PROTOTYPES | |
| 68 | ***************************************************************************/ | |
| 69 | ||
| 70 | //------------------------------------------------- | |
| 71 | // machine_config_additions - device-specific | |
| 72 | // machine configurations | |
| 73 | //------------------------------------------------- | |
| 74 | ||
| 75 | machine_config_constructor bml3bus_mp1802_device::device_mconfig_additions() const | |
| 76 | { | |
| 77 | return MACHINE_CONFIG_NAME( mp1802 ); | |
| 78 | } | |
| 79 | ||
| 80 | //------------------------------------------------- | |
| 81 | // rom_region - device-specific ROM region | |
| 82 | //------------------------------------------------- | |
| 83 | ||
| 84 | const rom_entry *bml3bus_mp1802_device::device_rom_region() const | |
| 85 | { | |
| 86 | return ROM_NAME( mp1802 ); | |
| 87 | } | |
| 88 | ||
| 89 | READ8_MEMBER( bml3bus_mp1802_device::bml3_mp1802_r) | |
| 90 | { | |
| 91 | return wd17xx_drq_r(m_wd17xx) ? 0x00 : 0x80; | |
| 92 | } | |
| 93 | ||
| 94 | WRITE8_MEMBER( bml3bus_mp1802_device::bml3_mp1802_w) | |
| 95 | { | |
| 96 | int drive = data & 0x03; | |
| 97 | int side = BIT(data, 4); | |
| 98 | int motor = BIT(data, 3); | |
| 99 | const char *floppy_name = NULL; | |
| 100 | switch (drive) { | |
| 101 | case 0: | |
| 102 | floppy_name = FLOPPY_0; | |
| 103 | break; | |
| 104 | case 1: | |
| 105 | floppy_name = FLOPPY_1; | |
| 106 | break; | |
| 107 | case 2: | |
| 108 | floppy_name = FLOPPY_2; | |
| 109 | break; | |
| 110 | case 3: | |
| 111 | floppy_name = FLOPPY_3; | |
| 112 | break; | |
| 113 | } | |
| 114 | device_t *floppy = subdevice(floppy_name); | |
| 115 | wd17xx_set_drive(m_wd17xx,drive); | |
| 116 | floppy_mon_w(floppy, !motor); | |
| 117 | floppy_drive_set_ready_state(floppy, ASSERT_LINE, 0); | |
| 118 | wd17xx_set_side(m_wd17xx,side); | |
| 119 | } | |
| 120 | ||
| 121 | ||
| 122 | //************************************************************************** | |
| 123 | // LIVE DEVICE | |
| 124 | //************************************************************************** | |
| 125 | ||
| 126 | bml3bus_mp1802_device::bml3bus_mp1802_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 127 | device_t(mconfig, BML3BUS_MP1802, "Hitachi MP-1802 Floppy Controller Card", tag, owner, clock, "bml3mp1802", __FILE__), | |
| 128 | device_bml3bus_card_interface(mconfig, *this), | |
| 129 | m_wd17xx(*this, "wd17xx") | |
| 130 | { | |
| 131 | } | |
| 132 | ||
| 133 | ||
| 134 | //------------------------------------------------- | |
| 135 | // device_start - device-specific startup | |
| 136 | //------------------------------------------------- | |
| 137 | ||
| 138 | void bml3bus_mp1802_device::device_start() | |
| 139 | { | |
| 140 | // set_bml3bus_device makes m_slot valid | |
| 141 | set_bml3bus_device(); | |
| 142 | ||
| 143 | m_rom = memregion(MP1802_ROM_REGION)->base(); | |
| 144 | ||
| 145 | // install into memory | |
| 146 | address_space &space_prg = machine().firstcpu->space(AS_PROGRAM); | |
| 147 | space_prg.install_legacy_readwrite_handler(m_wd17xx, 0xff00, 0xff03, FUNC(wd17xx_r), FUNC(wd17xx_w)); | |
| 148 | space_prg.install_readwrite_handler(0xff04, 0xff04, read8_delegate( FUNC(bml3bus_mp1802_device::bml3_mp1802_r), this), write8_delegate(FUNC(bml3bus_mp1802_device::bml3_mp1802_w), this) ); | |
| 149 | // overwriting the main ROM (rather than using e.g. install_rom) should mean that bank switches for RAM expansion still work... | |
| 150 | UINT8 *mainrom = device().machine().root_device().memregion("maincpu")->base(); | |
| 151 | memcpy(mainrom + 0xf800, m_rom + 0xf800, 0x800); | |
| 152 | } | |
| 153 | ||
| 154 | void bml3bus_mp1802_device::device_reset() | |
| 155 | { | |
| 156 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r24065 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | bml3bus.c - Hitachi MB-6890 slot bus and card emulation | |
| 4 | ||
| 5 | Adapted from a2bus by Jonathan Edwards | |
| 6 | ||
| 7 | Pinout (/ indicates an inverted signal, ie, one that would have a bar over it | |
| 8 | on a schematic diagram) | |
| 9 | ||
| 10 | out <-> CPU CPU <-> out | |
| 11 | ---------- ----------- | |
| 12 | +5V <-- 1 2 <-> GND | |
| 13 | D0 <-> 3 4 <-> D1 | |
| 14 | D2 <-> 5 6 <-> D3 | |
| 15 | D4 <-> 7 8 <-> D5 | |
| 16 | D6 <-> 9 10 <-> D7 | |
| 17 | A0 <-> 11 12 <-> A1 | |
| 18 | A2 <-> 13 14 <-> A3 | |
| 19 | A4 <-> 15 16 <-> A5 | |
| 20 | A6 <-> 17 18 <-> A7 | |
| 21 | A8 <-> 19 20 <-> A9 | |
| 22 | A10 <-> 21 22 <-> A11 | |
| 23 | A12 <-> 23 24 <-> A13 | |
| 24 | A14 <-> 25 26 <-> A15 | |
| 25 | BA <-- 27 28 --> BS | |
| 26 | /ROM-KIL --> 29 30 --> EXROM-KIL | |
| 27 | R/W IN --> 31 32 --> /EX-I/O | |
| 28 | R/W OUT <-- 33 34 --> VMA OUT | |
| 29 | E <-- 35 36 --> Q | |
| 30 | /RES <-- 37 38 <-- /NMI | |
| 31 | /IRQ --> 39 40 <-- /FIRQ | |
| 32 | /HALT --> 41 42 <-- /VMA CTRL | |
| 33 | /DMA --> 43 44 --> /BANK-SW | |
| 34 | HALT ACK <-- 45 46 <-- SOUND IN | |
| 35 | 16MCK <-- 47 48 <-> GND | |
| 36 | 2MCK <-- 49 50 <-> GND | |
| 37 | -5V <-- 51 52 --> /EX-I/O2 | |
| 38 | -12V <-- 53 54 --> +12V | |
| 39 | GND <-> 55 56 --> +5V | |
| 40 | ||
| 41 | ***************************************************************************/ | |
| 42 | ||
| 43 | #include "emu.h" | |
| 44 | #include "emuopts.h" | |
| 45 | #include "machine/bml3bus.h" | |
| 46 | ||
| 47 | ||
| 48 | //************************************************************************** | |
| 49 | // GLOBAL VARIABLES | |
| 50 | //************************************************************************** | |
| 51 | ||
| 52 | const device_type BML3BUS_SLOT = &device_creator<bml3bus_slot_device>; | |
| 53 | ||
| 54 | //************************************************************************** | |
| 55 | // LIVE DEVICE | |
| 56 | //************************************************************************** | |
| 57 | ||
| 58 | //------------------------------------------------- | |
| 59 | // bml3bus_slot_device - constructor | |
| 60 | //------------------------------------------------- | |
| 61 | bml3bus_slot_device::bml3bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 62 | device_t(mconfig, BML3BUS_SLOT, "Hitachi MB-6890 Slot", tag, owner, clock, "bml3bus_slot", __FILE__), | |
| 63 | device_slot_interface(mconfig, *this) | |
| 64 | { | |
| 65 | } | |
| 66 | ||
| 67 | bml3bus_slot_device::bml3bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : | |
| 68 | device_t(mconfig, type, name, tag, owner, clock, shortname, source), | |
| 69 | device_slot_interface(mconfig, *this) | |
| 70 | { | |
| 71 | } | |
| 72 | ||
| 73 | void bml3bus_slot_device::static_set_bml3bus_slot(device_t &device, const char *tag, const char *slottag) | |
| 74 | { | |
| 75 | bml3bus_slot_device &bml3bus_card = dynamic_cast<bml3bus_slot_device &>(device); | |
| 76 | bml3bus_card.m_bml3bus_tag = tag; | |
| 77 | bml3bus_card.m_bml3bus_slottag = slottag; | |
| 78 | } | |
| 79 | ||
| 80 | //------------------------------------------------- | |
| 81 | // device_start - device-specific startup | |
| 82 | //------------------------------------------------- | |
| 83 | ||
| 84 | void bml3bus_slot_device::device_start() | |
| 85 | { | |
| 86 | device_bml3bus_card_interface *dev = dynamic_cast<device_bml3bus_card_interface *>(get_card_device()); | |
| 87 | ||
| 88 | if (dev) device_bml3bus_card_interface::static_set_bml3bus_tag(*dev, m_bml3bus_tag, m_bml3bus_slottag); | |
| 89 | } | |
| 90 | ||
| 91 | //************************************************************************** | |
| 92 | // GLOBAL VARIABLES | |
| 93 | //************************************************************************** | |
| 94 | ||
| 95 | const device_type BML3BUS = &device_creator<bml3bus_device>; | |
| 96 | ||
| 97 | void bml3bus_device::static_set_cputag(device_t &device, const char *tag) | |
| 98 | { | |
| 99 | bml3bus_device &bml3bus = downcast<bml3bus_device &>(device); | |
| 100 | bml3bus.m_cputag = tag; | |
| 101 | } | |
| 102 | ||
| 103 | //------------------------------------------------- | |
| 104 | // device_config_complete - perform any | |
| 105 | // operations now that the configuration is | |
| 106 | // complete | |
| 107 | //------------------------------------------------- | |
| 108 | ||
| 109 | void bml3bus_device::device_config_complete() | |
| 110 | { | |
| 111 | // inherit a copy of the static data | |
| 112 | const bml3bus_interface *intf = reinterpret_cast<const bml3bus_interface *>(static_config()); | |
| 113 | if (intf != NULL) | |
| 114 | { | |
| 115 | *static_cast<bml3bus_interface *>(this) = *intf; | |
| 116 | } | |
| 117 | ||
| 118 | // or initialize to defaults if none provided | |
| 119 | else | |
| 120 | { | |
| 121 | memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb)); | |
| 122 | memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb)); | |
| 123 | memset(&m_out_firq_cb, 0, sizeof(m_out_firq_cb)); | |
| 124 | } | |
| 125 | } | |
| 126 | ||
| 127 | //************************************************************************** | |
| 128 | // LIVE DEVICE | |
| 129 | //************************************************************************** | |
| 130 | ||
| 131 | //------------------------------------------------- | |
| 132 | // bml3bus_device - constructor | |
| 133 | //------------------------------------------------- | |
| 134 | ||
| 135 | bml3bus_device::bml3bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 136 | device_t(mconfig, BML3BUS, "Hitachi MB-6890 Bus", tag, owner, clock, "bml3bus", __FILE__) | |
| 137 | { | |
| 138 | } | |
| 139 | ||
| 140 | bml3bus_device::bml3bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : | |
| 141 | device_t(mconfig, type, name, tag, owner, clock, shortname, source) | |
| 142 | { | |
| 143 | } | |
| 144 | //------------------------------------------------- | |
| 145 | // device_start - device-specific startup | |
| 146 | //------------------------------------------------- | |
| 147 | ||
| 148 | void bml3bus_device::device_start() | |
| 149 | { | |
| 150 | m_maincpu = machine().device<cpu_device>(m_cputag); | |
| 151 | ||
| 152 | // resolve callbacks | |
| 153 | m_out_nmi_func.resolve(m_out_nmi_cb, *this); | |
| 154 | m_out_irq_func.resolve(m_out_irq_cb, *this); | |
| 155 | m_out_firq_func.resolve(m_out_firq_cb, *this); | |
| 156 | ||
| 157 | // clear slots | |
| 158 | for (int i = 0; i < BML3BUS_MAX_SLOTS; i++) | |
| 159 | { | |
| 160 | m_device_list[i] = NULL; | |
| 161 | } | |
| 162 | } | |
| 163 | ||
| 164 | //------------------------------------------------- | |
| 165 | // device_reset - device-specific reset | |
| 166 | //------------------------------------------------- | |
| 167 | ||
| 168 | void bml3bus_device::device_reset() | |
| 169 | { | |
| 170 | } | |
| 171 | ||
| 172 | device_bml3bus_card_interface *bml3bus_device::get_bml3bus_card(int slot) | |
| 173 | { | |
| 174 | if (slot < 0) | |
| 175 | { | |
| 176 | return NULL; | |
| 177 | } | |
| 178 | ||
| 179 | return m_device_list[slot]; | |
| 180 | } | |
| 181 | ||
| 182 | void bml3bus_device::add_bml3bus_card(int slot, device_bml3bus_card_interface *card) | |
| 183 | { | |
| 184 | m_device_list[slot] = card; | |
| 185 | } | |
| 186 | ||
| 187 | void bml3bus_device::set_nmi_line(int state) | |
| 188 | { | |
| 189 | m_out_nmi_func(state); | |
| 190 | } | |
| 191 | ||
| 192 | void bml3bus_device::set_irq_line(int state) | |
| 193 | { | |
| 194 | m_out_irq_func(state); | |
| 195 | } | |
| 196 | ||
| 197 | void bml3bus_device::set_firq_line(int state) | |
| 198 | { | |
| 199 | m_out_firq_func(state); | |
| 200 | } | |
| 201 | ||
| 202 | // interrupt request from bml3bus card | |
| 203 | WRITE_LINE_MEMBER( bml3bus_device::nmi_w ) { m_out_nmi_func(state); } | |
| 204 | WRITE_LINE_MEMBER( bml3bus_device::irq_w ) { m_out_irq_func(state); } | |
| 205 | WRITE_LINE_MEMBER( bml3bus_device::firq_w ) { m_out_firq_func(state); } | |
| 206 | ||
| 207 | //************************************************************************** | |
| 208 | // DEVICE CONFIG BML3BUS CARD INTERFACE | |
| 209 | //************************************************************************** | |
| 210 | ||
| 211 | ||
| 212 | //************************************************************************** | |
| 213 | // DEVICE BML3BUS CARD INTERFACE | |
| 214 | //************************************************************************** | |
| 215 | ||
| 216 | //------------------------------------------------- | |
| 217 | // device_bml3bus_card_interface - constructor | |
| 218 | //------------------------------------------------- | |
| 219 | ||
| 220 | device_bml3bus_card_interface::device_bml3bus_card_interface(const machine_config &mconfig, device_t &device) | |
| 221 | : device_slot_card_interface(mconfig, device), | |
| 222 | m_bml3bus(NULL), | |
| 223 | m_bml3bus_tag(NULL) | |
| 224 | { | |
| 225 | } | |
| 226 | ||
| 227 | ||
| 228 | //------------------------------------------------- | |
| 229 | // ~device_bml3bus_card_interface - destructor | |
| 230 | //------------------------------------------------- | |
| 231 | ||
| 232 | device_bml3bus_card_interface::~device_bml3bus_card_interface() | |
| 233 | { | |
| 234 | } | |
| 235 | ||
| 236 | void device_bml3bus_card_interface::static_set_bml3bus_tag(device_t &device, const char *tag, const char *slottag) | |
| 237 | { | |
| 238 | device_bml3bus_card_interface &bml3bus_card = dynamic_cast<device_bml3bus_card_interface &>(device); | |
| 239 | bml3bus_card.m_bml3bus_tag = tag; | |
| 240 | bml3bus_card.m_bml3bus_slottag = slottag; | |
| 241 | } | |
| 242 | ||
| 243 | void device_bml3bus_card_interface::set_bml3bus_device() | |
| 244 | { | |
| 245 | // extract the slot number from the last digit of the slot tag | |
| 246 | int tlen = strlen(m_bml3bus_slottag); | |
| 247 | ||
| 248 | m_slot = (m_bml3bus_slottag[tlen-1] - '1'); | |
| 249 | ||
| 250 | if (m_slot < 0 || m_slot >= BML3BUS_MAX_SLOTS) | |
| 251 | { | |
| 252 | fatalerror("Slot %x out of range for Hitachi MB-6890 Bus\n", m_slot); | |
| 253 | } | |
| 254 | ||
| 255 | m_bml3bus = dynamic_cast<bml3bus_device *>(device().machine().device(m_bml3bus_tag)); | |
| 256 | m_bml3bus->add_bml3bus_card(m_slot, this); | |
| 257 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r24065 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | bml3mp1802.h | |
| 4 | ||
| 5 | Hitachi MP-1802 floppy disk controller card for the MB-6890 | |
| 6 | Hitachi MP-3550 floppy drive is attached | |
| 7 | ||
| 8 | *********************************************************************/ | |
| 9 | ||
| 10 | #ifndef __BML3BUS_MP1802__ | |
| 11 | #define __BML3BUS_MP1802__ | |
| 12 | ||
| 13 | #include "emu.h" | |
| 14 | #include "machine/bml3bus.h" | |
| 15 | #include "imagedev/flopdrv.h" | |
| 16 | #include "machine/wd17xx.h" | |
| 17 | ||
| 18 | //************************************************************************** | |
| 19 | // TYPE DEFINITIONS | |
| 20 | //************************************************************************** | |
| 21 | ||
| 22 | class bml3bus_mp1802_device: | |
| 23 | public device_t, | |
| 24 | public device_bml3bus_card_interface | |
| 25 | { | |
| 26 | public: | |
| 27 | // construction/destruction | |
| 28 | bml3bus_mp1802_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 29 | ||
| 30 | // optional information overrides | |
| 31 | virtual machine_config_constructor device_mconfig_additions() const; | |
| 32 | virtual const rom_entry *device_rom_region() const; | |
| 33 | ||
| 34 | DECLARE_READ8_MEMBER(bml3_mp1802_r); | |
| 35 | DECLARE_WRITE8_MEMBER(bml3_mp1802_w); | |
| 36 | ||
| 37 | protected: | |
| 38 | virtual void device_start(); | |
| 39 | virtual void device_reset(); | |
| 40 | ||
| 41 | required_device<mb8866_device> m_wd17xx; | |
| 42 | ||
| 43 | private: | |
| 44 | UINT8 *m_rom; | |
| 45 | }; | |
| 46 | ||
| 47 | // device type definition | |
| 48 | extern const device_type BML3BUS_MP1802; | |
| 49 | ||
| 50 | #endif /* __BML3BUS_MP1802__ */ |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r24065 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | bml3bus.h - Hitachi MB-6890 slot bus and card emulation | |
| 4 | ||
| 5 | Adapted from a2bus by Jonathan Edwards | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #pragma once | |
| 10 | ||
| 11 | #ifndef __BML3BUS_H__ | |
| 12 | #define __BML3BUS_H__ | |
| 13 | ||
| 14 | #include "emu.h" | |
| 15 | ||
| 16 | #define BML3BUS_MAX_SLOTS 6 | |
| 17 | ||
| 18 | //************************************************************************** | |
| 19 | // INTERFACE CONFIGURATION MACROS | |
| 20 | //************************************************************************** | |
| 21 | ||
| 22 | #define MCFG_BML3BUS_BUS_ADD(_tag, _cputag, _config) \ | |
| 23 | MCFG_DEVICE_ADD(_tag, BML3BUS, 0) \ | |
| 24 | MCFG_DEVICE_CONFIG(_config) \ | |
| 25 | bml3bus_device::static_set_cputag(*device, _cputag); | |
| 26 | #define MCFG_BML3BUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \ | |
| 27 | MCFG_DEVICE_ADD(_tag, BML3BUS_SLOT, 0) \ | |
| 28 | MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ | |
| 29 | bml3bus_slot_device::static_set_bml3bus_slot(*device, _nbtag, _tag); | |
| 30 | #define MCFG_BML3BUS_SLOT_REMOVE(_tag) \ | |
| 31 | MCFG_DEVICE_REMOVE(_tag) | |
| 32 | ||
| 33 | #define MCFG_BML3BUS_ONBOARD_ADD(_nbtag, _tag, _dev_type) \ | |
| 34 | MCFG_DEVICE_ADD(_tag, _dev_type, 0) \ | |
| 35 | device_bml3bus_card_interface::static_set_bml3bus_tag(*device, _nbtag, _tag); | |
| 36 | ||
| 37 | #define MCFG_BML3BUS_BUS_REMOVE(_tag) \ | |
| 38 | MCFG_DEVICE_REMOVE(_tag) | |
| 39 | ||
| 40 | //************************************************************************** | |
| 41 | // TYPE DEFINITIONS | |
| 42 | //************************************************************************** | |
| 43 | ||
| 44 | class bml3bus_device; | |
| 45 | ||
| 46 | class bml3bus_slot_device : public device_t, | |
| 47 | public device_slot_interface | |
| 48 | { | |
| 49 | public: | |
| 50 | // construction/destruction | |
| 51 | bml3bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 52 | bml3bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); | |
| 53 | ||
| 54 | // device-level overrides | |
| 55 | virtual void device_start(); | |
| 56 | ||
| 57 | // inline configuration | |
| 58 | static void static_set_bml3bus_slot(device_t &device, const char *tag, const char *slottag); | |
| 59 | protected: | |
| 60 | // configuration | |
| 61 | const char *m_bml3bus_tag, *m_bml3bus_slottag; | |
| 62 | }; | |
| 63 | ||
| 64 | // device type definition | |
| 65 | extern const device_type BML3BUS_SLOT; | |
| 66 | ||
| 67 | // ======================> bml3bus_interface | |
| 68 | ||
| 69 | struct bml3bus_interface | |
| 70 | { | |
| 71 | devcb_write_line m_out_nmi_cb; | |
| 72 | devcb_write_line m_out_irq_cb; | |
| 73 | devcb_write_line m_out_firq_cb; | |
| 74 | }; | |
| 75 | ||
| 76 | class device_bml3bus_card_interface; | |
| 77 | // ======================> bml3bus_device | |
| 78 | class bml3bus_device : public device_t, | |
| 79 | public bml3bus_interface | |
| 80 | { | |
| 81 | public: | |
| 82 | // construction/destruction | |
| 83 | bml3bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 84 | bml3bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); | |
| 85 | // inline configuration | |
| 86 | static void static_set_cputag(device_t &device, const char *tag); | |
| 87 | ||
| 88 | void add_bml3bus_card(int slot, device_bml3bus_card_interface *card); | |
| 89 | device_bml3bus_card_interface *get_bml3bus_card(int slot); | |
| 90 | ||
| 91 | void set_nmi_line(int state); | |
| 92 | void set_irq_line(int state); | |
| 93 | void set_firq_line(int state); | |
| 94 | ||
| 95 | DECLARE_WRITE_LINE_MEMBER( nmi_w ); | |
| 96 | DECLARE_WRITE_LINE_MEMBER( irq_w ); | |
| 97 | DECLARE_WRITE_LINE_MEMBER( firq_w ); | |
| 98 | ||
| 99 | protected: | |
| 100 | // device-level overrides | |
| 101 | virtual void device_start(); | |
| 102 | virtual void device_reset(); | |
| 103 | virtual void device_config_complete(); | |
| 104 | ||
| 105 | // internal state | |
| 106 | cpu_device *m_maincpu; | |
| 107 | ||
| 108 | devcb_resolved_write_line m_out_nmi_func; | |
| 109 | devcb_resolved_write_line m_out_irq_func; | |
| 110 | devcb_resolved_write_line m_out_firq_func; | |
| 111 | ||
| 112 | device_bml3bus_card_interface *m_device_list[BML3BUS_MAX_SLOTS]; | |
| 113 | const char *m_cputag; | |
| 114 | }; | |
| 115 | ||
| 116 | ||
| 117 | // device type definition | |
| 118 | extern const device_type BML3BUS; | |
| 119 | ||
| 120 | // ======================> device_bml3bus_card_interface | |
| 121 | ||
| 122 | // class representing interface-specific live bml3bus card | |
| 123 | class device_bml3bus_card_interface : public device_slot_card_interface | |
| 124 | { | |
| 125 | friend class bml3bus_device; | |
| 126 | public: | |
| 127 | // construction/destruction | |
| 128 | device_bml3bus_card_interface(const machine_config &mconfig, device_t &device); | |
| 129 | virtual ~device_bml3bus_card_interface(); | |
| 130 | ||
| 131 | device_bml3bus_card_interface *next() const { return m_next; } | |
| 132 | ||
| 133 | void set_bml3bus_device(); | |
| 134 | ||
| 135 | void raise_slot_nmi() { m_bml3bus->set_nmi_line(ASSERT_LINE); } | |
| 136 | void lower_slot_nmi() { m_bml3bus->set_nmi_line(CLEAR_LINE); } | |
| 137 | void raise_slot_irq() { m_bml3bus->set_irq_line(ASSERT_LINE); } | |
| 138 | void lower_slot_irq() { m_bml3bus->set_irq_line(CLEAR_LINE); } | |
| 139 | void raise_slot_firq() { m_bml3bus->set_firq_line(ASSERT_LINE); } | |
| 140 | void lower_slot_firq() { m_bml3bus->set_firq_line(CLEAR_LINE); } | |
| 141 | ||
| 142 | // inline configuration | |
| 143 | static void static_set_bml3bus_tag(device_t &device, const char *tag, const char *slottag); | |
| 144 | public: | |
| 145 | bml3bus_device *m_bml3bus; | |
| 146 | const char *m_bml3bus_tag, *m_bml3bus_slottag; | |
| 147 | int m_slot; | |
| 148 | device_bml3bus_card_interface *m_next; | |
| 149 | }; | |
| 150 | ||
| 151 | #endif /* __BML3BUS_H__ */ |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r24064 | r24065 | |
|---|---|---|
| 2094 | 2094 | rx78 |
| 2095 | 2095 | bmjr |
| 2096 | 2096 | bml3 |
| 2097 | bml3a | |
| 2098 | bml3b | |
| 2097 | bml3mk2 | |
| 2098 | bml3mk5 | |
| 2099 | 2099 | b16 |
| 2100 | 2100 | psioncm |
| 2101 | 2101 | psionla |
| Previous | 199869 Revisions | Next |