summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/cedar_magnet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/cedar_magnet.cpp')
-rw-r--r--src/mame/drivers/cedar_magnet.cpp796
1 files changed, 796 insertions, 0 deletions
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