diff options
author | 2022-04-21 08:23:46 -0400 | |
---|---|---|
committer | 2022-04-21 22:23:46 +1000 | |
commit | f7eec60e64d2b9deff71411299c68cb0a8405316 (patch) | |
tree | 6d86bf337c229a50ed9195515c1e615591e3209b | |
parent | 0467f7c836ad162d86182f8a642ed944e3d93479 (diff) |
Get Kurzweil K2000 skeleton driver to boot. (#9545)
-rw-r--r-- | src/mame/drivers/krz2000.cpp | 290 |
1 files changed, 280 insertions, 10 deletions
diff --git a/src/mame/drivers/krz2000.cpp b/src/mame/drivers/krz2000.cpp index c17d110c678..5e92a1ec283 100644 --- a/src/mame/drivers/krz2000.cpp +++ b/src/mame/drivers/krz2000.cpp @@ -5,28 +5,38 @@ krz2000.cpp - Kurzweil K2000 series Skeleton driver by R. Belmont + Additional improvements by Peter Sobot Hardware in brief: - TMP68301 CPU @ 16 MHz + TMP68301 CPU @ 16 MHz (with debug port on RXD2/TXD2) uPD72064 FDC - 85C30 SCSI - M37450 on I/O board to handle panel/display/keyboard scanning + 85C30 SCSI (53C80 on schematic?) + M37450 @ 10 MHz on I/O board to handle panel/display/keyboard scanning, LED control, LCD contrast, and the audio switching matrix + (16K of ROM stored on U69, 384 bytes of RAM, 8 A/D inputs, 2 D/A outputs, 6 ports of I/O, and a 31.25Kbaud serial link to the maincpu) HD6303 on I/O board to manage reverb DSP program loading - VLSI ASIC "Calvin" - Unknown purpose (speculation: handles maincpu and PCM ROM/RAM addressing and DRAM refresh?) + VLSI ASIC "Calvin" - Handles maincpu and PCM ROM/RAM addressing, as well as resampling (and possibly DRAM refresh) (on later K2000 and all later K-series units this is replaced by a more advanced VLSI ASIC "Janis") - 2x VLSI ASIC "Hobbes" - Unknown purpose (speculation: 'reverb' DSP, interpolation, accumulation, and shifting and dithering down a wider accumulator to a 16 bit output sample?) + (service manual says "sample fetching tasks") + 2x VLSI ASIC "Hobbes" - specialized DSP processors for sound synthesis (oscillators, filters, etc) + (service manual says "wave form generation and DSP functions") + (each Hobbes chip handles a subset of available voices, and seems independently programmable) + Digitech DSP256 Multi Effects VLSI Chip (reverb, chorus, delay, etc) + (EPROM seems avaialble on eBay, but the chip itself is quite custom) ***************************************************************************/ #include "emu.h" #include "cpu/m68000/m68000.h" +#include "cpu/m6502/m3745x.h" #include "machine/tmp68301.h" #include "machine/bankdev.h" #include "machine/upd765.h" #include "machine/ncr5380.h" #include "bus/nscsi/cd.h" #include "bus/nscsi/hd.h" +#include "bus/midi/midi.h" #include "video/t6963c.h" +#include "imagedev/floppy.h" #include "screen.h" #include "emupal.h" #include "softlist.h" @@ -38,8 +48,11 @@ public: k2000_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + // , m_scanner(*this, "scanner") , m_1m_bank(*this, "bank1m") , m_mainram(*this, "mainram") + // , m_midi(*this, "midi") + // , m_fdc(*this, "fdc") { } void k2000(machine_config &config); @@ -52,24 +65,105 @@ private: void bank_map_1m(address_map &map); required_device<cpu_device> m_maincpu; + // required_device<cpu_device> m_scanner; required_device<address_map_bank_device> m_1m_bank; required_shared_ptr<uint16_t> m_mainram; + // optional_device<midi_port_device> m_midi; + // required_device<upd765a_device> m_fdc; - void ctrl_w(uint16_t data); + void swap_bit_ctrl_w(uint16_t data); + uint16_t battery_voltage_and_keyscanner_version(offs_t offset); + + uint16_t calvin_read(offs_t offset); + void calvin_write(offs_t offset, uint16_t data); + + uint16_t hobbes0_read(offs_t offset); + void hobbes0_write(offs_t offset, uint16_t data); + + uint16_t hobbes1_read(offs_t offset); + void hobbes1_write(offs_t offset, uint16_t data); void k2000_palette(palette_device &palette) const; + + TIMER_CALLBACK_MEMBER(boot_hack_timer); + emu_timer *m_boot_hack_timer; }; -void k2000_state::ctrl_w(uint16_t data) +/** + * From the K2000/K2000R service manual: + * + * The 68301 processor's 16 megabits (sic) of address space are divided into 16 equal memory blocks, + * numbered 0-15. The first time the K2000 is powered up, Block 0 processes data for the boot + * EPROM and setup EPROM, while Block 1 processes data for the PSRAM. Many of the K2000's basic + * functions utilize the PSRAM, which accesses the higher address space of Block 1 in the CPU. + * This slows down the access time somewhat, since the address space of the CPU is accessed in + * sequence, beginning with Block 0. + * + * To optimize the processing speed, the K2000 performs a one-time software operation when + * powered up for the first time. The memory management unit (MMU) in the gate array logic chip + * (GAL) located at U35 on the engine board executes a "swap bit" function which makes Block 0 + * of the CPU responsible for the PSRAM, and Block 1 responsible for the Boot EPROM and Setup + * EPROM. Consequently the PSRAM functions are processed as early as possible. + * + * Note this "16 equal memory blocks" idea is really just the top hex digit of the address - + * i.e.: 0x?FFFFF + */ +void k2000_state::swap_bit_ctrl_w(uint16_t data) { data &= 0xff; - logerror("%02x to ctrl_w\n", data); - // bit 4: 0=program ROM at 0, work RAM at 100000, 1=work RAM at 0, program ROM at 100000. + logerror("%02x written to swap_bit_ctrl_w\n", data); + // bit 4: + // 0 = program ROM at 0x000000, work RAM at 0x100000 + // 1 = work RAM at 0x000000, program ROM at 0x100000 m_1m_bank->set_bank((data >> 4) & 1); } +uint16_t k2000_state::battery_voltage_and_keyscanner_version(offs_t offset) +{ + logerror("reading battery voltage and keyscanner version at %02x\n", offset); + uint8_t battery_voltage = 0x36; + uint8_t keyscanner_version = 0x12; + return (((uint16_t) battery_voltage) << 8) | ((uint16_t) keyscanner_version); +} + +uint16_t k2000_state::calvin_read(offs_t offset) +{ + logerror("Read from Calvin at %06x\n", offset); + return 0; +} + +void k2000_state::calvin_write(offs_t offset, uint16_t data) +{ + logerror("Write to Calvin at %06x = %04x\n", offset, data); +} + +uint16_t k2000_state::hobbes0_read(offs_t offset) +{ + logerror("Read from Hobbes[0] at %06x\n", offset); + return 0; +} + +void k2000_state::hobbes0_write(offs_t offset, uint16_t data) +{ + logerror("Write to Hobbes[0] at %06x = %04x\n", offset, data); +} + + +uint16_t k2000_state::hobbes1_read(offs_t offset) +{ + logerror("Read from Hobbes[1] at %06x\n", offset); + return 0; +} + +void k2000_state::hobbes1_write(offs_t offset, uint16_t data) +{ + logerror("Write to Hobbes[1] at %06x = %04x\n", offset, data); +} + void k2000_state::machine_start() { + m_boot_hack_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(k2000_state::boot_hack_timer), this)); + m_boot_hack_timer->adjust(attotime::from_seconds(2), 0, attotime::never); } void k2000_state::machine_reset() @@ -77,23 +171,161 @@ void k2000_state::machine_reset() m_1m_bank->set_bank(0); } +TIMER_CALLBACK_MEMBER(k2000_state::boot_hack_timer) +{ + logerror("Jumping to interrupt vector to continue boot sequence"); + m_maincpu->set_pc(m_1m_bank->read32(0x80)); +} + void k2000_state::k2000_map(address_map &map) { // word writes to 000000 region - unknown // word writes to 000090 region - unknown // word writes to 000180 region - unknown // word writes to 000240 region - unknown + + // The engine ROMs are mapped onto 0x0 when ENGROMCSb is low, which is IO3 of GODOT (pin 18) + // The setup ROMs are mapped onto 0x100000 when SUROMCSb is low, which is the IO2 output (pin 17) of GODOT + // This implies that IO3 of GODOT is low iff CA{20,23} are also low, and IO2 of GODOT is low iff CA{20,23} = 0x01 + + // Block 0, Block 1: ROM and RAM (depending on bank switch) map(0x000000, 0x1fffff).m(m_1m_bank, FUNC(address_map_bank_device::amap16)); + + // Lots of writes to 0x372B68 -> 0x372C8C + + // Block 4: PRAM? + // "The K2000 comes standard with 116KB, and with the PRAM upgrade, totals 760KB." + // Another source says: + // For the K2000 Series, the total memory allocated to all of these objects is + // 120K expandable to 760K with the PRAM option. For the K2500 Series, it is 256k, + // expandable to 1280k with the PRAM option. For the K2600 Series, it is 486k, + // expandable to 1506k with the PRAM option. + // These are pretty odd numbers - but it sounds like ~8KB of the RAM space is used + // for OS functions, meaning the built-in RAM might only be 128KB in total. + // The K2000 schematic shows 2x 1M "NVRAM" chips, one for the low byte, and one for + // the high byte, which means we should (?) actually have 2 * 1024 * 1024 / 8 = 262,144 bytes? + // + // The boot routines seem to write to 0x400000 and compare the value saved there, so + // this is probably the optional PRAM expansion. + map(0x400000, 0x400000 + ((2 * 1024 * 1024) / 8) - 1).ram(); + + // Init routine sets 0x4BAB44 -> 0x4BFFFA to 0x0000 + // Reads from 0x4BFFFC and 0x4BFFFE seem to happen on startup. + // HOBBES0CSb = NAND(CS1', CA19) = high unless CS1 is high and CA19 is high + // HOBBES1CSb = NAND(CS1', !CA19) = high unless CS1 is high and CA19 is low + // 0xFFFC00 is the Address Decoder area that controls which part of memory causes CS1 to be "enabled" (low) + // At runtime, + // 0xFFFC00 = 0x50 = + // 0xFFFC01 = 0x3F + // 0xFFFC02 = 0x00 + // 0xFFFC03 = 0x30 + // For CS1: + // 0xFFFC04 = 0x60 = 0b0110 0000 = Start address of the memory area for CS1 = A21 + A22 + // 0xFFFC05 = 0x3F = 0b0011 1111 = Size of memory area = M19 + M18 + M17 + M16 + M15-M9 + M8 = 1MB + // 0xFFFC06 = 0x00 + // 0xFFFC07 = 0x30 = 0b0011 0000 = Area enabled, use external DTACK + // By this logic, Hobbes chips are mapped to 0x100000, 0x200000, 0x400000, 0x600000 + // And their address mask is 0x000FFF00, which means the effective ranges are: + // 0x100???00 + + // Hobbes chip selection seems to look at CA19 and CS1 + + // Internal sample ROM is switched on SBA20,SBA21, which corresponds to CA21,CA22 (one bit off) + // meaning the internal address space for accessing the sample ROM is 0x200000 through 0x6fffff (?) + // Blocks 2, 3, 4, 5, 6 + // map(0x200000, 0x2fffff).rom().region("pcm", 0); // Block 2: Sample ROM + // map(0x300000, 0x3fffff).rom().region("pcm", 0x100000); // Block 3: Sample ROM + // map(0x400000, 0x4fffff).rom().region("pcm", 0x200000); // Block 4: Sample ROM + // Writes to 0x4FFD82, 0x4FFD88, 0x4FFE24 + + // Hypothesis: Calvin (or Janis) is mapped at 0x500000 + // Writes to 0x500402, 0x500418, 0x50041A early in the boot process + // Initialization then writes zeros in a descending ladder: + // 0x500400, 0x500402 + // 0x5003FC, 0x5003FE, ... + // down to 0x500004 (then 0x500006) + + // Calvin memory? + map(0x500000, 0x5003FF).rw(FUNC(k2000_state::calvin_read), FUNC(k2000_state::calvin_write)); + // Calvin control registers? + map(0x500400, 0x5004FF).rw(FUNC(k2000_state::calvin_read), FUNC(k2000_state::calvin_write)); + // Reads and writes to 0x580000 + + // Hobbes (it seems) is connected in the 0x600000 range + // The second Hobbes chip (?) seems connected at 0x680000 + // Initialization seems to: + // - write to 0x600300, followed by 0x600xxx where xxx is in 0x400 through 0x5FF + // - write to 0x6?0002, 0x6?0006, 0x6?0004, through 0x6?000F4 + // - write to 0x600004, 0x600014, 0x600024... through 0x6002F4 + // (with a repeating pattern of [0x02, 0x00, 0x26, 0x24, 0x4A, 0x48]) + // - write to 0x680004, 0x680014, 0x680024... through 0x6802F4 + // (with a repeating pattern of [0x80, 0x02, 0xA4, 0x26, 0xC6, 0x4A]) + // Each Hobbes chip seems to have two control registers, mapped at 0x600300/0x680300 and 0x600400/0x680400 + + // Hobbes memory? + map(0x600000, 0x6002FF).rw(FUNC(k2000_state::hobbes0_read), FUNC(k2000_state::hobbes0_write)); + // Hobbes control registers? + map(0x600300, 0x6005FF).rw(FUNC(k2000_state::hobbes0_read), FUNC(k2000_state::hobbes0_write)); + + // Hobbes memory? + map(0x680000, 0x6802FF).rw(FUNC(k2000_state::hobbes1_read), FUNC(k2000_state::hobbes1_write)); + // Hobbes control registers? + map(0x680300, 0x6805FF).rw(FUNC(k2000_state::hobbes1_read), FUNC(k2000_state::hobbes1_write)); + + // SROM - Setup ROM? + uint32 srom_base = 0x280000; + map(srom_base, srom_base + 0x40000 - 1).rom().region("maincpu", 0x100000); + + // Calvin chip has a 20-bit address bus with A0 tied low and A12-15 tied high, giving it access to 0x?0??[0-E] + // Later models' Janis chips use 24-bit address buses (or at least they're all connected in the schematic) + // Hobbes has a 10-bit address bus with A0 tied low, giving access to 0x0 through 0x3FF + + // Block 7: LCD control and bank switching map(0x700000, 0x700003).rw("lcd", FUNC(lm24014h_device::read), FUNC(lm24014h_device::write)).umask16(0x00ff); - map(0x7e0000, 0x7e0001).w(FUNC(k2000_state::ctrl_w)); + + // Reads from 0x740000 (floppy?) + // Writes to 0x760000 + // Writes to 0x7C0000 + + // Single byte reads seem to happen at 0x740000, which seems to be FDCCTLCSb? + // map(0x740000, 0x74000F). + map(0x7e0000, 0x7e0001).w(FUNC(k2000_state::swap_bit_ctrl_w)); + + // Some sort of hardware mapping - initial firmware boot expects a 4 at $78000B + map(0x780000, 0x78FFFF).ram(); + + // When (CPUASb + GODOT I6) and (GODOT I/O0 + IOCSb) are low, + // Address bits 17, 18, 19 get demultiplexed onto: + // 0, 0, 0 => LCDCSb + // 0, 0, 1 => FDCCSb + // 0, 1, 0 => FDCCTLCSb + // 0, 1, 1 => FDCOUTCSb + // 1, 0, 0 => SCSICSb + // 1, 0, 1 => SCSIDMACSb + // 1, 1, 0 => CPUEXPCSb + // 1, 1, 1 => MCTLREGCSb (OR'ed with WRITELOb to provide input into the Memory Management Control Register) + + // map(0x800000, 0x8fffff); // Block 8: ??? + // map(0x900000, 0x9fffff); // Block 9: ??? + // map(0xa00000, 0xffffff); // Blocks 10, 11, 12, 13, 14: Orchestral ROM + // map(0x1000000, 0x18fffff); // Blocks 15, 16, 17, 18, 19: Contemporary ROM } void k2000_state::bank_map_1m(address_map &map) { map(0x000000, 0x0fffff).rom().region("maincpu", 0); map(0x100000, 0x1fffff).ram().share("mainram"); + + // The "stride" of this bank map is 0x200000, so this is the second "view" of the same data map(0x200000, 0x2fffff).ram().share("mainram"); map(0x300000, 0x3fffff).rom().region("maincpu", 0); + + // Unsure if the battery voltage and keyscanner data is memory-mapped at these ranges (unlikely) + // or if this data is written to some time during the boot process. If it's the latter, + // this will have to change when loading different versions of the ROM (or someone has to figure + // out where the battery voltage is actually read from). + map(0x100000 + 0x1052, 0x100000 + 0x1053).r(FUNC(k2000_state::battery_voltage_and_keyscanner_version)); + map(0x200000 + 0x1052, 0x200000 + 0x1053).r(FUNC(k2000_state::battery_voltage_and_keyscanner_version)); } void k2000_state::k2000(machine_config &config) @@ -101,14 +333,47 @@ void k2000_state::k2000(machine_config &config) TMP68301(config, m_maincpu, XTAL(12'000'000)); m_maincpu->set_addrmap(AS_PROGRAM, &k2000_state::k2000_map); + // MIDI_PORT(config, m_midi, midiin_slot, "midiin"); + // TODO: Uncomment when the TMP68301 has serial/MIDI support, to wire up MIDI I/O and scanner. + // MIDI_PORT(config, m_midi, midiout_slot, "midiout"); + + // M37450(config, m_scanner, XTAL(10'000'000)); + // The "Scanner" sub-CPU is connected to main CPU via: + // - MIDI_FM_ENG, going to P34/RxD, which comes from SERTxD, which is INTMIDITxD == TxD1 + // - 37450_TXD, coming from P35/TxD, which is NAND'd together with 6303_TXD + // and inverted to provide SERRxD to the engine (maincpu), which goes to INTMIDIRxD + // eventually ending up at RxD1 + // Essentially, the 68k's second built-in serial port runs at 31250Hz, which is MIDI baud rate, + // which is how it talks to the scanner to tell it to operate the LEDs on the front of the case. + // The external MIDI port(s) are connected directly to the 68K's first serial port, RxD0 and TxD0. + // (RxD2 and TxD2 are hooked up to a "debug port" which the manual says requires additional + // hardware - this is untested.) + // The scanner's ROM comes from an NTE2764 (U69, 28-pin DIP) EPROM of which 16Kb are used. + // (Note that on the K2500 and above, the scanner is an M37451M8-FP the ROM is 16KB, but stored on an M27256.) + // The scanner ROM from the K2500 may be compatible with the K2000, and can be pulled from "U2" + // on the K2500 Audio Scanner Board (Rev D) + ADDRESS_MAP_BANK(config, "bank1m").set_map(&k2000_state::bank_map_1m).set_options(ENDIANNESS_BIG, 16, 24, 0x200000); + // uPD765AC; clocked through SED9420C + // UPD765A(config, m_fdc, 16_MHz_XTAL / 4, true, true); + // m_fdc->intrq_wr_callback().set_inputline(m_maincpu, I6); + // FLOPPY_CONNECTOR(config, "fdc:0", dss1_floppies, "35dd", floppy_image_device::default_floppy_formats).enable_sound(true); + // FLOPPY_CONNECTOR(config, "fdc:1", dss1_floppies, nullptr, floppy_image_device::default_floppy_formats).enable_sound(true); + + PALETTE(config, "palette", FUNC(k2000_state::k2000_palette), 2); + LM24014H(config, "lcd"); SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); } +void k2000_state::k2000_palette(palette_device &palette) const +{ + palette.set_pen_color(0, rgb_t(131, 136, 139)); + palette.set_pen_color(1, rgb_t( 92, 83, 88)); +} static INPUT_PORTS_START( k2000 ) @@ -199,7 +464,12 @@ ROM_START( k2000 ) ROM_REGION(0x3000, "pals", 0) ROM_LOAD( "pseudo_v4d.u11.gal16v8b.jed", 0x000000, 0x000bd0, CRC(43561132) SHA1(a0c567c81022bc7fb83023d89556ccd5aa1ab36d) ) ROM_LOAD( "sndram_v1.u50.gal16v8b.jed", 0x001000, 0x000bd0, CRC(cabc9335) SHA1(968fa5baa43c7589c901f09b12085437834aeb37) ) + // GODOT seems to take in the top 4 maincpu address lines (A20-A24) and multiplex/decode onto 11 (?) I/O lines + // Effectively takes care of the "memory block" logic (MMU/bank switching) that the service manual describes ROM_LOAD( "godot_v5.u10.gal20v8a.jed", 0x002000, 0x00066f, CRC(c6517456) SHA1(b82530d46afdca5f6460e77ac11710cad55a6b89) ) + // There's an additional GAL20V8 for the MMU - exact logic unknown, but the MCTL[0-3] lines are used, which seem + // like the "address space select" lines - so at least one or more of those address space areas map directly to SBA[22-25], which + // seem to be the Sample Bank address lines. ROM_END CONS( 1990, k2000, 0, 0, k2000, k2000, k2000_state, empty_init, "Kurzweil Music Systems", "K2000", MACHINE_NOT_WORKING|MACHINE_NO_SOUND ) |