From a060de50628ad5a3f2ec590bc3c315c7c4e33223 Mon Sep 17 00:00:00 2001 From: David Haywood Date: Sat, 22 Oct 2016 09:37:10 +0100 Subject: new WORKING Magnet System (prototype) [David Haywood, Ricky2001, ArcadeHacker, IFW] with the following games Time Scanner (TS 2.0, Magnet System, prototype) Exzisus (EX 1.0, Magnet System, prototype) Xain'd Sleena (SC 3.0, Magnet System, prototype) this is a checkpoint, there is a sizeable ToDo list but I think this is a good enough state for initial inclusion before working out the remaining issues. ArcadeHacker has the hardware working for questions etc. I would especially appreciate help with sound (haven't a clue how it hooks up, tried lots of things, no luck) and some help in going over the CPU comms, especially with the sprite CPU as I think I must be missing something important. Likewise help from somebody more familiar with the floppy code from MESS so that it can use that, I had no luck in getting it to work with the copy protection or from a rom region, I've kept all floppy related code in a device so it's very easy to swap out so for now what I've got isn't intrusive. note, very weird idea for a system, they've ported 3 arcade games from other manufacturers, original titles were advertised, but it's likely nothing more of the system exists. the system uses 5 PCBs, one Z80 on each and instead of having dedicated sprite / tilemap chips they have the Z80s doing software rendering, using 8bpp framebuffers. 2 of the boards are for background planes, 1 of the boards is for sprites. The hardware has various memory expansions which look like afterthoughts as they're addressed in strange ways. --- scripts/target/mame/arcade.lua | 6 + src/mame/drivers/cedar_magnet.cpp | 796 +++++++++++++++++++++++++++++++ src/mame/drivers/cedar_magnet.h | 131 +++++ src/mame/drivers/cedar_magnet_board.cpp | 90 ++++ src/mame/drivers/cedar_magnet_board.h | 50 ++ src/mame/drivers/cedar_magnet_flop.cpp | 232 +++++++++ src/mame/drivers/cedar_magnet_flop.h | 49 ++ src/mame/drivers/cedar_magnet_plane.cpp | 162 +++++++ src/mame/drivers/cedar_magnet_plane.h | 59 +++ src/mame/drivers/cedar_magnet_sound.cpp | 168 +++++++ src/mame/drivers/cedar_magnet_sound.h | 53 ++ src/mame/drivers/cedar_magnet_sprite.cpp | 336 +++++++++++++ src/mame/drivers/cedar_magnet_sprite.h | 83 ++++ src/mame/mame.lst | 6 + 14 files changed, 2221 insertions(+) create mode 100644 src/mame/drivers/cedar_magnet.cpp create mode 100644 src/mame/drivers/cedar_magnet.h create mode 100644 src/mame/drivers/cedar_magnet_board.cpp create mode 100644 src/mame/drivers/cedar_magnet_board.h create mode 100644 src/mame/drivers/cedar_magnet_flop.cpp create mode 100644 src/mame/drivers/cedar_magnet_flop.h create mode 100644 src/mame/drivers/cedar_magnet_plane.cpp create mode 100644 src/mame/drivers/cedar_magnet_plane.h create mode 100644 src/mame/drivers/cedar_magnet_sound.cpp create mode 100644 src/mame/drivers/cedar_magnet_sound.h create mode 100644 src/mame/drivers/cedar_magnet_sprite.cpp create mode 100644 src/mame/drivers/cedar_magnet_sprite.h diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 43a57585f2c..aa4a8035006 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -4331,6 +4331,12 @@ files { MAME_DIR .. "src/mame/machine/cdislave.h", MAME_DIR .. "src/mame/machine/cdicdic.cpp", MAME_DIR .. "src/mame/machine/cdicdic.h", + MAME_DIR .. "src/mame/drivers/cedar_magnet.cpp", + MAME_DIR .. "src/mame/drivers/cedar_magnet_sound.cpp", + MAME_DIR .. "src/mame/drivers/cedar_magnet_plane.cpp", + MAME_DIR .. "src/mame/drivers/cedar_magnet_sprite.cpp", + MAME_DIR .. "src/mame/drivers/cedar_magnet_board.cpp", + MAME_DIR .. "src/mame/drivers/cedar_magnet_flop.cpp", MAME_DIR .. "src/mame/drivers/cesclass.cpp", MAME_DIR .. "src/mame/drivers/chance32.cpp", MAME_DIR .. "src/mame/drivers/chexx.cpp", diff --git a/src/mame/drivers/cedar_magnet.cpp b/src/mame/drivers/cedar_magnet.cpp new file mode 100644 index 00000000000..fe4617278ab --- /dev/null +++ b/src/mame/drivers/cedar_magnet.cpp @@ -0,0 +1,796 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +// thanks to: Ricky2001, ArcadeHacker, IFW + +/* + todo: + - fix sound emulation + - fix sprite communication / banking + * bit "output bit 0x02 %d (IC21)" at 0x42 might be important + * mag_exzi currently requires a gross hack to stop the sprite CPU crashing on startup + * mag_xain sometimes leaves old sprites on the screen, probably due to a lost clear + command + - fix flipscreen + - verify behavior of unknown / unused ports / interrupt sources etc. + - verify the disk images, convert to a better format that can natively store protection + * RAW data also available if required + * as mentioned, the disks are copy protected, see notes below + * are the bad tiles shortly into the first level of mag_exzi caused by a bad dump or + bad comms? + - Use proper floppy drive emulation code that originally came from MESS (tied with above) + - verify all clocks and screen params (50hz seems to match original videos) + - work out why we need a protection hack and replace it with proper emulation + * there are no per-game protection devices, so it's something to do with the base hardware + * there seem to be 2 checks, one based on a weird sector on the discs, the other based on + a port read + - add additional hardware notes from ArcadeHacker + +*/ + + +/* + + Magnet System by + + EFO SA (Electrónica Funcional Operativa SA). + based on Cedar hardware + + + http://retrolaser.es/cedar-computer-el-ordenador-profesional-de-efo-sa/ + http://www.recreativas.org/magnet-system-2427-efosa + + A number of original games as well as conversions were advertised for this system, it is however + believed that EFO went bankrupt before anything hit the market. The only 3 dumped games are + conversions and appear to be in incomplete states (it is rather easy to break Time Scanner for + example, the ball simply gets stuck in some places) These are not simply bootlegs, they're + completely original pieces of code more akin to home computer ports. + + The following were advertised + Original Games + - A Day in Space ** + - Crazy Driver + - Jungle Trophy + - Quadrum + - War Mission ** + - The Burning Cave + - Scorpio + - Paris Dakar ** + - Sailing Race + - Formula + + Ports / Conversions + - Exzisus * + - Double Dragon + - Flying Shark + - Time Scanner * + - Xain d'Sleena * + - Boody Kids (Booby Kids?) + + ** screenshots present on flyer + * dumps exist + + + +Disk Protection + +Sectors are 1024 (0x400) bytes long but marked on the disc as 512 bytes as a copy protection +Sector numbering for each track starts at 200 (0xC8) again, presumably as a protection. +Each track has 6 sectors (200 - 205) +The drive runs at 240 RPM allowing for ~25% extra data. (attempting to dump at other speeds won't work) + + data order / sector marking + track 0, side 0, sector 200...205 (instead of sector 0...5) + track 0, side 1, sector 200...205 + track 1, side 0, sector 200...205 + track 1, side 1, sector 200...205 + +Note, the games store settings / scores to the disk and don't provide any kind of 'factory reset' +option, so if used the data will not be pristine. + +PCB Setup + +The hardware consists of 5 main PCBs in a cage. +1x Audio PCB (on top) +1x Master PCB +2x Plane PCBs (both identical aside from jumper settings) +1x Sprite PCB + +There are small memory sub-boards on the Master PCB and Sprite PCB; due to the awkwardness of +the banking at times (and the fact that even with 4 banks of 256 colours, only one can be active) +I suspect the additional memory was an afterthought. + +(put more details hardware notes here) + + +*/ + +#include "cedar_magnet.h" + +/*********************** + + Memory maps + +***********************/ + +static ADDRESS_MAP_START( cedar_magnet_mainboard_sub_pal_map, AS_PROGRAM, 8, cedar_magnet_state ) +// these are 3x MOTOROLA MM2114N SRAM 4096 bit RAM (twice the size because we map bytes, but only 4 bits are used) +// these are on the master board memory sub-board + AM_RANGE(0x2400, 0x27ff) AM_RAM_WRITE(palette_r_w) AM_SHARE("pal_r") + AM_RANGE(0x2800, 0x2bff) AM_RAM_WRITE(palette_g_w) AM_SHARE("pal_g") + AM_RANGE(0x3000, 0x33ff) AM_RAM_WRITE(palette_b_w) AM_SHARE("pal_b") +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cedar_magnet_mainboard_sub_ram_map, AS_PROGRAM, 8, cedar_magnet_state ) +// these are 8x SIEMENS HYB 41256-15 AA - 262,144 bit DRAM (32kbytes) +// these are on the master board memory sub-board + AM_RANGE(0x00000, 0x3ffff) AM_RAM AM_SHARE("ram0") +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cedar_magnet_map, AS_PROGRAM, 8, cedar_magnet_state ) + AM_RANGE(0x0000, 0xffff) AM_DEVICE("bank0", address_map_bank_device, amap8) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cedar_magnet_io, AS_IO, 8, cedar_magnet_state ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + + AM_RANGE(0x18, 0x18) AM_READWRITE(port18_r, port18_w) + AM_RANGE(0x19, 0x19) AM_READWRITE(port19_r, port19_w) + AM_RANGE(0x1a, 0x1a) AM_READ(port1a_r) + AM_RANGE(0x1b, 0x1b) AM_WRITE(port1b_w) + + AM_RANGE(0x20, 0x23) AM_DEVREADWRITE("z80pio_ic48", z80pio_device, read_alt, write_alt) + AM_RANGE(0x40, 0x43) AM_DEVREADWRITE("z80pio_ic49", z80pio_device, read_alt, write_alt) + + AM_RANGE(0x60, 0x63) AM_DEVREADWRITE("flop", cedar_magnet_flop_device, read, write) + + AM_RANGE(0x64, 0x64) AM_READ_PORT("P1_IN") + AM_RANGE(0x68, 0x68) AM_READ_PORT("P2_IN") + AM_RANGE(0x6c, 0x6c) AM_READ_PORT("TEST") + + // banking / access controls to the sub-board memory + AM_RANGE(0x70, 0x70) AM_WRITE(rambank_palbank_w) + AM_RANGE(0x74, 0x74) AM_WRITE(palupload_w) + AM_RANGE(0x78, 0x78) AM_READWRITE(watchdog_r, paladdr_w) + AM_RANGE(0x7c, 0x7c) AM_READ(port7c_r) // protection?? + + AM_RANGE(0xff, 0xff) AM_WRITE(soundlatch_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cedar_bank0, AS_PROGRAM, 8, cedar_magnet_state ) + /* memory configuration 0 */ + AM_RANGE(0x00000, 0x0ffff) AM_DEVICE("mb_sub_ram", address_map_bank_device, amap8) + + /* memory configuration 1 */ + AM_RANGE(0x10000, 0x1dfff) AM_DEVICE("mb_sub_ram", address_map_bank_device, amap8) + AM_RANGE(0x1e000, 0x1ffff) AM_ROM AM_REGION("maincpu", 0x0000) + + /* memory configuration 2*/ + AM_RANGE(0x20000, 0x2bfff) AM_DEVICE("mb_sub_ram", address_map_bank_device, amap8) + AM_RANGE(0x2c000, 0x2ffff) AM_READWRITE(other_cpu_r, other_cpu_w) + + /* memory configuration 3*/ + AM_RANGE(0x30000, 0x31fff) AM_ROM AM_REGION("maincpu", 0x0000) AM_MIRROR(0x0e000) +ADDRESS_MAP_END + + +/*********************** + + 7x - ports + Main board RAM sub-board + +***********************/ + +WRITE8_MEMBER(cedar_magnet_state::rambank_palbank_w) +{ + // ---- --xx + // xx = program bank + m_sub_ram_bankdev->set_bank(data & 0x03); + + // yyy? yy-- palette bank + m_palbank = data; + int palbank = ((data & 0xc0) >> 6) | (data & 0x3c); + m_sub_pal_bankdev->set_bank(palbank); +} + +WRITE8_MEMBER(cedar_magnet_state::palupload_w) +{ + m_sub_pal_bankdev->write8(space, m_paladdr, data); +} + +WRITE8_MEMBER(cedar_magnet_state::paladdr_w) +{ + m_paladdr = data; +} + +READ8_MEMBER(cedar_magnet_state::watchdog_r) +{ + // watchdog + return 0x00; +} + + +/*********************** + + 7c - protection?? + +***********************/ + +READ8_MEMBER(cedar_magnet_state::port7c_r) +{ + //printf("%s: port7c_r\n", device().machine().describe_context()); + return 0x01; +} + + +/*********************** + + 1x ports + Unknown, debug? protection? + +***********************/ + +READ8_MEMBER(cedar_magnet_state::port18_r) +{ +// printf("%s: port18_r\n", device().machine().describe_context()); + return 0x00; +} + +WRITE8_MEMBER(cedar_magnet_state::port18_w) +{ +// printf("%s: port18_w %02x\n", device().machine().describe_context(), data); +} + +READ8_MEMBER(cedar_magnet_state::port19_r) +{ + UINT8 ret = 0x00; +// printf("%s: port19_r\n", device().machine().describe_context()); + +// 9496 in a,($19) +// 9498 bit 2,a + + ret |= 0x04; + + return ret; +} + +READ8_MEMBER(cedar_magnet_state::port1a_r) +{ +// printf("%s: port1a_r\n", device().machine().describe_context()); + return 0x00; +} + + +WRITE8_MEMBER(cedar_magnet_state::port19_w) +{ +// printf("%s: port19_w %02x\n", device().machine().describe_context(), data); +} + +WRITE8_MEMBER(cedar_magnet_state::port1b_w) +{ +// printf("%s: port1b_w %02x\n", device().machine().describe_context(), data); +} + +/*********************** + + Palette / Video + +***********************/ + +void cedar_magnet_state::set_palette(int offset) +{ + m_palette->set_pen_color(offset^0xff, pal4bit(m_pal_r[offset]), pal4bit(m_pal_g[offset]), pal4bit(m_pal_b[offset])); +} + +WRITE8_MEMBER(cedar_magnet_state::palette_r_w) +{ + m_pal_r[offset] = data; + set_palette(offset); +} + +WRITE8_MEMBER(cedar_magnet_state::palette_g_w) +{ + m_pal_g[offset] = data; + set_palette(offset); +} + +WRITE8_MEMBER(cedar_magnet_state::palette_b_w) +{ + m_pal_b[offset] = data; + set_palette(offset); +} + +UINT32 cedar_magnet_state::screen_update_cedar_magnet(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + + bitmap.fill(m_palette->black_pen(), cliprect); + + int pal = (m_palbank >> 6); + + m_cedplane1->draw(screen, bitmap, cliprect,pal); + m_cedplane0->draw(screen, bitmap, cliprect,pal); + m_cedsprite->draw(screen, bitmap, cliprect,pal); + + return 0; +} + +void cedar_magnet_state::video_start() +{ +} + +/*********************** + + Access to other CPUs + +***********************/ + +WRITE8_MEMBER(cedar_magnet_state::soundlatch_w) +{ +// printf("%s: writing soundlatch_w! %02x\n", device().machine().describe_context(), data); + portff_data = data; + m_cedsound->write_command(data); +} + +READ8_MEMBER(cedar_magnet_state::other_cpu_r) +{ + int bankbit0 = (m_ic48_pio_pa_val & 0x60) >> 5; + int plane0select = (m_ic48_pio_pa_val & 0x07) >> 0; + int plane1select = (m_ic48_pio_pb_val & 0x07) >> 0; + int spriteselect = (m_ic48_pio_pb_val & 0x70) >> 4; + int soundselect = (m_ic49_pio_pb_val & 0x70) >> 4; + int windowbank = (m_ic49_pio_pb_val & 0x0c) >> 2; + int unk2 = (m_ic49_pio_pb_val & 0x03) >> 0; + + int cpus_accessed = 0; + UINT8 ret = 0x00; + + int offset2 = offset + windowbank * 0x4000; + + if (spriteselect == 0x1) + { + cpus_accessed++; + ret |= m_cedsprite->read_cpu_bus(offset2); + } + + if (plane0select == 0x1) + { + cpus_accessed++; + ret |= m_cedplane0->read_cpu_bus(offset2); + } + + if (plane1select == 0x1) + { + cpus_accessed++; + ret |= m_cedplane1->read_cpu_bus(offset2); + } + + if (soundselect == 0x1) + { + cpus_accessed++; + ret |= m_cedsound->read_cpu_bus(offset2); + logerror("%s: reading soundselect! %04x - bank bits %d %d %d %d %d %d %d\n", device().machine().describe_context(), offset,bankbit0, plane0select, plane1select, spriteselect, soundselect, windowbank, unk2); + } + + if (cpus_accessed != 1) + logerror("%s: reading multiple CPUS!!! %04x - bank bits %d %d %d %d %d %d %d\n", device().machine().describe_context(), offset,bankbit0, plane0select, plane1select, spriteselect, soundselect, windowbank, unk2); + +// if ((offset==0) || (offset2 == 0xe) || (offset2 == 0xf) || (offset2 == 0x68)) +// logerror("%s: reading banked bus area %04x - bank bits %d %d %d %d %d %d %d\n", device().machine().describe_context(), offset,bankbit0, plane0select, plane1select, spriteselect, soundselect, windowbank, unk2); + + return ret; +} + +WRITE8_MEMBER(cedar_magnet_state::other_cpu_w) +{ + int bankbit0 = (m_ic48_pio_pa_val & 0x60) >> 5; + int plane0select = (m_ic48_pio_pa_val & 0x07) >> 0; + int plane1select = (m_ic48_pio_pb_val & 0x07) >> 0; + int spriteselect = (m_ic48_pio_pb_val & 0x70) >> 4; + int soundselect = (m_ic49_pio_pb_val & 0x70) >> 4; + int windowbank = (m_ic49_pio_pb_val & 0x0c) >> 2; + int unk2 = (m_ic49_pio_pb_val & 0x03) >> 0; + + int cpus_accessed = 0; + + int offset2 = offset + windowbank * 0x4000; + + if (spriteselect == 0x1) + { + cpus_accessed++; + m_cedsprite->write_cpu_bus(offset2, data); + } + + if (plane0select == 0x1) + { + cpus_accessed++; + m_cedplane0->write_cpu_bus(offset2, data); + } + + if (plane1select == 0x1) + { + cpus_accessed++; + m_cedplane1->write_cpu_bus(offset2, data); + } + + if (soundselect == 0x1) + { + cpus_accessed++; + m_cedsound->write_cpu_bus(offset2, data); + // printf("%s: sound cpu write %04x %02x - bank bits %d %d %d %d %d %d %d\n", device().machine().describe_context(), offset,data, bankbit0, plane0select, plane1select, spriteselect, soundselect, windowbank, unk2); + } + + if (cpus_accessed != 1) + logerror("%s: writing multiple CPUS!!! %04x %02x - bank bits %d %d %d %d %d %d %d\n", device().machine().describe_context(), offset,data, bankbit0, plane0select, plane1select, spriteselect, soundselect, windowbank, unk2); + +// if ((offset==0) || (offset2 == 0xe) || (offset2 == 0xf) || (offset2 == 0x68)) +// printf("%s: other cpu write %04x %02x - bank bits %d %d %d %d %d %d %d\n", device().machine().describe_context(), offset,data, bankbit0, plane0select, plane1select, spriteselect, soundselect, windowbank, unk2); +} + + +void cedar_magnet_state::handle_sub_board_cpu_lines(cedar_magnet_board_device* dev, int old_data, int data) +{ + if (old_data != data) + { + if (data & 0x04) + dev->reset_assert(); + else + dev->reset_clear(); + + if (data & 0x02) + dev->halt_clear(); + else + dev->halt_assert(); + } +} + +/*********************** + + IC 48 PIO handlers + (mapped at 0x20 / 0x22) + +***********************/ + +READ8_MEMBER( cedar_magnet_state::ic48_pio_pa_r ) // 0x20 +{ + UINT8 ret = m_ic48_pio_pa_val & ~0x08; + + ret |= ioport("COIN1")->read()<<3; + if (!m_cedplane0->is_running()) ret &= ~0x01; + + // interrupt source stuff?? + ret &= ~0x10; + + if (LOG_IC48_PIO_PA) printf("%s: ic48_pio_pa_r (returning %02x)\n", device().machine().describe_context(), ret); + return ret; +} + +WRITE8_MEMBER( cedar_magnet_state::ic48_pio_pa_w ) // 0x20 +{ + int oldplane0select = (m_ic48_pio_pa_val & 0x07) >> 0; + + // bits 19 are set to input? + m_ic48_pio_pa_val = data; + + // address 0x20 - pio ic48 port a + if (LOG_IC48_PIO_PA) printf("%s: ic48_pio_pa_w %02x (memory banking etc.)\n", device().machine().describe_context(), data); + + if (LOG_IC48_PIO_PA) printf("output bit 0x80 %d (unused)\n", (data >> 7)&1); // A7 -> 12 J4 unpopulated + if (LOG_IC48_PIO_PA) printf("output bit 0x40 %d (bank)\n", (data >> 6)&1); // A6 -> 2 74HC10 3NAND IC19 + if (LOG_IC48_PIO_PA) printf("output bit 0x20 %d (bank)\n", (data >> 5)&1); // A5 -> 4 74HC10 3NAND IC19 + if (LOG_IC48_PIO_PA) printf("input bit 0x10 %d (interrupt source related?)\n", (data >> 4)&1); // 10 in // A4 <- 9 74HC74 IC20 <- input from 18 74LS244 IC61 + if (LOG_IC48_PIO_PA) printf("input bit 0x08 %d (COIN1)\n", (data >> 3)&1); // 08 in // A3 <- 4 74HC14P (inverter) IC4 <- EDGE 21 COIN1 + if (LOG_IC48_PIO_PA) printf("output bit 0x04 %d (plane0 CPU/bus related?)\n", (data >> 2)&1); // A2 -> 45 J6 + if (LOG_IC48_PIO_PA) printf("output bit 0x02 %d (plane0 CPU/bus related?)\n", (data >> 1)&1); // A1 -> 47 J6 + if (LOG_IC48_PIO_PA) printf("input bit 0x01 %d (plane0 CPU/bus related?)\n", (data >> 0)&1); // A0 -> 49 J6 + + int bankbit0 = (m_ic48_pio_pa_val & 0x60) >> 5; + m_bank0->set_bank(bankbit0); + + int plane0select = (m_ic48_pio_pa_val & 0x07) >> 0; + + handle_sub_board_cpu_lines(m_cedplane0, oldplane0select, plane0select); +} + + +READ8_MEMBER( cedar_magnet_state::ic48_pio_pb_r ) // 0x22 +{ + UINT8 ret = m_ic48_pio_pb_val & ~0x80; + + ret |= ioport("COIN2")->read()<<7; + + if (!m_cedsprite->is_running()) ret &= ~0x10; + if (!m_cedplane1->is_running()) ret &= ~0x01; + + if (LOG_IC48_PIO_PB) printf("%s: ic48_pio_pb_r (returning %02x)\n", device().machine().describe_context(), ret); + return ret; +} + +WRITE8_MEMBER(cedar_magnet_state::ic48_pio_pb_w) // 0x22 +{ + int oldplane1select = (m_ic48_pio_pb_val & 0x07) >> 0; + int oldspriteselect = (m_ic48_pio_pb_val & 0x70) >> 4; + + m_ic48_pio_pb_val = data; + + if (LOG_IC48_PIO_PB) printf("%s: ic48_pio_pb_w %02x\n", device().machine().describe_context(), data); + + // address 0x22 - pio ic48 port b + if (LOG_IC48_PIO_PB) printf("input bit 0x80 %d (COIN2)\n", (data >> 7)&1); // B7 <- 2 74HC14P (inverter) IC4 <- EDGE 22 COIN2 + if (LOG_IC48_PIO_PB) printf("output bit 0x40 (J6) (sprite CPU/bus related?) %d\n", (data >> 6)&1); // B6 -> 41 J6 + if (LOG_IC48_PIO_PB) printf("output bit 0x20 (J6) (sprite CPU/bus related?) %d\n", (data >> 5)&1); // B5 -> 43 J6 + if (LOG_IC48_PIO_PB) printf("input bit 0x10 (J6) (sprite CPU/bus related?) %d\n", (data >> 4)&1); // B4 -> 44 J6 + if (LOG_IC48_PIO_PB) printf("output bit 0x08 (Q8) %d\n", (data >> 3)&1); // B3 -> Q8 transistor + if (LOG_IC48_PIO_PB) printf("output bit 0x04 (J6) (plane1 CPU/bus related?) %d\n", (data >> 2)&1); // B2 -> 46 J6 + if (LOG_IC48_PIO_PB) printf("output bit 0x02 (J6) (plane1 CPU/bus related?) %d\n", (data >> 1)&1); // B1 -> 48 J6 + if (LOG_IC48_PIO_PB) printf("input bit 0x01 (J6) (plane1 CPU/bus related?) %d\n", (data >> 0)&1); // B0 -> 50 J6 + + int plane1select = (m_ic48_pio_pb_val & 0x07) >> 0; + int spriteselect = (m_ic48_pio_pb_val & 0x70) >> 4; + + handle_sub_board_cpu_lines(m_cedplane1, oldplane1select, plane1select); + handle_sub_board_cpu_lines(m_cedsprite, oldspriteselect, spriteselect); +} + +/*********************** + + IC 49 PIO handlers + (mapped at 0x42) + +***********************/ + +READ8_MEMBER( cedar_magnet_state::ic49_pio_pb_r ) // 0x42 +{ + UINT8 ret = m_ic49_pio_pb_val; + + if (!m_cedsound->is_running()) ret &= ~0x10; + + if (LOG_IC49_PIO_PB) printf("%s: ic49_pio_pb_r (returning %02x)\n", device().machine().describe_context(), ret); + return ret; +} + +WRITE8_MEMBER( cedar_magnet_state::ic49_pio_pb_w ) // 0x42 +{ + int oldsoundselect = (m_ic49_pio_pb_val & 0x70) >> 4; + + m_ic49_pio_pb_val = data; + + //printf("%s: ic49_pio_pb_w %02x\n", device().machine().describe_context(), data); + + // address 0x42 - pio ic49 port b + if (LOG_IC49_PIO_PB) printf("output bit 0x80 %d (Q9)\n", (data >> 7)&1); // B7 -> Q9 transistor + if (LOG_IC49_PIO_PB) printf("output bit 0x40 %d (sound CPU bus related) (J3)\n", (data >> 6)&1); // B6 -> 9 J3 + if (LOG_IC49_PIO_PB) printf("output bit 0x20 %d (sound CPU bus related) (J3)\n", (data >> 5)&1); // B5 -> 8 J3 + if (LOG_IC49_PIO_PB) printf("input bit 0x10 %d (sound CPU bus related) (J3)\n", (data >> 4)&1); // B4 -> 7 J3 // input? + if (LOG_IC49_PIO_PB) printf("output bit 0x08 %d (J7)\n", (data >> 3)&1); // B3 -> 35 J7 bank bits + if (LOG_IC49_PIO_PB) printf("output bit 0x04 %d (J7)\n", (data >> 2)&1); // B2 -> 36 J7 bank bits + // there is code to mask out both bottom bits here before load operations? + if (LOG_IC49_PIO_PB) printf("output bit 0x02 %d (IC21)\n", (data >> 1)&1); // B1 -> 3 74HC04 IC21 (set before some SPRITE cpu operations, possibly halts the blitter?) + if (LOG_IC49_PIO_PB) printf("output bit 0x01 (LED) %d\n", (data >> 0)&1); // B0 -> LED LD1 + + + + int soundselect = (m_ic49_pio_pb_val & 0x70) >> 4; + + handle_sub_board_cpu_lines(m_cedsound, oldsoundselect, soundselect); +} + +/*********************** + + Init / Inputs / Machine + +***********************/ + +void cedar_magnet_state::machine_start() +{ + save_item(NAME(m_paladdr)); +} + +void cedar_magnet_state::machine_reset() +{ + m_ic48_pio_pa_val = 0xff; + portff_data = 0x00; + + int bankbit0 = (m_ic48_pio_pa_val & 0x60) >> 5; + m_bank0->set_bank(bankbit0); + m_sub_ram_bankdev->set_bank(3); + m_sub_pal_bankdev->set_bank(0); +} + + +static INPUT_PORTS_START( cedar_magnet ) + PORT_START("COIN1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN1 ) + + PORT_START("COIN2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN2 ) + + PORT_START("P1_IN") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3 ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START1 ) + + PORT_START("P2_IN") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START2 ) + + PORT_START("TEST") + PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_SERVICE_NO_TOGGLE( 0x80, IP_ACTIVE_LOW ) +INPUT_PORTS_END + +INTERRUPT_GEN_MEMBER(cedar_magnet_state::irq) +{ + if (m_prothack) + m_prothack(this); + + m_maincpu->set_input_line(0, HOLD_LINE); + // maybe generate the irqs for the other PCBs here? +} + +static MACHINE_CONFIG_START( cedar_magnet, cedar_magnet_state ) + + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", Z80,4000000) /* ? MHz */ + MCFG_CPU_PROGRAM_MAP(cedar_magnet_map) + MCFG_CPU_IO_MAP(cedar_magnet_io) + MCFG_CPU_VBLANK_INT_DRIVER("screen", cedar_magnet_state, irq) + + MCFG_DEVICE_ADD("bank0", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(cedar_bank0) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_LITTLE) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(8) + MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(18) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x10000) + + MCFG_DEVICE_ADD("mb_sub_ram", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(cedar_magnet_mainboard_sub_ram_map) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_LITTLE) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(8) + MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(18) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x10000) + + MCFG_DEVICE_ADD("mb_sub_pal", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(cedar_magnet_mainboard_sub_pal_map) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_LITTLE) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(8) + MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(8+6) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x100) + + MCFG_DEVICE_ADD("z80pio_ic48", Z80PIO, 4000000/2) +// MCFG_Z80PIO_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0)) + MCFG_Z80PIO_IN_PA_CB(READ8(cedar_magnet_state, ic48_pio_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(cedar_magnet_state, ic48_pio_pa_w)) + MCFG_Z80PIO_IN_PB_CB(READ8(cedar_magnet_state, ic48_pio_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(cedar_magnet_state, ic48_pio_pb_w)) + + MCFG_DEVICE_ADD("z80pio_ic49", Z80PIO, 4000000/2) +// MCFG_Z80PIO_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0)) +// MCFG_Z80PIO_IN_PA_CB(READ8(cedar_magnet_state, ic49_pio_pa_r)) // NOT USED +// MCFG_Z80PIO_OUT_PA_CB(WRITE8(cedar_magnet_state, ic49_pio_pa_w)) // NOT USED + MCFG_Z80PIO_IN_PB_CB(READ8(cedar_magnet_state, ic49_pio_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(cedar_magnet_state, ic49_pio_pb_w)) + + /* video hardware */ + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) + MCFG_SCREEN_SIZE(256, 256) + MCFG_SCREEN_VISIBLE_AREA(0, 256-8-1, 0, 192-1) + MCFG_SCREEN_UPDATE_DRIVER(cedar_magnet_state, screen_update_cedar_magnet) + MCFG_SCREEN_PALETTE("palette") + + MCFG_PALETTE_ADD("palette", 0x400) + + MCFG_CEDAR_MAGNET_SOUND_ADD("cedtop") + MCFG_CEDAR_MAGNET_PLANE_ADD("cedplane0") + MCFG_CEDAR_MAGNET_PLANE_ADD("cedplane1") + MCFG_CEDAR_MAGNET_SPRITE_ADD("cedsprite") + + MCFG_CEDAR_MAGNET_FLOP_ADD("flop") + + MCFG_QUANTUM_PERFECT_CPU("maincpu") +MACHINE_CONFIG_END + + +#define BIOS_ROM \ + ROM_REGION( 0x10000, "maincpu", 0 ) \ + ROM_LOAD( "Magnet-Master-VID-E03.BIN", 0x00000, 0x02000, CRC(86c4a4f0) SHA1(6db1a006b2e0b2a7cc9748ade881debb098b6757) ) + + + +ROM_START( cedmag ) + BIOS_ROM + + ROM_REGION( 0x100000, "flop:disk", ROMREGION_ERASE00 ) + // no disk inserted +ROM_END + +ROM_START( mag_time ) + BIOS_ROM + + ROM_REGION( 0x100000, "flop:disk", 0 ) + ROM_LOAD( "timescanner.img", 0x00000, 0xf0000, CRC(214c558c) SHA1(9c71fce35acaf17ac685f77aebb1b0a930060f0b) ) +ROM_END + +ROM_START( mag_exzi ) + BIOS_ROM + + ROM_REGION( 0x100000, "flop:disk", ROMREGION_ERASE00 ) // I don't 100% trust this one + ROM_LOAD( "exzisus.img", 0x00000, 0xf0000, BAD_DUMP CRC(1ac7409e) SHA1(b894bd65b0b9699e18a1ab49f309c460488f0ef8) ) +ROM_END + +ROM_START( mag_xain ) + BIOS_ROM + + ROM_REGION( 0x100000, "flop:disk", ROMREGION_ERASE00 ) + ROM_LOAD( "xain.img", 0x00000, 0xf0000, CRC(5647849f) SHA1(edd2f3f6359424583bf526bf4601476dc849e617) ) +ROM_END + +/* + protection? (Time Scanner note) + + one part of the code is a weird loop checking values from port 0x7c while doing other nonsensical stuff, a flag gets set to 0xff if it fails + + the other part is after reading the weird extra block on the disk (score / protection data at 0xea400 in the disk image*) and again a flag + gets set to 0xff in certain conditions there's then a check after inserting a coin, these values can't be 0xff at that point, and there + doesn't appear to be any code to reset them. + + *0xea400 is/was track 4e, side 00, sector 01 for future reference if the floppy format changes + + all games have the same code in them but at different addresses +*/ + + +void protection_hack(UINT8* ram, int address1, int address2) +{ + if ((ram[address1] == 0x3e) && (ram[address1+1] == 0xff)) ram[address1] = 0xc9; + if ((ram[address2] == 0x3e) && (ram[address2+1] == 0xff)) ram[address2] = 0xc9; +} + +void mag_time_protection_hack(cedar_magnet_state* state) +{ + protection_hack(state->m_ram0, 0x8bc, 0x905); +} + +void mag_xain_protection_hack(cedar_magnet_state* state) +{ + protection_hack(state->m_ram0, 0x796, 0x7df); +} + +void mag_exzi_protection_hack(cedar_magnet_state* state) +{ + protection_hack(state->m_ram0, 0x8b6, 0x8ff); +} + + + +DRIVER_INIT_MEMBER(cedar_magnet_state, mag_time) +{ + m_prothack = mag_time_protection_hack; +} + +DRIVER_INIT_MEMBER(cedar_magnet_state, mag_xain) +{ + m_prothack = mag_xain_protection_hack; +} + +DRIVER_INIT_MEMBER(cedar_magnet_state, mag_exzi) +{ + m_prothack = mag_exzi_protection_hack; +} + +GAME( 1987, cedmag, 0, cedar_magnet, cedar_magnet, driver_device, 0, ROT0, "EFO SA / Cedar", "Magnet System (prototype)", MACHINE_IS_BIOS_ROOT ) + +GAME( 1987, mag_time, cedmag, cedar_magnet, cedar_magnet, cedar_magnet_state, mag_time, ROT90, "EFO SA / Cedar", "Time Scanner (TS 2.0, Magnet System, prototype)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NO_SOUND ) // original game was by Sega +GAME( 1987, mag_exzi, cedmag, cedar_magnet, cedar_magnet, cedar_magnet_state, mag_exzi, ROT0, "EFO SA / Cedar", "Exzisus (EX 1.0, Magnet System, prototype)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NO_SOUND ) // original game was by Taito +GAME( 1987, mag_xain, cedmag, cedar_magnet, cedar_magnet, cedar_magnet_state, mag_xain, ROT0, "EFO SA / Cedar", "Xain'd Sleena (SC 3.0, Magnet System, prototype)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NO_SOUND ) // original game was by Technos diff --git a/src/mame/drivers/cedar_magnet.h b/src/mame/drivers/cedar_magnet.h new file mode 100644 index 00000000000..feaa610889c --- /dev/null +++ b/src/mame/drivers/cedar_magnet.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* + + +*/ + +#include "emu.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "machine/z80pio.h" +#include "machine/bankdev.h" +#include "machine/z80ctc.h" +#include "sound/ay8910.h" + +#include "cedar_magnet_sound.h" +#include "cedar_magnet_plane.h" +#include "cedar_magnet_sprite.h" +#include "cedar_magnet_flop.h" + +#define LOG_IC49_PIO_PB 0 +#define LOG_IC48_PIO_PB 0 +#define LOG_IC48_PIO_PA 0 + +class cedar_magnet_state : public driver_device +{ +public: + cedar_magnet_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_bank0(*this, "bank0"), + m_sub_ram_bankdev(*this, "mb_sub_ram"), + m_sub_pal_bankdev(*this, "mb_sub_pal"), + m_ram0(*this, "ram0"), + m_pal_r(*this, "pal_r"), + m_pal_g(*this, "pal_g"), + m_pal_b(*this, "pal_b"), + + m_ic48_pio(*this, "z80pio_ic48"), + m_ic49_pio(*this, "z80pio_ic49"), + m_palette(*this, "palette"), + m_maincpu(*this, "maincpu"), + m_cedsound(*this, "cedtop"), + m_cedplane0(*this, "cedplane0"), + m_cedplane1(*this, "cedplane1"), + m_cedsprite(*this, "cedsprite") + { + m_ic48_pio_pa_val = 0xff; + m_ic48_pio_pb_val = 0xff; + m_ic49_pio_pb_val = 0xff; + m_prothack = nullptr; + } + + required_device m_bank0; + required_device m_sub_ram_bankdev; + required_device m_sub_pal_bankdev; + + required_shared_ptr m_ram0; + required_shared_ptr m_pal_r; + required_shared_ptr m_pal_g; + required_shared_ptr m_pal_b; + + required_device m_ic48_pio; + required_device m_ic49_pio; + + DECLARE_READ8_MEMBER(ic48_pio_pa_r); + DECLARE_WRITE8_MEMBER(ic48_pio_pa_w); + + DECLARE_READ8_MEMBER(ic48_pio_pb_r); + DECLARE_WRITE8_MEMBER(ic48_pio_pb_w); + + DECLARE_READ8_MEMBER(ic49_pio_pb_r); + DECLARE_WRITE8_MEMBER(ic49_pio_pb_w); + + // 1x range ports + DECLARE_WRITE8_MEMBER(port18_w); + DECLARE_WRITE8_MEMBER(port19_w); + DECLARE_WRITE8_MEMBER(port1b_w); + + DECLARE_READ8_MEMBER(port18_r); + DECLARE_READ8_MEMBER(port19_r); + DECLARE_READ8_MEMBER(port1a_r); + + // 7x range ports + DECLARE_WRITE8_MEMBER(rambank_palbank_w); + DECLARE_WRITE8_MEMBER(palupload_w); + DECLARE_WRITE8_MEMBER(paladdr_w); + DECLARE_READ8_MEMBER(watchdog_r); + DECLARE_READ8_MEMBER(port7c_r); + + // other ports + DECLARE_WRITE8_MEMBER(soundlatch_w); + UINT8 portff_data; + + DECLARE_READ8_MEMBER(other_cpu_r); + DECLARE_WRITE8_MEMBER(other_cpu_w); + + UINT8 m_paladdr; + int m_palbank; + + UINT8 m_ic48_pio_pa_val; + UINT8 m_ic48_pio_pb_val; + UINT8 m_ic49_pio_pb_val; + + void set_palette(int offset); + DECLARE_WRITE8_MEMBER(palette_r_w); + DECLARE_WRITE8_MEMBER(palette_g_w); + DECLARE_WRITE8_MEMBER(palette_b_w); + + void handle_sub_board_cpu_lines(cedar_magnet_board_device* dev, int old_data, int data); + INTERRUPT_GEN_MEMBER(irq); + void (*m_prothack)(cedar_magnet_state*); + + virtual void machine_start() override; + virtual void machine_reset() override; + virtual void video_start() override; + UINT32 screen_update_cedar_magnet(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + required_device m_palette; + required_device m_maincpu; + + required_device m_cedsound; + required_device m_cedplane0; + required_device m_cedplane1; + required_device m_cedsprite; + + DECLARE_DRIVER_INIT(mag_time); + DECLARE_DRIVER_INIT(mag_xain); + DECLARE_DRIVER_INIT(mag_exzi); + +}; + + diff --git a/src/mame/drivers/cedar_magnet_board.cpp b/src/mame/drivers/cedar_magnet_board.cpp new file mode 100644 index 00000000000..3b95fcc384c --- /dev/null +++ b/src/mame/drivers/cedar_magnet_board.cpp @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + + +#include "emu.h" +#include "cedar_magnet_plane.h" + + +//const device_type CEDAR_MAGNET_BASE = &device_creator; + +cedar_magnet_board_device::cedar_magnet_board_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) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) +// m_ram(*this, "ram") +{ +} + +INTERRUPT_GEN_MEMBER(cedar_magnet_board_device::irq) +{ + m_cpu->set_input_line(0, HOLD_LINE); +} + +void cedar_magnet_board_device::device_start() +{ +} + +void cedar_magnet_board_device::write_cpu_bus(int offset, UINT8 data) +{ + device_t* cpu = m_cpu; + address_space& ap = cpu->memory().space(AS_PROGRAM); + ap.write_byte(offset, data); +} + +UINT8 cedar_magnet_board_device::read_cpu_bus(int offset) +{ + device_t* cpu = m_cpu; + address_space& ap = cpu->memory().space(AS_PROGRAM); + return ap.read_byte(offset); +} + +bool cedar_magnet_board_device::is_running(void) +{ + return m_is_running; +} + +TIMER_CALLBACK_MEMBER(cedar_magnet_board_device::reset_assert_callback) +{ + m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); +} + +TIMER_CALLBACK_MEMBER(cedar_magnet_board_device::reset_clear_callback) +{ + m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); +} + +TIMER_CALLBACK_MEMBER(cedar_magnet_board_device::halt_assert_callback) +{ + m_cpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_is_running = false; +} + +TIMER_CALLBACK_MEMBER(cedar_magnet_board_device::halt_clear_callback) +{ + m_cpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + m_is_running = true; +} + +void cedar_magnet_board_device::halt_assert(void) +{ + machine().scheduler().timer_set(attotime::from_usec(2), timer_expired_delegate(FUNC(cedar_magnet_board_device::halt_assert_callback),this)); +} + +void cedar_magnet_board_device::halt_clear(void) +{ + machine().scheduler().timer_set(attotime::from_usec(2), timer_expired_delegate(FUNC(cedar_magnet_board_device::halt_clear_callback),this)); +} + +void cedar_magnet_board_device::reset_assert(void) +{ + machine().scheduler().timer_set(attotime::from_usec(1), timer_expired_delegate(FUNC(cedar_magnet_board_device::reset_assert_callback),this)); +} + +void cedar_magnet_board_device::reset_clear(void) +{ + machine().scheduler().timer_set(attotime::from_usec(1), timer_expired_delegate(FUNC(cedar_magnet_board_device::reset_clear_callback),this)); +} + +void cedar_magnet_board_device::device_reset() +{ + halt_assert(); +} diff --git a/src/mame/drivers/cedar_magnet_board.h b/src/mame/drivers/cedar_magnet_board.h new file mode 100644 index 00000000000..2d04f8a156c --- /dev/null +++ b/src/mame/drivers/cedar_magnet_board.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +// just a base device to hold some common functions of the EFO / Cedar Magnet System PCBs + +#pragma once + +#ifndef CEDAR_MAGNET_BOARD_DEF +#define CEDAR_MAGNET_BOARD_DEF + +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "machine/z80pio.h" + +extern const device_type CEDAR_MAGNET_PLANE; + +class cedar_magnet_board_device : public device_t +{ +public: + // construction/destruction + cedar_magnet_board_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); + + UINT8* m_ram; + z80_device* m_cpu; + + virtual UINT8 read_cpu_bus(int offset); + virtual void write_cpu_bus(int offset, UINT8 data); + + TIMER_CALLBACK_MEMBER(halt_assert_callback); + TIMER_CALLBACK_MEMBER(halt_clear_callback); + TIMER_CALLBACK_MEMBER(reset_assert_callback); + TIMER_CALLBACK_MEMBER(reset_clear_callback); + + void halt_assert(void); + void halt_clear(void); + void reset_assert(void); + void reset_clear(void); + bool is_running(void); + bool m_is_running; + + INTERRUPT_GEN_MEMBER(irq); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + +private: +}; + +#endif diff --git a/src/mame/drivers/cedar_magnet_flop.cpp b/src/mame/drivers/cedar_magnet_flop.cpp new file mode 100644 index 00000000000..7d4bdd8d42c --- /dev/null +++ b/src/mame/drivers/cedar_magnet_flop.cpp @@ -0,0 +1,232 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +// todo, scrap this and use the core SAB 2797B emulation +// (FM - MFM type) @ 1.25mhz (oscillates 1.250~1.251) + + +#include "emu.h" +#include "cedar_magnet_flop.h" + +extern const device_type CEDAR_MAGNET_FLOP = &device_creator; + +cedar_magnet_flop_device::cedar_magnet_flop_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CEDAR_MAGNET_FLOP, "Cedar Floppy Simulation", tag, owner, clock, "cedmag_flop", __FILE__) +{ +} + + +static MACHINE_CONFIG_FRAGMENT( cedar_magnet_flop ) + MCFG_NVRAM_ADD_NO_FILL("floppy_nvram") +MACHINE_CONFIG_END + +machine_config_constructor cedar_magnet_flop_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cedar_magnet_flop ); +} + +void cedar_magnet_flop_device::device_start() +{ + subdevice("floppy_nvram")->set_base(memregion("disk")->base(), 0xf0000); +} + +void cedar_magnet_flop_device::device_reset() +{ + m_flopdat = 0; + m_flopcmd = 0; + m_flopsec = 0; + m_flopstat = 0; + m_floptrk = 0; +} + +READ8_MEMBER(cedar_magnet_flop_device::port60_r) +{ + UINT8 ret = m_flopstat; + return ret; +} + +READ8_MEMBER(cedar_magnet_flop_device::port61_r) +{ + UINT8 ret = m_curtrack; + return ret; +} + +READ8_MEMBER(cedar_magnet_flop_device::port63_r) +{ + UINT8 ret = rand(); + + // printf("%s: port63_r (DATA) (%02x)\n", device().machine().describe_context(), ret); + + if ((m_flopcmd&0xf0) == 0x90) // reading data + { + UINT8 *flop = memregion("disk")->base(); + int side = (m_flopcmd & 0x02)>>1; + int read_offset_base = (m_flopsec * 0x400) + (m_curtrack * 0x3000) + (side * 0x1800); + + int sector_size = 1024; + + if (m_secoffs < sector_size) + { + m_flopstat |= 0x05; + + int read_offset = read_offset_base + m_secoffs; + ret = flop[read_offset]; + + if (m_secoffs == 0) + { + // this is weird data, protection?? + if(read_offset_base==0xea400) + printf("reading sector %d offset %d (from disk image at %04x) (cur track %02x cur side %02x cur sector %02x)\n", m_flopsec, m_secoffs, read_offset, m_curtrack, side, m_flopsec); + } + + m_secoffs++; + + if (m_secoffs == sector_size) + { + //printf("finished sector read\n"); + m_flopstat &= ~0x05; + + m_secoffs = 0; + m_flopsec++; + } + } + else + { + printf("read past sector!! %d\n", m_secoffs); + m_secoffs++; + } + + } + else + { + fatalerror("read data in non-read mode?\n"); + } +// + return ret; +} + +WRITE8_MEMBER(cedar_magnet_flop_device::port60_w) +{ + //printf("%s: port60_w (COMMAND) %02x\n", device().machine().describe_context(), data); + m_flopcmd = data; + + + switch (m_flopcmd & 0xf0) + { + case 0x00: + //printf("restore\n"); + m_flopstat = 0x06; + m_curtrack = 0x00; + break; + + case 0x10: + //printf("seek track\n"); + m_curtrack = m_flopdat; + break; + + + case 0x90: + //printf("read sector\n"); + m_flopstat |= 0x07; + m_secoffs = 0; + break; + + case 0xb0: + //printf("write sector\n"); + m_flopstat |= 0x07; + m_secoffs = 0; + break; + + case 0xd0: + //printf("force interrupt?\n"); + // m_flopstat = 0x06; + // m_flopstat &= ~0x07; + // m_maincpu->set_input_line(0, HOLD_LINE); + + break; + + + default: + printf("unhandled disk command %02x\n", m_flopcmd); + } + +} + +WRITE8_MEMBER(cedar_magnet_flop_device::port62_w) +{ + //printf("%s: port62_w (SECTOR) %02x\n", device().machine().describe_context(), data); + m_flopsec = data; + + if (m_flopsec < 200) + { + printf("sector specified <200!\n"); + } + + m_flopsec -= 200; +} + +WRITE8_MEMBER(cedar_magnet_flop_device::port63_w) +{ + //printf("%s: port63_w (DATA) %02x\n", device().machine().describe_context(), data); + m_flopdat = data; + + if ((m_flopcmd & 0xf0) == 0xb0) // writing data + { + UINT8 *flop = memregion("disk")->base(); + int side = (m_flopcmd & 0x02)>>1; + int read_offset_base = (m_flopsec * 0x400) + (m_curtrack * 0x3000) + (side * 0x1800); + + int sector_size = 1024; + + if (m_secoffs < sector_size) + { + m_flopstat |= 0x05; + + int read_offset = read_offset_base + m_secoffs; + flop[read_offset] = data; + + if (m_secoffs == 0) + { + printf("writing sector %d offset %d (from disk image at %04x) (cur track %02x cur side %02x cur sector %02x)\n", m_flopsec, m_secoffs, read_offset, m_curtrack, side, m_flopsec); + } + + m_secoffs++; + + if (m_secoffs == sector_size) + { + //printf("finished sector read\n"); + m_flopstat &= ~0x05; + + m_secoffs = 0; + m_flopsec++; + } + } + } + +} + +WRITE8_MEMBER(cedar_magnet_flop_device::write) +{ + switch (offset & 3) + { + case 0x00:port60_w(space, offset, data);break; + // case 0x01:port61_w(space, offset, data);break; + case 0x02:port62_w(space, offset, data);break; + case 0x03:port63_w(space, offset, data);break; + default:break; + } +} + +READ8_MEMBER(cedar_magnet_flop_device::read) +{ + switch (offset & 3) + { + case 0x00: return port60_r(space, offset); + case 0x01: return port61_r(space, offset); + //case 0x02: return port62_r(space, offset); + case 0x03: return port63_r(space, offset); + default: return 0x00; + } + + return 0x00; +} \ No newline at end of file diff --git a/src/mame/drivers/cedar_magnet_flop.h b/src/mame/drivers/cedar_magnet_flop.h new file mode 100644 index 00000000000..7ff44b40947 --- /dev/null +++ b/src/mame/drivers/cedar_magnet_flop.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#pragma once + +#ifndef CEDAR_MAGNET_FLOP_DEF +#define CEDAR_MAGNET_FLOP_DEF + +extern const device_type CEDAR_MAGNET_FLOP; + +#define MCFG_CEDAR_MAGNET_FLOP_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, CEDAR_MAGNET_FLOP, 0) + +#include "machine/nvram.h" + +class cedar_magnet_flop_device : public device_t +{ +public: + // construction/destruction + cedar_magnet_flop_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + UINT8 m_flopdat; + UINT8 m_flopcmd; + UINT8 m_flopsec; + UINT8 m_flopstat; + UINT8 m_floptrk; + + UINT8 m_curtrack; + int m_secoffs; + + DECLARE_READ8_MEMBER(port60_r); + DECLARE_READ8_MEMBER(port61_r); + DECLARE_READ8_MEMBER(port63_r); + + DECLARE_WRITE8_MEMBER(port60_w); + DECLARE_WRITE8_MEMBER(port62_w); + DECLARE_WRITE8_MEMBER(port63_w); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + +protected: + virtual machine_config_constructor device_mconfig_additions() const override; + virtual void device_start() override; + virtual void device_reset() override; +private: +}; + +#endif diff --git a/src/mame/drivers/cedar_magnet_plane.cpp b/src/mame/drivers/cedar_magnet_plane.cpp new file mode 100644 index 00000000000..ffa92d03643 --- /dev/null +++ b/src/mame/drivers/cedar_magnet_plane.cpp @@ -0,0 +1,162 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + + +#include "emu.h" +#include "cedar_magnet_plane.h" + + +extern const device_type CEDAR_MAGNET_PLANE = &device_creator; + + +cedar_magnet_plane_device::cedar_magnet_plane_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cedar_magnet_board_device(mconfig, CEDAR_MAGNET_PLANE, "Cedar Plane", tag, owner, clock, "cedmag_plane", __FILE__) +{ +} + + + +static ADDRESS_MAP_START( cedar_magnet_plane_map, AS_PROGRAM, 8, cedar_magnet_plane_device ) + AM_RANGE(0x0000, 0xffff) AM_RAM AM_SHARE("ram") +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cedar_magnet_plane_io, AS_IO, 8, cedar_magnet_plane_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + + AM_RANGE(0xc0, 0xc3) AM_DEVREADWRITE("z80pio0", z80pio_device, read_alt, write_alt) + AM_RANGE(0xc4, 0xc7) AM_DEVREADWRITE("z80pio1", z80pio_device, read_alt, write_alt) + + AM_RANGE(0xcc, 0xcc) AM_WRITE(plane_portcc_w) + AM_RANGE(0xcd, 0xcd) AM_WRITE(plane_portcd_w) + AM_RANGE(0xce, 0xce) AM_WRITE(plane_portce_w) + AM_RANGE(0xcf, 0xcf) AM_WRITE(plane_portcf_w) + +ADDRESS_MAP_END + + + + +WRITE8_MEMBER(cedar_magnet_plane_device::plane_portcc_w) +{ + m_framebuffer[((m_curline&0xff)*0x100)+(m_lineoffset&0xff)] = data; + + // counters simply wrap when they reach the maximum, don't move onto next row/colummn (confirmed by xain) + if (m_pio0_pa_data&0x01) + { + m_lineoffset++; + } + else + { + m_curline++; + } +} + +WRITE8_MEMBER(cedar_magnet_plane_device::plane_portcd_w) +{ + m_lineoffset = data; +} + +WRITE8_MEMBER(cedar_magnet_plane_device::plane_portce_w) +{ + m_curline = data; + +} + +WRITE8_MEMBER(cedar_magnet_plane_device::plane_portcf_w) +{ + // does it have a meaning or is it just some kind of watchdog? + m_cf_data = data; +} + +static MACHINE_CONFIG_FRAGMENT( cedar_magnet_plane ) + MCFG_CPU_ADD("planecpu", Z80,4000000) + MCFG_CPU_PROGRAM_MAP(cedar_magnet_plane_map) + MCFG_CPU_IO_MAP(cedar_magnet_plane_io) + MCFG_CPU_VBLANK_INT_DRIVER(":screen", cedar_magnet_board_device, irq) + + MCFG_DEVICE_ADD("z80pio0", Z80PIO, 4000000/2) +// MCFG_Z80PIO_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0)) + MCFG_Z80PIO_IN_PA_CB(READ8(cedar_magnet_plane_device, pio0_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(cedar_magnet_plane_device, pio0_pa_w)) +// MCFG_Z80PIO_IN_PB_CB(READ8(cedar_magnet_plane_device, pio0_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(cedar_magnet_plane_device, pio0_pb_w)) + + MCFG_DEVICE_ADD("z80pio1", Z80PIO, 4000000/2) +// MCFG_Z80PIO_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0)) +// MCFG_Z80PIO_IN_PA_CB(READ8(cedar_magnet_plane_device, pio1_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(cedar_magnet_plane_device, pio1_pa_w)) +// MCFG_Z80PIO_IN_PB_CB(READ8(cedar_magnet_plane_device, pio1_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(cedar_magnet_plane_device, pio1_pb_w)) +MACHINE_CONFIG_END + + +READ8_MEMBER(cedar_magnet_plane_device::pio0_pa_r) +{ +// this is read +// logerror("%s: pio0_pa_r\n", machine().describe_context()); + return 0x00; +} + + +WRITE8_MEMBER(cedar_magnet_plane_device::pio0_pa_w) +{ + m_pio0_pa_data = data; + + // 7ex- 321d + // + // e = video enable + // d = draw direction + // x = done? gets set at end of each frame at least, but unlike video enable, also when video shouldn't be enabled + // 7 = always set? + // 321 = always set after startup? +} + +WRITE8_MEMBER(cedar_magnet_plane_device::pio0_pb_w) +{ + m_pio0_pb_data = data; +} + +WRITE8_MEMBER(cedar_magnet_plane_device::pio1_pa_w) +{ + m_scrollx = data; +} + +WRITE8_MEMBER(cedar_magnet_plane_device::pio1_pb_w) +{ + m_scrolly = data; +} + +machine_config_constructor cedar_magnet_plane_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cedar_magnet_plane ); +} + +void cedar_magnet_plane_device::device_start() +{ + m_cpu = subdevice("planecpu"); + m_ram = (UINT8*)memshare("ram")->ptr(); + save_item(NAME(m_framebuffer)); +} + +UINT32 cedar_magnet_plane_device::draw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int palbase) +{ + int count = 0; + + if (!(m_pio0_pa_data & 0x40)) + return 0; + + for (int y = 0;y < 256;y++) + { + UINT16 *dst = &bitmap.pix16((y-m_scrolly)&0xff); + + for (int x = 0; x < 256;x++) + { + UINT8 pix = m_framebuffer[count]; + count++; + + if (pix) dst[(x-m_scrollx)&0xff] = pix + palbase*0x100; + } + } + + return 0; +} diff --git a/src/mame/drivers/cedar_magnet_plane.h b/src/mame/drivers/cedar_magnet_plane.h new file mode 100644 index 00000000000..fe5c481aa7d --- /dev/null +++ b/src/mame/drivers/cedar_magnet_plane.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#pragma once + +#ifndef CEDAR_MAGNET_PLANE_DEF +#define CEDAR_MAGNET_PLANE_DEF + +#include "cedar_magnet_board.h" + +extern const device_type CEDAR_MAGNET_PLANE; + +#define MCFG_CEDAR_MAGNET_PLANE_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, CEDAR_MAGNET_PLANE, 0) + + +class cedar_magnet_plane_device : public cedar_magnet_board_device +{ +public: + // construction/destruction + cedar_magnet_plane_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(pio0_pa_r); + DECLARE_WRITE8_MEMBER(pio0_pa_w); +// DECLARE_READ8_MEMBER(pio0_pb_r); + DECLARE_WRITE8_MEMBER(pio0_pb_w); + +// DECLARE_READ8_MEMBER(pio1_pa_r); + DECLARE_WRITE8_MEMBER(pio1_pa_w); +// DECLARE_READ8_MEMBER(pio1_pb_r); + DECLARE_WRITE8_MEMBER(pio1_pb_w); + + DECLARE_WRITE8_MEMBER(plane_portcc_w); + DECLARE_WRITE8_MEMBER(plane_portcd_w); + DECLARE_WRITE8_MEMBER(plane_portce_w); + DECLARE_WRITE8_MEMBER(plane_portcf_w); + + UINT8 m_framebuffer[0x10000]; + int m_curline; + int m_lineoffset; + + UINT8 m_pio0_pa_data; + UINT8 m_pio0_pb_data; + UINT8 m_scrollx; + UINT8 m_scrolly; + int m_direction; + + UINT8 m_cd_data; + UINT8 m_cf_data; + UINT32 draw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int palbase); +protected: + virtual machine_config_constructor device_mconfig_additions() const override; + virtual void device_start() override; +// virtual void device_reset() override; + +private: +}; + +#endif diff --git a/src/mame/drivers/cedar_magnet_sound.cpp b/src/mame/drivers/cedar_magnet_sound.cpp new file mode 100644 index 00000000000..a155762f13c --- /dev/null +++ b/src/mame/drivers/cedar_magnet_sound.cpp @@ -0,0 +1,168 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +/* + THIS IMPLEMENTATION IS ENTIRELY INCORRECT AND SHOULD NOT BE TRUSTED! +*/ + +#include "emu.h" +#include "cedar_magnet_sound.h" + + +extern const device_type CEDAR_MAGNET_SOUND = &device_creator; + + +cedar_magnet_sound_device::cedar_magnet_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cedar_magnet_board_device(mconfig, CEDAR_MAGNET_SOUND, "Cedar Sound", tag, owner, clock, "cedmag_sound", __FILE__), + m_ctc0(*this, "ctc0"), + m_ctc1(*this, "ctc1") +{ +} + + +READ8_MEMBER(cedar_magnet_sound_device::top_port14_r) +{ +// UINT8 ret = m_command; +// m_command = 0; + return rand(); +} + +void cedar_magnet_sound_device::write_command(UINT8 data) +{ + m_command = data; + m_cpu->set_input_line(0, HOLD_LINE); +} + + +static ADDRESS_MAP_START( cedar_magnet_sound_map, AS_PROGRAM, 8, cedar_magnet_sound_device ) + AM_RANGE(0x0000, 0xffff) AM_RAM AM_SHARE("ram") +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cedar_magnet_sound_io, AS_IO, 8, cedar_magnet_sound_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + + AM_RANGE(0x00, 0x03) AM_DEVREADWRITE("ctc0", z80ctc_device, read, write) + AM_RANGE(0x04, 0x07) AM_DEVREADWRITE("ctc1", z80ctc_device, read, write) + + AM_RANGE(0x0c, 0x0c) AM_DEVWRITE("aysnd0", ay8910_device, address_w) + AM_RANGE(0x0d, 0x0d) AM_DEVWRITE("aysnd0", ay8910_device, data_w) + + AM_RANGE(0x10, 0x10) AM_DEVWRITE("aysnd1", ay8910_device, address_w) + AM_RANGE(0x11, 0x11) AM_DEVWRITE("aysnd1", ay8910_device, data_w) + + AM_RANGE(0x14, 0x14) AM_READ(top_port14_r) + +ADDRESS_MAP_END + + +WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc0_z0_w) +{ +// printf("USED ctc0_z0_w %d\n", state); +} + +WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc0_z1_w) +{ +// printf("USED ctc0_z1_w %d\n", state); +} + + +// I don't think any of the below are used + +WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc1_z0_w) +{ + printf("ctc1_z0_w %d\n", state); +} + +WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc1_z1_w) +{ + printf("ctc1_z1_w %d\n", state); +} + +WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc1_z2_w) +{ + printf("ctc1_z2_w %d\n", state); +} + +WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc0_z2_w) +{ + printf("ctc0_z2_w %d\n", state); +} + +WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc0_int_w) +{ + //printf("ctc0_int_w %d\n", state); +} + +WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc1_int_w) +{ +/* + switch (rand()&0x1) + { + case 0x00: + m_ctc0->trg0(rand()&1); + break; + case 0x01: + m_ctc0->trg1(rand()&1); + break; + } +*/ +} + +#if 0 +static const z80_daisy_config daisy_chain[] = +{ + { "ctc1" }, + { "ctc0" }, + { nullptr } +}; +#endif + +static MACHINE_CONFIG_FRAGMENT( cedar_magnet_sound ) + MCFG_CPU_ADD("topcpu", Z80,4000000) + MCFG_CPU_PROGRAM_MAP(cedar_magnet_sound_map) + MCFG_CPU_IO_MAP(cedar_magnet_sound_io) +// MCFG_Z80_DAISY_CHAIN(daisy_chain) + + MCFG_DEVICE_ADD("ctc0", Z80CTC, 4000000/8 ) + MCFG_Z80CTC_INTR_CB(WRITELINE(cedar_magnet_sound_device, ctc0_int_w)) + MCFG_Z80CTC_ZC0_CB(WRITELINE(cedar_magnet_sound_device, ctc0_z0_w)) + MCFG_Z80CTC_ZC1_CB(WRITELINE(cedar_magnet_sound_device, ctc0_z1_w)) + MCFG_Z80CTC_ZC2_CB(WRITELINE(cedar_magnet_sound_device, ctc0_z2_w)) + + MCFG_DEVICE_ADD("ctc1", Z80CTC, 4000000/8 ) + MCFG_Z80CTC_INTR_CB(INPUTLINE("topcpu", INPUT_LINE_IRQ0)) +// MCFG_Z80CTC_INTR_CB(DEVWRITELINE("ctc0", z80ctc_device, trg0)) + MCFG_Z80CTC_INTR_CB(WRITELINE(cedar_magnet_sound_device, ctc1_int_w)) + MCFG_Z80CTC_ZC0_CB(WRITELINE(cedar_magnet_sound_device, ctc1_z0_w)) + MCFG_Z80CTC_ZC1_CB(WRITELINE(cedar_magnet_sound_device, ctc1_z1_w)) + MCFG_Z80CTC_ZC2_CB(WRITELINE(cedar_magnet_sound_device, ctc1_z2_w)) + + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("aysnd0", AY8910, 4000000/2) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.5) + + MCFG_SOUND_ADD("aysnd1", AY8910, 4000000/2) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.5) + + MCFG_SOUND_ADD("adpcm", MSM5205, 4000000/16) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) + +MACHINE_CONFIG_END + +machine_config_constructor cedar_magnet_sound_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cedar_magnet_sound ); +} + +void cedar_magnet_sound_device::device_start() +{ + m_cpu = subdevice("topcpu"); + m_ram = (UINT8*)memshare("ram")->ptr(); +} + +void cedar_magnet_sound_device::device_reset() +{ + m_command = 0; + cedar_magnet_board_device::device_reset(); +} diff --git a/src/mame/drivers/cedar_magnet_sound.h b/src/mame/drivers/cedar_magnet_sound.h new file mode 100644 index 00000000000..909482ab059 --- /dev/null +++ b/src/mame/drivers/cedar_magnet_sound.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#pragma once + +#ifndef CEDAR_MAGNET_SOUND_DEF +#define CEDAR_MAGNET_SOUND_DEF + +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "machine/z80ctc.h" +#include "sound/ay8910.h" +#include "sound/msm5205.h" +#include "cedar_magnet_board.h" + +extern const device_type CEDAR_MAGNET_SOUND; + +#define MCFG_CEDAR_MAGNET_SOUND_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, CEDAR_MAGNET_SOUND, 0) + + +class cedar_magnet_sound_device : public cedar_magnet_board_device +{ +public: + // construction/destruction + cedar_magnet_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + required_device m_ctc0; + required_device m_ctc1; + + DECLARE_READ8_MEMBER(top_port14_r); + + void write_command(UINT8 data); + UINT8 m_command; + + DECLARE_WRITE_LINE_MEMBER(ctc1_z0_w); + DECLARE_WRITE_LINE_MEMBER(ctc1_z1_w); + DECLARE_WRITE_LINE_MEMBER(ctc1_z2_w); + DECLARE_WRITE_LINE_MEMBER(ctc0_z0_w); + DECLARE_WRITE_LINE_MEMBER(ctc0_z1_w); + DECLARE_WRITE_LINE_MEMBER(ctc0_z2_w); + DECLARE_WRITE_LINE_MEMBER(ctc0_int_w); + DECLARE_WRITE_LINE_MEMBER(ctc1_int_w); + +protected: + virtual machine_config_constructor device_mconfig_additions() const override; + virtual void device_start() override; + virtual void device_reset() override; + +private: +}; + +#endif diff --git a/src/mame/drivers/cedar_magnet_sprite.cpp b/src/mame/drivers/cedar_magnet_sprite.cpp new file mode 100644 index 00000000000..e79b83faf84 --- /dev/null +++ b/src/mame/drivers/cedar_magnet_sprite.cpp @@ -0,0 +1,336 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +/* + + todo: sometimes sprites get left onscreen (xain) + +*/ +#include "emu.h" +#include "cedar_magnet_sprite.h" + + +extern const device_type CEDAR_MAGNET_SPRITE = &device_creator; + + +cedar_magnet_sprite_device::cedar_magnet_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cedar_magnet_board_device(mconfig, CEDAR_MAGNET_SPRITE, "Cedar Sprite", tag, owner, clock, "cedmag_sprite", __FILE__), + m_sprite_ram_bankdev(*this, "sp_sub_ram"), + m_pio0(*this, "z80pio0"), + m_pio1(*this, "z80pio1"), + m_pio2(*this, "z80pio2") +{ +} + +static ADDRESS_MAP_START( cedar_magnet_sprite_sub_ram_map, AS_PROGRAM, 8, cedar_magnet_sprite_device ) +// these are 8x SIEMENS HYB 41256-15 AA - 262,144 bit DRAM (32kbytes) +// these are on the sprite board memory sub-board + AM_RANGE(0x00000, 0x3ffff) AM_RAM AM_SHARE("ram") +ADDRESS_MAP_END + +READ8_MEMBER(cedar_magnet_sprite_device::exzisus_hack_r) +{ + //printf("exzisus_hack_r\n"); + int pc = m_cpu->pc(); + + // exzisus has startup code outside of the first 0x400 bytes + // but the main cpu only transfers 0x400 bytes of the code to the other banks?! + if ((pc >= 0x3e0) && (pc <= 0x800)) + { + return m_ram[0x400 + offset]; + } + else + { + return m_ram[0x400 + offset + (pio2_pb_data & 0x3)*0x10000]; + } + +} + + +static ADDRESS_MAP_START( cedar_magnet_sprite_map, AS_PROGRAM, 8, cedar_magnet_sprite_device ) + AM_RANGE(0x00400, 0x007ff) AM_READ(exzisus_hack_r) + + AM_RANGE(0x00000, 0x0ffff) AM_DEVICE("sp_sub_ram", address_map_bank_device, amap8) + +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cedar_magnet_sprite_io, AS_IO, 8, cedar_magnet_sprite_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + + AM_RANGE(0xc0, 0xc3) AM_DEVREADWRITE("z80pio0", z80pio_device, read_alt, write_alt) + AM_RANGE(0xc4, 0xc7) AM_DEVREADWRITE("z80pio1", z80pio_device, read_alt, write_alt) + AM_RANGE(0xc8, 0xcb) AM_DEVREADWRITE("z80pio2", z80pio_device, read_alt, write_alt) + + AM_RANGE(0x80, 0x80) AM_WRITE(sprite_port80_w) + AM_RANGE(0x84, 0x84) AM_WRITE(sprite_port84_w) + + AM_RANGE(0x88, 0x88) AM_WRITE(sprite_port88_w) // increasing values // upper address? + + AM_RANGE(0x8c, 0x8c) AM_WRITE(sprite_port8c_w) // written after 88 (possible data upload?) + + AM_RANGE(0x9c, 0x9c) AM_WRITE(sprite_port9c_w) // ? + +ADDRESS_MAP_END + +void cedar_magnet_sprite_device::do_blit() +{ +// printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); +// printf("~~~~~~~~~~~~~~~~~ drawing sprite with x:%02x y:%02x code:%04x size:%02x unk:%02x\n", m_loweraddr, m_upperaddr, (m_spritecodehigh << 8) | m_spritecodelow, m_spritesize, pio0_pb_data); +// printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); + + int ysize; + int xsize; + int erase = 0; + + // bit 0x80 is always set + if ((m_spritesize & 0x7f) == 0x00) + ysize = xsize = 8; + + if ((m_spritesize & 0x7f) == 0x01) + ysize = xsize = 16; + + if ((m_spritesize & 0x7f) == 0x02) + ysize = xsize = 32; + + if ((m_spritesize & 0x7f) == 0x03) + ysize = xsize = 64; + + // m_spritesize + // pio0_pb_data + + + int source = (m_spritecodehigh << 8) | m_spritecodelow; + + if (source == 0) + erase = 1; + + source &= ~0x3f; + + for (int y = 0;y < ysize;y++) + { + for (int x = 0;x < xsize;x++) + { + int xpos = (m_loweraddr + x); + int ypos = (m_upperaddr + y); + + UINT8 data = m_ram[source + ((m_uppersprite & 0x3) * 0x10000)]; + + if (!(pio0_pb_data & 0x02)) + data = rand(); + + source++; + + xpos &= 0xff; + + // without this some sprites incorrectly wraparound on the volcano table. + if (!erase) + { + if (!(pio0_pb_data & 0x40)) + { + if (xpos >= 0xff-64) + continue; + } + else + { + if (xpos < 64) + continue; + } + } + + //if ((ypos >= 0) && (ypos < 0x100)) + ypos &= 0xff; + + { + int offset = (ypos * 256) + xpos; + + if (erase == 1) + { + m_framebuffer[offset] = 0; + } + else + { + if (data) m_framebuffer[offset] = data; + } + } + } + } +} + +WRITE8_MEMBER(cedar_magnet_sprite_device::sprite_port80_w) +{ + m_spritecodelow = data; +// printf("%s:sprite numlow / trigger %02x\n", machine().describe_context(), data); + + do_blit(); +} + +WRITE8_MEMBER(cedar_magnet_sprite_device::sprite_port84_w) +{ + m_spritecodehigh = data; + m_high_write = 1; +// printf("%s:sprite numhigh %02x\n", machine().describe_context(), data); +} + +WRITE8_MEMBER(cedar_magnet_sprite_device::sprite_port88_w) +{ +// frequent +// printf("%s:sprite_y_coordinate %02x\n", machine().describe_context(), data); + m_upperaddr = data; +} + +WRITE8_MEMBER(cedar_magnet_sprite_device::pio2_pa_w) +{ +// frequent +// printf("%s:sprite_x_coordinate %02x\n", machine().describe_context(), data); + m_loweraddr = data; +} + +WRITE8_MEMBER(cedar_magnet_sprite_device::sprite_port8c_w) +{ + int address = (m_upperaddr << 8) | m_loweraddr; + m_framebuffer[address] = data; + if (data!=0x00) printf("sprite_port8c_w write %04x %02x\n", address, data); +} + +// possible watchdog? +WRITE8_MEMBER(cedar_magnet_sprite_device::sprite_port9c_w) +{ +// printf("%s:sprite_port9c_w %02x\n", machine().describe_context(), data); +} + +static MACHINE_CONFIG_FRAGMENT( cedar_magnet_sprite ) + MCFG_CPU_ADD("spritecpu", Z80,4000000) + MCFG_CPU_PROGRAM_MAP(cedar_magnet_sprite_map) + MCFG_CPU_IO_MAP(cedar_magnet_sprite_io) + MCFG_CPU_VBLANK_INT_DRIVER(":screen", cedar_magnet_board_device, irq) + + MCFG_DEVICE_ADD("z80pio0", Z80PIO, 4000000/2) +// MCFG_Z80PIO_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0)) + MCFG_Z80PIO_IN_PA_CB(READ8(cedar_magnet_sprite_device, pio0_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(cedar_magnet_sprite_device, pio0_pa_w)) +// MCFG_Z80PIO_IN_PB_CB(READ8(cedar_magnet_sprite_device, pio0_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(cedar_magnet_sprite_device, pio0_pb_w)) + + MCFG_DEVICE_ADD("z80pio1", Z80PIO, 4000000/2) +// MCFG_Z80PIO_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0)) +// MCFG_Z80PIO_IN_PA_CB(READ8(cedar_magnet_sprite_device, pio1_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(cedar_magnet_sprite_device, pio1_pa_w)) +// MCFG_Z80PIO_IN_PB_CB(READ8(cedar_magnet_sprite_device, pio1_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(cedar_magnet_sprite_device, pio1_pb_w)) + + MCFG_DEVICE_ADD("z80pio2", Z80PIO, 4000000/2) +// MCFG_Z80PIO_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0)) +// MCFG_Z80PIO_IN_PA_CB(READ8(cedar_magnet_sprite_device, pio2_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(cedar_magnet_sprite_device, pio2_pa_w)) +// MCFG_Z80PIO_IN_PB_CB(READ8(cedar_magnet_sprite_device, pio2_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(cedar_magnet_sprite_device, pio2_pb_w)) + + MCFG_DEVICE_ADD("sp_sub_ram", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(cedar_magnet_sprite_sub_ram_map) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_LITTLE) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(8) + MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(18) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x10000) +MACHINE_CONFIG_END + + +READ8_MEMBER(cedar_magnet_sprite_device::pio0_pa_r) +{ +// actually read +// printf("%s: pio0_pa_r\n", machine().describe_context()); + return 0x00; +} + + + +WRITE8_MEMBER(cedar_magnet_sprite_device::pio0_pa_w) +{ + m_spritesize = data; +} + +WRITE8_MEMBER(cedar_magnet_sprite_device::pio0_pb_w) +{ + pio0_pb_data = data; + //printf("%s: pio0_pb_w %02x\n", machine().describe_context(), data); +} + +WRITE8_MEMBER(cedar_magnet_sprite_device::pio1_pa_w) +{ + //printf("%s: pio1_pa_w %02x\n", machine().describe_context(), data); +} + +WRITE8_MEMBER(cedar_magnet_sprite_device::pio1_pb_w) +{ + //printf("%s: pio1_pb_w %02x\n", machine().describe_context(), data); +} + + +WRITE8_MEMBER(cedar_magnet_sprite_device::pio2_pb_w) +{ + // this feels like a hack + // the game writes here when creating the sprite list so that it can access the correct gfd data + // however the actual LIST data is always in bank 0 (it can't be in any other bank, those areas are occupied by actual gfx) + if (m_high_write) + { + m_uppersprite = data & 0x03; + m_high_write = 0; + return; + + } + + pio2_pb_data = data; + //printf("%s: ******************************************* BANK? **** pio2_pb_w %02x\n", machine().describe_context(), data); + // yes, it ends up banking the ram right out from under itself during startup execution... + // during this time the main cpu is waiting in a loop, after which it copies the startup code again, and reboots it. + m_sprite_ram_bankdev->set_bank(data & 0x03); +} + + +machine_config_constructor cedar_magnet_sprite_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cedar_magnet_sprite ); +} + +void cedar_magnet_sprite_device::device_start() +{ + m_cpu = subdevice("spritecpu"); + m_ram = (UINT8*)memshare("ram")->ptr(); +} + + + +void cedar_magnet_sprite_device::device_reset() +{ + halt_assert(); + m_sprite_ram_bankdev->set_bank(0); + pio2_pb_data = 0x00; + m_spritesize = 0xff; +} + +UINT32 cedar_magnet_sprite_device::draw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int palbase) +{ +// printf("-----------------------------------------------------------------------------------------------------------\n"); +// printf("--------------------------------------------- FRAME -------------------------------------------------------\n"); +// printf("-----------------------------------------------------------------------------------------------------------\n"); + + UINT8* mem = m_framebuffer; + int count = 0; + +// if (!(m_m_spritesize & 0x40)) +// return 0; + + for (int y = 0;y < 256;y++) + { + UINT16 *dst = &bitmap.pix16((y)&0xff); + + for (int x = 0; x < 256;x++) + { + UINT8 pix = mem[count]; + count++; + + if (pix) dst[(x)&0xff] = pix + palbase*0x100; + } + } + + return 0; +} diff --git a/src/mame/drivers/cedar_magnet_sprite.h b/src/mame/drivers/cedar_magnet_sprite.h new file mode 100644 index 00000000000..52eeb88c042 --- /dev/null +++ b/src/mame/drivers/cedar_magnet_sprite.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#pragma once + +#ifndef CEDAR_MAGNET_SPRITE_DEF +#define CEDAR_MAGNET_SPRITE_DEF + +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "machine/z80pio.h" +#include "machine/bankdev.h" +#include "cedar_magnet_board.h" + +extern const device_type CEDAR_MAGNET_SPRITE; + +#define MCFG_CEDAR_MAGNET_SPRITE_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, CEDAR_MAGNET_SPRITE, 0) + + +class cedar_magnet_sprite_device : public cedar_magnet_board_device +{ +public: + // construction/destruction + cedar_magnet_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + UINT8 m_framebuffer[0x10000]; + UINT8 pio2_pb_data; + + required_device m_sprite_ram_bankdev; + + DECLARE_READ8_MEMBER(pio0_pa_r); + DECLARE_WRITE8_MEMBER(pio0_pa_w); +// DECLARE_READ8_MEMBER(pio0_pb_r); + DECLARE_WRITE8_MEMBER(pio0_pb_w); + +// DECLARE_READ8_MEMBER(pio1_pa_r); + DECLARE_WRITE8_MEMBER(pio1_pa_w); +// DECLARE_READ8_MEMBER(pio1_pb_r); + DECLARE_WRITE8_MEMBER(pio1_pb_w); + +// DECLARE_READ8_MEMBER(pio2_pa_r); + DECLARE_WRITE8_MEMBER(pio2_pa_w); +// DECLARE_READ8_MEMBER(pio2_pb_r); + DECLARE_WRITE8_MEMBER(pio2_pb_w); + + DECLARE_WRITE8_MEMBER(sprite_port80_w); + DECLARE_WRITE8_MEMBER(sprite_port84_w); + DECLARE_WRITE8_MEMBER(sprite_port88_w); + DECLARE_WRITE8_MEMBER(sprite_port8c_w); + DECLARE_WRITE8_MEMBER(sprite_port9c_w); + + DECLARE_READ8_MEMBER(exzisus_hack_r); + + UINT8 m_upperaddr; + UINT8 m_loweraddr; + + void do_blit(); + + UINT8 m_spritesize; + UINT8 pio0_pb_data; + UINT8 m_spritecodelow; + UINT8 m_spritecodehigh; + + int m_high_write; + UINT8 m_uppersprite; + + INTERRUPT_GEN_MEMBER(irq); + + required_device m_pio0; + required_device m_pio1; + required_device m_pio2; + + UINT32 draw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int palbase); +protected: + virtual machine_config_constructor device_mconfig_additions() const override; + virtual void device_start() override; + virtual void device_reset() override; + +private: +}; + +#endif diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 9bb57b3d766..1c03938a64c 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -9272,6 +9272,12 @@ quizard4 // (c) TAB Austria 1998 quizard4_40 // (c) TAB Austria 1997 quizard4_41 // (c) TAB Austria 1998 +@source:cedar_magnet.cpp +cedmag +mag_time +mag_exzi +mag_xain + @source:centiped.cpp bullsdrt // (c) 1985 Shinkai caterplr // (bootleg) -- cgit v1.2.3