mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
new WORKING
Unisonic Champion 2711 [David Viens]
This commit is contained in:
parent
2751e76c83
commit
bc6c55fe47
54
hash/unichamp.xml
Normal file
54
hash/unichamp.xml
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
|
||||
|
||||
<softwarelist name="unichamp" description="Unisonic Champion 2711 cartridges">
|
||||
|
||||
<software name="pac-02">
|
||||
<description>Professional Poker Games</description>
|
||||
<year>1977</year>
|
||||
<publisher>Unisonic</publisher>
|
||||
<info name="serial" value="PAC-02"/>
|
||||
<part name="cart" interface="unichamp_cart">
|
||||
<dataarea name="rom" size="0x1000">
|
||||
<rom name="pac-02.bin" size="0x1000" crc="fe3213be" sha1="5b9c407fe86865f3454d4be824a7f2bf53478f73" offset="0x0000"/>
|
||||
</dataarea>
|
||||
</part>
|
||||
</software>
|
||||
|
||||
<software name="pac-03">
|
||||
<description>Assorted Family Fun</description>
|
||||
<year>1977</year>
|
||||
<publisher>Unisonic</publisher>
|
||||
<info name="serial" value="PAC-03"/>
|
||||
<part name="cart" interface="unichamp_cart">
|
||||
<dataarea name="rom" size="0x1000">
|
||||
<rom name="pac-03.bin" size="0x1000" crc="f81f04bd" sha1="82e2a0fda1787d5835c457ee5745b0db0cebe079" offset="0x0000"/>
|
||||
</dataarea>
|
||||
</part>
|
||||
</software>
|
||||
|
||||
<software name="pac-04">
|
||||
<description>Family Card Games</description>
|
||||
<year>1977</year>
|
||||
<publisher>Unisonic</publisher>
|
||||
<info name="serial" value="PAC-04"/>
|
||||
<part name="cart" interface="unichamp_cart">
|
||||
<dataarea name="rom" size="0x1000">
|
||||
<rom name="pac-04.bin" size="0x1000" crc="cac09841" sha1="bc9db83f26ed0810938156db6b104b4576754225" offset="0x0000"/>
|
||||
</dataarea>
|
||||
</part>
|
||||
</software>
|
||||
|
||||
<software name="pac-05">
|
||||
<description>Math</description>
|
||||
<year>1977</year>
|
||||
<publisher>Unisonic</publisher>
|
||||
<info name="serial" value="PAC-05"/>
|
||||
<part name="cart" interface="unichamp_cart">
|
||||
<dataarea name="rom" size="0x1000">
|
||||
<rom name="pac-05.bin" size="0x1000" crc="d54a6090" sha1="e85593096f43dcf14b08fd2c9fda277008a8df8b" offset="0x0000"/>
|
||||
</dataarea>
|
||||
</part>
|
||||
</software>
|
||||
|
||||
</softwarelist>
|
@ -849,6 +849,7 @@ function linkProjects_mame_mess(_target, _subtarget)
|
||||
"trs",
|
||||
"ultimachine",
|
||||
"ultratec",
|
||||
"unisonic",
|
||||
"unisys",
|
||||
"veb",
|
||||
"vidbrain",
|
||||
@ -2481,6 +2482,14 @@ files {
|
||||
MAME_DIR .. "src/mame/drivers/minicom.c",
|
||||
}
|
||||
|
||||
createMESSProjects(_target, _subtarget, "unisonic")
|
||||
files {
|
||||
MAME_DIR .. "src/mame/drivers/unichamp.c",
|
||||
MAME_DIR .. "src/mame/video/gic.c",
|
||||
MAME_DIR .. "src/mame/video/gic.c",
|
||||
}
|
||||
|
||||
|
||||
createMESSProjects(_target, _subtarget, "unisys")
|
||||
files {
|
||||
MAME_DIR .. "src/mame/drivers/univac.c",
|
||||
|
277
src/mame/drivers/unichamp.c
Normal file
277
src/mame/drivers/unichamp.c
Normal file
@ -0,0 +1,277 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:David Viens
|
||||
/************************************************************************
|
||||
* Unisonic Champion 2711 (late 1977 based on part dates)
|
||||
*
|
||||
* Driver from plgDavid (David Viens)
|
||||
*
|
||||
* Thanks to Sylvain De Chantal (Sly D.C.) for the 2 test units,
|
||||
* carts and FAQ: http://www.ccjvq.com/slydc/index/faq/2711
|
||||
*
|
||||
* Thanks to Paul Robson for the GIC font rom.
|
||||
* (http://worstconsole.blogspot.ca/2012/12/the-worstconsoleever.html)
|
||||
* Note a spare dead GIC has been given to Lord Nightmare and should be sent for decap!
|
||||
*
|
||||
* The Unisonc Champion is the only known GI "Gimini Mid-Range 8950 Programmable Game Set"
|
||||
* to ever reach the market, and only in limited quantities (aprox 500 units ever built)
|
||||
*
|
||||
* Architecture:
|
||||
* Master IC : AY-3-8800-1 Graphics Interface (A.K.A. GIC, 40 pin)
|
||||
* Slave IC : CP1610 CPU (40 pin, same as in the Intellivision)
|
||||
* EXEC ROM : 9501-01009 (40 pin) at 0x0800 (factory mapped)
|
||||
*
|
||||
* The GIC generates the CPU Clock, the video signals and the audio.
|
||||
* The CPU does NOT access the GIC directly.
|
||||
* One way CPU->GIC 'communication' takes place through 256 bytes of shared RAM
|
||||
* (using two 4x256 TMS4043NL-2 (2112-1) Static Rams at U3 and U4)
|
||||
*
|
||||
* In this design the GIC only allows the CPU to use the BUS (and shared RAM)
|
||||
* a fraction of the frame time. (4.33ms for each 16.69ms, or 26% of the time)
|
||||
* (the real ratio of clocks is 7752/29868 )
|
||||
*
|
||||
* Boot: When the GIC let go of !RESET_OUT the EXEC Rom pushes 0x800 onto
|
||||
* the bus for the CPU to fetch and place in R7 to start execution.
|
||||
* This first CPU slice only last 3ms, then the GIC sets the CPU's BUSRQ low,
|
||||
* stalling it for 12.36ms, then sets it high for 4.33ms etc...
|
||||
* 59.95 times a second - NTSC
|
||||
************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "cpu/cp1610/cp1610.h"
|
||||
#include "video/gic.h"
|
||||
|
||||
#include "bus/generic/slot.h"
|
||||
#include "bus/generic/carts.h"
|
||||
|
||||
class unichamp_state : public driver_device
|
||||
{
|
||||
public:
|
||||
unichamp_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_gic(*this, "gic"),
|
||||
m_cart(*this, "cartslot"),
|
||||
m_ctrls(*this, "CTRLS"){}
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<gic_device> m_gic;
|
||||
required_device<generic_slot_device> m_cart;
|
||||
|
||||
UINT8 m_ram[256];
|
||||
DECLARE_DRIVER_INIT(unichamp);
|
||||
virtual void machine_start();
|
||||
virtual void machine_reset();
|
||||
DECLARE_PALETTE_INIT(unichamp);
|
||||
|
||||
DECLARE_READ8_MEMBER(bext_r);
|
||||
|
||||
DECLARE_READ16_MEMBER(unichamp_gicram_r);
|
||||
DECLARE_WRITE16_MEMBER(unichamp_gicram_w);
|
||||
|
||||
DECLARE_READ16_MEMBER(unichamp_trapl_r);
|
||||
DECLARE_WRITE16_MEMBER(unichamp_trapl_w);
|
||||
|
||||
UINT32 screen_update_unichamp(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
|
||||
protected:
|
||||
required_ioport m_ctrls;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
};
|
||||
|
||||
PALETTE_INIT_MEMBER(unichamp_state, unichamp)
|
||||
{
|
||||
/*
|
||||
palette.set_pen_color(GIC_BLACK, rgb_t(0x00, 0x00, 0x00));
|
||||
palette.set_pen_color(GIC_RED, rgb_t(0xAE, 0x49, 0x41));//(from box shot)
|
||||
palette.set_pen_color(GIC_GREEN, rgb_t(0x62, 0x95, 0x88));//(from box shot)
|
||||
palette.set_pen_color(GIC_WHITE, rgb_t(0xFF, 0xFF, 0xFF));
|
||||
*/
|
||||
|
||||
//using from intv.c instead as suggested by RB
|
||||
palette.set_pen_color(GIC_BLACK, rgb_t(0x00, 0x00, 0x00));
|
||||
palette.set_pen_color(GIC_RED, rgb_t(0xFF, 0x3D, 0x10));
|
||||
//palette.set_pen_color(GIC_GREEN, rgb_t(0x38, 0x6B, 0x3F)); //intv's DARK GREEN
|
||||
palette.set_pen_color(GIC_GREEN, rgb_t(0x00, 0xA7, 0x56)); //intv's GREEN
|
||||
palette.set_pen_color(GIC_WHITE, rgb_t(0xFF, 0xFC, 0xFF));
|
||||
}
|
||||
|
||||
|
||||
static ADDRESS_MAP_START( unichamp_mem, AS_PROGRAM, 16, unichamp_state )
|
||||
ADDRESS_MAP_GLOBAL_MASK(0x1FFF) //B13/B14/B15 are grounded!
|
||||
AM_RANGE(0x0000, 0x00FF) AM_READWRITE(unichamp_gicram_r, unichamp_gicram_w)
|
||||
AM_RANGE(0x0100, 0x07FF) AM_READWRITE(unichamp_trapl_r, unichamp_trapl_w)
|
||||
AM_RANGE(0x0800, 0x17FF) AM_ROM AM_REGION("maincpu", 0x0800 << 1) // Carts and EXE ROM, 10-bits wide
|
||||
ADDRESS_MAP_END
|
||||
|
||||
|
||||
static INPUT_PORTS_START( unichamp )
|
||||
PORT_START( "CTRLS" )
|
||||
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')// P1 YES (EBCA0)
|
||||
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')// P1 NO (EBCA1)
|
||||
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')// P2 YES (EBCA2)
|
||||
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')// P2 NO (EBCA3)
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_UNUSED
|
||||
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_UNUSED
|
||||
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_UNUSED
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_UNUSED
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
void unichamp_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
//TODO should we add an explicit Reset button in there just like the controller?
|
||||
}
|
||||
|
||||
|
||||
READ8_MEMBER(unichamp_state::bext_r)
|
||||
{
|
||||
//The BEXT instruction pushes a user-defined nibble out on the four EBCA pins (EBCA0 to EBCA3)
|
||||
//and reads the ECBI input pin for HIGH or LOW signal to know whether or not to branch
|
||||
|
||||
//The unisonic control system couldnt be simpler in desing.
|
||||
//Each of the two player controllers has three buttons:
|
||||
//one tying !RESET(GIC pin 21) to ground when closed - resetting the WHOLE system.
|
||||
//a YES button (connecting EBCA0 to EBCI for Player1 and EBC2 to EBCI for Player2)
|
||||
//a NO button (connecting EBCA1 to EBCI for Player1 and EBC3 to EBCI for Player2)
|
||||
|
||||
//The CPU outputs a MASK of whatever it needs and checks the result.
|
||||
//EG: Any player can choose if one or two players are going to play the game for instance
|
||||
|
||||
UINT8 port = ioport("CTRLS")->read() & 0x0F; ////only lower nibble
|
||||
|
||||
//We need to return logical high or low on the EBCI pin
|
||||
return (port & offset)>0?1:0;
|
||||
}
|
||||
|
||||
|
||||
DRIVER_INIT_MEMBER(unichamp_state,unichamp)
|
||||
{
|
||||
m_gic->set_shared_memory(m_ram);
|
||||
}
|
||||
|
||||
void unichamp_state::machine_start()
|
||||
{
|
||||
m_gic->set_shared_memory(m_ram);
|
||||
|
||||
if (m_cart->exists()){
|
||||
//flip endians in more "this surely exists in MAME" way?
|
||||
//NOTE The unichamp roms have the same endianness as intv on disk and in memory
|
||||
UINT8*ptr = m_cart->get_rom_base();
|
||||
size_t size = m_cart->get_rom_size();
|
||||
for(size_t i=0;i<size;i+=2){
|
||||
UINT8 TEMP = ptr[i];
|
||||
ptr[i] = ptr[i+1];
|
||||
ptr[i+1] = TEMP;
|
||||
}
|
||||
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0x1000, 0x1800,
|
||||
read16_delegate(FUNC(generic_slot_device::read16_rom),(generic_slot_device*)m_cart));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set Reset and INTR/INTRM Vector */
|
||||
void unichamp_state::machine_reset()
|
||||
{
|
||||
/*
|
||||
the intv driver did not explain this but from the CP1600 manual:
|
||||
When MSYNC* goes inactive (high), the bus control signals issue lAB,
|
||||
and the CPU inputs from the bus into the PC the starting address of the main program.
|
||||
Note that the initialization address can be defined by the user at any desired bus address or
|
||||
can be the default address resulting from the logical state of the non-driven bus
|
||||
*/
|
||||
|
||||
//The Unisonic EXEC ROM chip (9501-01009) is self mapped at 0x0800
|
||||
//The cart ROMS are self mapped to 0x1000
|
||||
//upon boot the EXEC ROM puts 0x0800 on the bus for the CPU to use as first INT vector
|
||||
|
||||
m_maincpu->set_input_line_vector(CP1610_RESET, 0x0800);
|
||||
m_maincpu->set_input_line_vector(CP1610_INT_INTRM, 0x0804);//not used anyway
|
||||
m_maincpu->set_input_line_vector(CP1610_INT_INTR, 0x0804);//not used anyway
|
||||
|
||||
/* Set initial PC */
|
||||
m_maincpu->set_state_int(CP1610_R7, 0x0800);
|
||||
}
|
||||
|
||||
|
||||
UINT32 unichamp_state::screen_update_unichamp(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
return m_gic->screen_update(screen, bitmap, cliprect);
|
||||
}
|
||||
|
||||
READ16_MEMBER( unichamp_state::unichamp_gicram_r )
|
||||
{
|
||||
return (int)m_ram[offset];
|
||||
}
|
||||
|
||||
WRITE16_MEMBER( unichamp_state::unichamp_gicram_w )
|
||||
{
|
||||
m_ram[offset] = data&0xff;
|
||||
}
|
||||
|
||||
READ16_MEMBER( unichamp_state::unichamp_trapl_r )
|
||||
{
|
||||
logerror("trapl_r(%x)\n",offset);
|
||||
return (int)0;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER( unichamp_state::unichamp_trapl_w )
|
||||
{
|
||||
logerror("trapl_w(%x) = %x\n",offset,data);
|
||||
}
|
||||
|
||||
static MACHINE_CONFIG_START( unichamp, unichamp_state )
|
||||
/* basic machine hardware */
|
||||
|
||||
//The CPU is really clocked this way:
|
||||
//MCFG_CPU_ADD("maincpu", CP1610, XTAL_3_579545MHz/4)
|
||||
//But since it is only running 7752/29868 th's of the time...
|
||||
//TODO find a more accurate method? (the emulation will me the same though)
|
||||
MCFG_CPU_ADD("maincpu", CP1610, (int)((7752.0/29868.0)*XTAL_3_579545MHz/4))
|
||||
|
||||
MCFG_CPU_PROGRAM_MAP(unichamp_mem)
|
||||
MCFG_QUANTUM_TIME(attotime::from_hz(60))
|
||||
MCFG_CP1610_BEXT_CALLBACK(READ8(unichamp_state, bext_r))
|
||||
|
||||
/* video hardware */
|
||||
MCFG_SCREEN_ADD("screen", RASTER)
|
||||
MCFG_SCREEN_RAW_PARAMS( XTAL_3_579545MHz,
|
||||
gic_device::LINE_CLOCKS,
|
||||
gic_device::START_ACTIVE_SCAN,
|
||||
gic_device::END_ACTIVE_SCAN,
|
||||
gic_device::LINES,
|
||||
gic_device::START_Y,
|
||||
gic_device::START_Y + gic_device::SCREEN_HEIGHT )
|
||||
|
||||
MCFG_SCREEN_UPDATE_DRIVER(unichamp_state, screen_update_unichamp)
|
||||
MCFG_SCREEN_PALETTE("palette")
|
||||
|
||||
MCFG_PALETTE_ADD("palette", 4)
|
||||
MCFG_PALETTE_INIT_OWNER(unichamp_state, unichamp)
|
||||
|
||||
/* sound hardware */
|
||||
MCFG_SPEAKER_STANDARD_MONO("mono")
|
||||
MCFG_GIC_ADD( "gic", XTAL_3_579545MHz, "screen" )
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40)
|
||||
|
||||
/* cartridge */
|
||||
MCFG_GENERIC_CARTSLOT_ADD("cartslot", generic_linear_slot, "unichamp_cart")
|
||||
MCFG_GENERIC_EXTENSIONS("bin,rom")
|
||||
MCFG_SOFTWARE_LIST_ADD("cart_list", "unichamp")
|
||||
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
ROM_START(unichamp)
|
||||
ROM_REGION(0x10000<<1,"maincpu", ROMREGION_ERASEFF)
|
||||
|
||||
ROM_LOAD16_WORD( "9501-01009.u2", 0x0800<<1, 0x1000, CRC(49a0bd8f) SHA1(f4d126d3462ad351da4b75d76c75942d5a6f27ef))
|
||||
|
||||
//these below are for local tests. you can use them in softlist or -cart
|
||||
//ROM_LOAD16_WORD( "pac-02.bin", 0x1000<<1, 0x1000, CRC(fe3213be) SHA1(5b9c407fe86865f3454d4be824a7f2bf53478f73))
|
||||
//ROM_LOAD16_WORD( "pac-03.bin", 0x1000<<1, 0x1000, CRC(f81f04bd) SHA1(82e2a0fda1787d5835c457ee5745b0db0cebe079))
|
||||
//ROM_LOAD16_WORD( "pac-04.bin", 0x1000<<1, 0x1000, CRC(cac09841) SHA1(bc9db83f26ed0810938156db6b104b4576754225))
|
||||
//ROM_LOAD16_WORD( "pac-05.bin", 0x1000<<1, 0x1000, CRC(d54a6090) SHA1(e85593096f43dcf14b08fd2c9fda277008a8df8b))
|
||||
ROM_END
|
||||
|
||||
|
||||
CONS( 1977, unichamp, 0, 0, unichamp, unichamp, unichamp_state, unichamp, "Unisonic", "Champion 2711", 0/*MACHINE_IMPERFECT_GRAPHICS*/)
|
@ -2764,3 +2764,4 @@ squale
|
||||
micral
|
||||
rd100
|
||||
proteus3
|
||||
unichamp
|
||||
|
335
src/mame/video/gic.c
Normal file
335
src/mame/video/gic.c
Normal file
@ -0,0 +1,335 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:David Viens
|
||||
/***************************************************************************
|
||||
|
||||
gic.c
|
||||
|
||||
GI AY-3-8800-1 (Datasheet exists as AY-3-8500-1 Graphics Interface Chip)
|
||||
For the GIMINI "Challenger" programmable game system.
|
||||
|
||||
Really only ever used in the Unisonic Champion 2711
|
||||
|
||||
More LA tests made by plgDavid on hardware pretty much confirmed what is found
|
||||
in the AY-3-8950-1 datasheet, but with more fine grained detail.
|
||||
|
||||
the GIC does not have internal ram of any sort apart from shift registers,
|
||||
instead it relies on the external shared ram, (see page 7-85) Appendix AY-3-8950-1
|
||||
|
||||
Unverified on LA (since the video pins are all connected into a composite mix):
|
||||
at line 46 it lowers GIC_BUSY, until line 240
|
||||
|
||||
Verified using LA:
|
||||
It will read the external ram areas continuously while GIC_BUSY is low (for 12.36ms)
|
||||
|
||||
(NOTE: OCTAL)
|
||||
|
||||
000,001,002,003,004,005, 110,111,112,113,114,115,116,117,120,121,122,123,124,125 (15 times - No first bg line?)
|
||||
006,007,010,011,012,013, 110,111,112,113,114,115,116,117,120,121,122,123,124,125 (16 times)
|
||||
|
||||
014,015,016,017,020,021, 125,126,127,130,131,132,133,134,135,136,137,140,141,142 (16 times)
|
||||
022,023,024,025,026,027, 125,126,127,130,131,132,133,134,135,136,137,140,141,142 (16 times)
|
||||
|
||||
030,031,032,033,034,035, 142,143,144,145,146,147,150,151,152,153,154,155,156,157 (16 times)
|
||||
036,037,040,041,042,043, 142,143,144,145,146,147,150,151,152,153,154,155,156,157 (16 times)
|
||||
|
||||
044,045,046,047,050,051, 157,160,161,162,163,164,165,166,167,170,171,172,173,174 (16 times)
|
||||
052,053,054,055,056,057, 157,160,161,162,163,164,165,166,167,170,171,172,173,174 (16 times)
|
||||
|
||||
060,061,062,063,064,065, 174,175,176,177,200,201,202,203,204,205,206,207,210,211 (16 times)
|
||||
066,067,070,071,072,073, 174,175,176,177,200,201,202,203,204,205,206,207,210,211 (16 times)
|
||||
|
||||
074,075,076,077,100,101, 211,212,213,214,215,216,217,220,221,222,223,224,225,226 (16 times)
|
||||
102,103,104,105,106,107, 211,212,213,214,215,216,217,220,221,222,223,224,225,226 (16 times)
|
||||
|
||||
000,001,002,003,004,005, 000,001,002,003,004,005,006,007,010,011,012,013,014,015 (once! padding?)
|
||||
|
||||
for a total of (12*20*16) = 3840 RAM reads (3 clocks per read at 1.79MHz)
|
||||
|
||||
Then it relingishes control to the CPU by raising BUSREQ.
|
||||
|
||||
Cloking in more detail: (in 1.79MHz clocks)
|
||||
boot:
|
||||
busy:1 5360 clocks
|
||||
busy:0 22116 clocks
|
||||
busy:1 7752 clocks
|
||||
busy:0 22116 clocks
|
||||
busy:1 7752 clocks
|
||||
(...)
|
||||
|
||||
There are NO IRQ handshakes, just BUSREQ sync shared RAM
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "gic.h"
|
||||
|
||||
// device type definition
|
||||
const device_type GIC = &device_creator<gic_device>;
|
||||
|
||||
|
||||
//Font data taken from Paul Robson's simulator
|
||||
//http://worstconsole.blogspot.ca/2012/12/the-worstconsoleever.html
|
||||
//A real AY-3-8800-1 (dead) is going to decap for a good dump
|
||||
ROM_START( gic_font )
|
||||
ROM_REGION( 0x200, "cgrom", 0 )
|
||||
ROM_LOAD( "ay-3-8800-1.bin", 0x0000, 0x200, BAD_DUMP CRC(d9f11d2b) SHA1(60ef45d51d102cd3af78787008d9aed848137bee))
|
||||
ROM_END
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// gic_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
gic_device::gic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, GIC, "GIC", tag, owner, clock, "gic", __FILE__)
|
||||
, device_sound_interface(mconfig, *this)
|
||||
, device_video_interface(mconfig, *this)
|
||||
, m_cgrom(0)
|
||||
, m_audiocnt(0)
|
||||
, m_audioval(0)
|
||||
, m_audioreset(0)
|
||||
, m_ram(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
gic_device::gic_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int lines, const char *shortname, const char *source)
|
||||
: device_t(mconfig, type, name, tag, owner, clock, shortname, source)
|
||||
, device_sound_interface(mconfig, *this)
|
||||
, device_video_interface(mconfig, *this)
|
||||
, m_cgrom(0)
|
||||
, m_audiocnt(0)
|
||||
, m_audioval(0)
|
||||
, m_audioreset(0)
|
||||
, m_ram(0)
|
||||
{
|
||||
}
|
||||
|
||||
const rom_entry *gic_device::device_rom_region() const
|
||||
{
|
||||
//there is only one... how do I get rid of this?
|
||||
return ROM_NAME( gic_font );
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void gic_device::device_start()
|
||||
{
|
||||
m_cgrom = memregion("cgrom")->base();
|
||||
|
||||
// Let the screen create our temporary bitmap with the screen's dimensions
|
||||
m_screen->register_screen_bitmap(m_bitmap);
|
||||
|
||||
m_vblank_timer = timer_alloc(TIMER_VBLANK);
|
||||
m_vblank_timer->adjust( m_screen->time_until_pos(1, END_ACTIVE_SCAN + 18 ), 0, m_screen->scan_period() );
|
||||
|
||||
// allocate the audio stream
|
||||
m_stream = stream_alloc( 0, 1, clock()/(2*228) );
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void gic_device::device_reset()
|
||||
{
|
||||
m_audiocnt=0;
|
||||
m_audioval=0;
|
||||
m_audioreset=0;
|
||||
}
|
||||
|
||||
#define GIC_CLUB 28
|
||||
#define GIC_SPACE 0
|
||||
|
||||
void gic_device::draw_char_left(int startx, int starty, UINT8 code, bitmap_ind16 &bitmap){
|
||||
|
||||
UINT8*ptr = &m_cgrom[code*GIC_CHAR_H];
|
||||
|
||||
for (size_t y=0;y<GIC_CHAR_H;y++){
|
||||
UINT8 current = *ptr++;
|
||||
UINT8 nextx=0;
|
||||
UINT8 curry= starty+y;
|
||||
for(UINT8 x=0x20;x!=0;x=x/2){
|
||||
if (current&x)
|
||||
m_bitmap.pix16(curry,startx+nextx) = GIC_WHITE;
|
||||
nextx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gic_device::draw_char_right(int startx, int starty, UINT8 code, bitmap_ind16 &bitmap, int bg_col){
|
||||
|
||||
UINT8*ptr = &m_cgrom[code*GIC_CHAR_H];
|
||||
|
||||
for (size_t y=0;y<GIC_CHAR_H;y++){
|
||||
UINT8 current = *ptr++;
|
||||
UINT8 nextx=0;
|
||||
UINT8 curry= starty+y;
|
||||
|
||||
m_bitmap.pix16(curry,startx+nextx) = bg_col;
|
||||
nextx++;
|
||||
for(UINT8 x=0x20;x!=0;x=x/2){
|
||||
m_bitmap.pix16(curry,startx+nextx) = (current&x)?GIC_WHITE:bg_col;
|
||||
nextx++;
|
||||
}
|
||||
m_bitmap.pix16(curry,startx+nextx) = bg_col;
|
||||
nextx++;
|
||||
m_bitmap.pix16(curry,startx+nextx) = bg_col;
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 gic_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
m_bitmap.fill(GIC_GREEN);
|
||||
|
||||
size_t XSTART = BORDER_SIZE;
|
||||
size_t YSTART = START_ACTIVE_SCAN;
|
||||
|
||||
//left hand side first
|
||||
UINT8 current=0;
|
||||
for(UINT8 cy=0;cy<GIC_LEFT_H;cy++){
|
||||
for(UINT8 cx=0;cx<GIC_LEFT_W;cx++){
|
||||
draw_char_left(XSTART+(cx*GIC_CHAR_W),
|
||||
YSTART+(cy*GIC_CHAR_H),
|
||||
m_ram[current],
|
||||
m_bitmap);
|
||||
current++;
|
||||
}
|
||||
}
|
||||
|
||||
//right hand side is next
|
||||
current=0x48;//110 octal
|
||||
XSTART+=(GIC_LEFT_W*GIC_CHAR_W)+1;
|
||||
|
||||
for(UINT8 cy=0;cy<GIC_RIGHT_H;cy++){
|
||||
for(UINT8 cx=0;cx<GIC_RIGHT_W;cx++){
|
||||
//complex case
|
||||
UINT8 data = m_ram[current++];
|
||||
|
||||
size_t currX = (XSTART+ (cx*(3+GIC_CHAR_W)));
|
||||
size_t currUP = (YSTART+ (cy*(2*GIC_CHAR_H)));
|
||||
size_t currLOW = (YSTART+GIC_CHAR_H+(cy*(2*GIC_CHAR_H)));
|
||||
|
||||
switch(data&0xC0){
|
||||
case 0x00:{
|
||||
//lower rectangle only, normal char
|
||||
draw_char_right(currX,currLOW,data,m_bitmap,GIC_GREEN);
|
||||
}break;
|
||||
|
||||
//White block
|
||||
case 0xC0:{
|
||||
//upper rectangle
|
||||
draw_char_right(currX,currUP, GIC_SPACE,m_bitmap,GIC_WHITE);
|
||||
//lower rectangle
|
||||
draw_char_right(currX,currLOW,GIC_SPACE,m_bitmap,GIC_WHITE);
|
||||
}break;
|
||||
|
||||
//Draw a card
|
||||
case 0x40:{
|
||||
int bgColor = (data&0x10)?GIC_RED:GIC_BLACK;
|
||||
//upper rectangle
|
||||
draw_char_right(currX,currUP, (data&0xF)+0x30,m_bitmap,bgColor);
|
||||
//lower rectangle
|
||||
draw_char_right(currX,currLOW,GIC_CLUB+((data&0x30)>>4),m_bitmap,bgColor);
|
||||
}break;
|
||||
|
||||
default:printf("gic unknown char! %02X\n",data); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copybitmap( bitmap, m_bitmap, 0, 0, 0, 0, cliprect );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AUDIO SECTION */
|
||||
|
||||
void gic_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch ( id )
|
||||
{
|
||||
case TIMER_VBLANK:
|
||||
//flag the audio to reset
|
||||
m_audioreset = 1;//phase need to reset! on next clock/228
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define GIC_AUDIO_BYTE 0x96
|
||||
|
||||
void gic_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
|
||||
{
|
||||
stream_sample_t *buffer = outputs[0];
|
||||
|
||||
//Audio is basic and badly implemented (doubt that was the intent)
|
||||
//The datasheet list the 3 different frequencies the GIC can generate: 500,1000 and 2000Hz
|
||||
//but it is clear (for an audio guy at least) that the resulting spectrum
|
||||
//is not a pure square wav. In fact, the counter is reset on vertical sync!
|
||||
//http://twitter.com/plgDavid/status/527269086016077825
|
||||
//...thus creating a buzzing sound.
|
||||
|
||||
//Dumping the audio pin value each time
|
||||
// either (PHI2 made a 0->1 transition (1.789MHz)
|
||||
// or (PHI1 made a 1->1 transition (1.789MHz)
|
||||
//I found that the granularity of audio transitions
|
||||
//(including phase resets and silences) was 228 clocks
|
||||
//The audio subsystem thus runs at 1.789MHz/228 = 7849.88Hz
|
||||
|
||||
//when 1
|
||||
//normal period:912 clocks (228*4)
|
||||
//hi for 456 clocks
|
||||
//lo for 456 clocks
|
||||
//reset period: (each frame)
|
||||
//hi for 228 clocks
|
||||
//lo for 456 clocks
|
||||
//when 2
|
||||
//normal period lasts 1824 clocks (228*8)
|
||||
//hi for 912 clocks
|
||||
//lo for 912 clocks
|
||||
//reset period: (each frame)
|
||||
//hi for 912 (228*4)
|
||||
//lo for 1596 (228*7)
|
||||
//hi for 912 (228*4)
|
||||
//when 4
|
||||
//normal period lasts 3648 clocks (228*16)
|
||||
//hi for 1824(228*8)
|
||||
//lo for 1824(228*8)
|
||||
//Reset period:
|
||||
//lo for 1824(228*8)
|
||||
//hi for 2508(228*11)
|
||||
//lo for 1824(228*8)
|
||||
//hi for 1824(228*8)
|
||||
|
||||
if(!m_ram) return;
|
||||
|
||||
UINT8 audioByte = m_ram[GIC_AUDIO_BYTE]*2;
|
||||
|
||||
if(!audioByte){
|
||||
for(size_t i = 0; i < samples; i++)
|
||||
*buffer++ = 0;
|
||||
|
||||
m_audioval = 0;
|
||||
m_audiocnt = 0;
|
||||
m_audioreset = 0;
|
||||
return;//early
|
||||
}
|
||||
|
||||
//forced resynch @ 59.95Hz
|
||||
if(m_audioreset){
|
||||
m_audioval = 0;//forced low
|
||||
m_audiocnt = 0;
|
||||
m_audioreset = 0;
|
||||
}
|
||||
|
||||
for(size_t i=0; i < samples; i++){
|
||||
m_audiocnt++;
|
||||
if(m_audiocnt >= audioByte){
|
||||
m_audioval = !m_audioval;
|
||||
m_audiocnt=0;
|
||||
}
|
||||
*buffer++ = m_audioval<<13;
|
||||
}
|
||||
}
|
114
src/mame/video/gic.h
Normal file
114
src/mame/video/gic.h
Normal file
@ -0,0 +1,114 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:David Viens
|
||||
/***************************************************************************
|
||||
|
||||
gic.h
|
||||
|
||||
GI AY-3-8800-1 (Datasheet exists as AY-3-8500-1 Graphics Interface Chip)
|
||||
For the GIMINI "Challenger" programmable game system.
|
||||
|
||||
Really only ever used in the Unisonic Champion 2711
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __GIC_H__
|
||||
#define __GIC_H__
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_GIC_ADD(_tag, _clock, _screen_tag) \
|
||||
MCFG_DEVICE_ADD(_tag, GIC, _clock) \
|
||||
MCFG_VIDEO_SET_SCREEN(_screen_tag)
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
// ======================> gic_device
|
||||
|
||||
//Palette entries
|
||||
#define GIC_BLACK 0
|
||||
#define GIC_RED 1
|
||||
#define GIC_GREEN 2
|
||||
#define GIC_WHITE 3
|
||||
|
||||
#define GIC_CHAR_W 6
|
||||
#define GIC_CHAR_H 8
|
||||
|
||||
#define GIC_LEFT_H 12
|
||||
#define GIC_LEFT_W 6
|
||||
|
||||
#define GIC_RIGHT_H 6
|
||||
#define GIC_RIGHT_W 13
|
||||
|
||||
class gic_device : public device_t
|
||||
, public device_sound_interface
|
||||
, public device_video_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
gic_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int lines, const char *shortname, const char *source);
|
||||
|
||||
// static configuration helpers
|
||||
static void set_screen_tag(device_t &device, const char *screen_tag) { downcast<gic_device &>(device).m_screen_tag = screen_tag; }
|
||||
|
||||
DECLARE_PALETTE_INIT(gic);
|
||||
|
||||
UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
|
||||
inline bitmap_ind16 *get_bitmap() { return &m_bitmap; }
|
||||
|
||||
//plgDavid please change this to a MESS friendly handshake
|
||||
void set_shared_memory(const UINT8*m){ m_ram = m;};
|
||||
|
||||
// Global constants (non mesured figures)
|
||||
static const int START_ACTIVE_SCAN = 10;
|
||||
static const int BORDER_SIZE = GIC_CHAR_W*3;
|
||||
static const int END_ACTIVE_SCAN = 10 + GIC_CHAR_W*2 + 150 + GIC_CHAR_W*2;
|
||||
static const int START_Y = 1;
|
||||
static const int SCREEN_HEIGHT = GIC_CHAR_H*(GIC_LEFT_H+2);
|
||||
static const int LINE_CLOCKS = 455;
|
||||
static const int LINES = 262;
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
|
||||
// optional information overrides
|
||||
virtual const rom_entry *device_rom_region() const;
|
||||
|
||||
// device_sound_interface overrides
|
||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
|
||||
|
||||
/* timers */
|
||||
static const device_timer_id TIMER_VBLANK = 0;
|
||||
|
||||
void draw_char_left (int x, int y, UINT8 code, bitmap_ind16 &bitmap);
|
||||
void draw_char_right(int x, int y, UINT8 code, bitmap_ind16 &bitmap,int bg_col);
|
||||
|
||||
bitmap_ind16 m_bitmap;
|
||||
UINT8 * m_cgrom; // internal chargen ROM
|
||||
|
||||
emu_timer *m_vblank_timer;
|
||||
sound_stream *m_stream;
|
||||
|
||||
int m_audiocnt;
|
||||
int m_audioval;
|
||||
int m_audioreset;
|
||||
const UINT8* m_ram;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type GIC;
|
||||
|
||||
#endif /* __GIC_H__ */
|
Loading…
Reference in New Issue
Block a user