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.
This commit is contained in:
David Haywood 2016-10-22 09:37:10 +01:00
parent 5df1518708
commit a060de5062
14 changed files with 2221 additions and 0 deletions

View File

@ -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",

View File

@ -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

View File

@ -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<address_map_bank_device> m_bank0;
required_device<address_map_bank_device> m_sub_ram_bankdev;
required_device<address_map_bank_device> m_sub_pal_bankdev;
required_shared_ptr<UINT8> m_ram0;
required_shared_ptr<UINT8> m_pal_r;
required_shared_ptr<UINT8> m_pal_g;
required_shared_ptr<UINT8> m_pal_b;
required_device<z80pio_device> m_ic48_pio;
required_device<z80pio_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<palette_device> m_palette;
required_device<cpu_device> m_maincpu;
required_device<cedar_magnet_sound_device> m_cedsound;
required_device<cedar_magnet_plane_device> m_cedplane0;
required_device<cedar_magnet_plane_device> m_cedplane1;
required_device<cedar_magnet_sprite_device> m_cedsprite;
DECLARE_DRIVER_INIT(mag_time);
DECLARE_DRIVER_INIT(mag_xain);
DECLARE_DRIVER_INIT(mag_exzi);
};

View File

@ -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::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();
}

View File

@ -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

View File

@ -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::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<nvram_device>("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;
}

View File

@ -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

View File

@ -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::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<z80_device>("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;
}

View File

@ -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

View File

@ -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::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<z80_device>("topcpu");
m_ram = (UINT8*)memshare("ram")->ptr();
}
void cedar_magnet_sound_device::device_reset()
{
m_command = 0;
cedar_magnet_board_device::device_reset();
}

View File

@ -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<z80ctc_device> m_ctc0;
required_device<z80ctc_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

View File

@ -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::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<z80_device>("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;
}

View File

@ -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<address_map_bank_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<z80pio_device> m_pio0;
required_device<z80pio_device> m_pio1;
required_device<z80pio_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

View File

@ -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)