new WORKING

Unisonic Champion 2711 [David Viens]
This commit is contained in:
David Haywood 2015-10-26 22:02:55 +00:00
parent 2751e76c83
commit bc6c55fe47
6 changed files with 790 additions and 0 deletions

54
hash/unichamp.xml Normal file
View 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>

View File

@ -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
View 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*/)

View File

@ -2764,3 +2764,4 @@ squale
micral
rd100
proteus3
unichamp

335
src/mame/video/gic.c Normal file
View 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
View 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__ */