Merge pull request #478 from jfdelnero/master

EF9365 video controller skeleton added and connected to Squale [Jean-Francois DEL NERO]
This commit is contained in:
Miodrag Milanović 2015-11-30 09:01:29 +01:00
commit 60083f5094
6 changed files with 684 additions and 6 deletions

View File

@ -154,6 +154,18 @@ if (VIDEOS["EF9345"]~=null) then
}
end
--------------------------------------------------
--
--@src/devices/video/ef9365.h,VIDEOS["EF9365"] = true
--------------------------------------------------
if (VIDEOS["EF9365"]~=null) then
files {
MAME_DIR .. "src/devices/video/ef9365.cpp",
MAME_DIR .. "src/devices/video/ef9365.h",
}
end
--------------------------------------------------
--@src/devices/video/epic12.h,VIDEOS["EPIC12"] = true
--------------------------------------------------

View File

@ -275,6 +275,7 @@ VIDEOS["BUFSPRITE"] = true
VIDEOS["DM9368"] = true
--VIDEOS["EF9340_1"] = true
--VIDEOS["EF9345"] = true
--VIDEOS["EF9365"] = true
--VIDEOS["GF4500"] = true
VIDEOS["GF7600GS"] = true
VIDEOS["EPIC12"] = true

View File

@ -272,6 +272,7 @@ VIDEOS["DL1416"] = true
VIDEOS["DM9368"] = true
VIDEOS["EF9340_1"] = true
VIDEOS["EF9345"] = true
VIDEOS["EF9365"] = true
VIDEOS["GF4500"] = true
--VIDEOS+= EPIC12"] = true
--VIDEOS+= FIXFREQ"] = true

View File

@ -0,0 +1,455 @@
// license:BSD-3-Clause
// copyright-holders:Jean-François DEL NERO
/*********************************************************************
ef9365.c
Thomson EF9365 video controller emulator code
*********************************************************************/
#include "emu.h"
#include "ef9365.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
// devices
const device_type EF9365 = &device_creator<ef9365_device>;
// default address map
static ADDRESS_MAP_START( ef9365, AS_0, 8, ef9365_device )
AM_RANGE(0x0000, 0x1fff) AM_RAM // BLUE
AM_RANGE(0x2000, 0x3fff) AM_RAM // GREEN
AM_RANGE(0x4000, 0x5fff) AM_RAM // RED
AM_RANGE(0x6000, 0x7fff) AM_RAM // INTENSITY
ADDRESS_MAP_END
//-------------------------------------------------
// memory_space_config - return a description of
// any address spaces owned by this device
//-------------------------------------------------
const address_space_config *ef9365_device::memory_space_config(address_spacenum spacenum) const
{
return (spacenum == AS_0) ? &m_space_config : NULL;
}
//**************************************************************************
// INLINE HELPERS
//**************************************************************************
//**************************************************************************
// live device
//**************************************************************************
//-------------------------------------------------
// ef9365_device - constructor
//-------------------------------------------------
ef9365_device::ef9365_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, EF9365, "EF9365", tag, owner, clock, "ef9365", __FILE__),
device_memory_interface(mconfig, *this),
device_video_interface(mconfig, *this),
m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(ef9365)),
m_palette(*this)
{
}
//-------------------------------------------------
// static_set_palette_tag: Set the tag of the
// palette device
//-------------------------------------------------
void ef9365_device::static_set_palette_tag(device_t &device, const char *tag)
{
downcast<ef9365_device &>(device).m_palette.set_tag(tag);
}
//-------------------------------------------------
// static_set_color_filler: Set the color value
// used by the chip to draw/fill the memory
//-------------------------------------------------
void ef9365_device::static_set_color_filler( UINT8 color )
{
m_current_color = color;
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void ef9365_device::device_start()
{
m_busy_timer = timer_alloc(BUSY_TIMER);
m_videoram = &space(0);
m_charset = region();
m_current_color = 0x0F;
m_screen_out.allocate(496, m_screen->height());
save_item(NAME(m_border));
save_item(NAME(m_registers));
save_item(NAME(m_bf));
save_item(NAME(m_state));
save_item(NAME(m_screen_out));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void ef9365_device::device_reset()
{
m_state = 0;
m_bf = 0;
memset(m_registers, 0, sizeof(m_registers));
memset(m_border, 0, sizeof(m_border));
m_screen_out.fill(0);
set_video_mode();
}
//-------------------------------------------------
// device_timer - handler timer events
//-------------------------------------------------
void ef9365_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch(id)
{
case BUSY_TIMER:
m_bf = 0;
break;
}
}
// set busy flag and timer to clear it
void ef9365_device::set_busy_flag(int period)
{
m_bf = 1;
m_busy_timer->adjust(attotime::from_usec(period));
}
// set then ef9365 mode
void ef9365_device::set_video_mode(void)
{
UINT16 new_width = 256;
if (m_screen->width() != new_width)
{
rectangle visarea = m_screen->visible_area();
visarea.max_x = new_width - 1;
m_screen->configure(new_width, m_screen->height(), visarea, m_screen->frame_period().attoseconds());
}
//border color
memset(m_border, 0, sizeof(m_border));
}
void ef9365_device::draw_border(UINT16 line)
{
}
void ef9365_device::draw_character( unsigned char c )
{
int x_char,y_char;
int char_base,char_pix;
unsigned int x, y;
x = ( (m_registers[EF9365_REG_X_MSB]<<8) | m_registers[EF9365_REG_X_LSB]);
y = ( (m_registers[EF9365_REG_Y_MSB]<<8) | m_registers[EF9365_REG_Y_LSB]);
if(c<96)
{
y = ( 256 - y ) - 8;
if( ( x < ( 256 - 5 ) ) && ( y < ( 256 - 8 ) ) )
{
char_base = c * 5; // 5 bytes per char.
char_pix = 0;
for(y_char=0;y_char<8;y_char++)
{
for(x_char=0;x_char<5;x_char++)
{
if ( m_charset->u8(char_base + (char_pix>>3) ) & ( 0x80 >> (char_pix&7)))
{
if( m_current_color & 0x01)
m_videoram->write_byte ( 0x0000 + ((((y_char+y)*256) + (x_char+x))>>3), m_videoram->read_byte( 0x0000 + ((((y_char+y)*256) + (x_char+x))>>3)) | (0x80 >> ((((y_char+y)*256) + (x_char+x))&7) ) );
if( m_current_color & 0x02)
m_videoram->write_byte ( 0x2000 + ((((y_char+y)*256) + (x_char+x))>>3), m_videoram->read_byte( 0x2000 + ((((y_char+y)*256) + (x_char+x))>>3)) | (0x80 >> ((((y_char+y)*256) + (x_char+x))&7) ) );
if( m_current_color & 0x04)
m_videoram->write_byte ( 0x4000 + ((((y_char+y)*256) + (x_char+x))>>3), m_videoram->read_byte( 0x4000 + ((((y_char+y)*256) + (x_char+x))>>3)) | (0x80 >> ((((y_char+y)*256) + (x_char+x))&7) ) );
if( m_current_color & 0x08)
m_videoram->write_byte ( 0x6000 + ((((y_char+y)*256) + (x_char+x))>>3), m_videoram->read_byte( 0x6000 + ((((y_char+y)*256) + (x_char+x))>>3)) | (0x80 >> ((((y_char+y)*256) + (x_char+x))&7) ) );
}
char_pix++;
}
}
x = x + 6;
m_registers[EF9365_REG_X_MSB] = x >> 8;
m_registers[EF9365_REG_X_LSB] = x & 0xFF;
}
}
}
// Execute EF9365 command
void ef9365_device::ef9365_exec(UINT8 cmd)
{
m_state = 0;
set_busy_flag(4);
if( ( cmd>>4 ) == 0 )
{
switch(cmd & 0xF)
{
case 0x0: // Set bit 1 of CTRL1 : Pen Selection
#ifdef DBGMODE
printf("Set bit 1 of CTRL1 : Pen Selection\n");
#endif
m_registers[EF9365_REG_CTRL1] |= 0x02;
break;
case 0x1: // Clear bit 1 of CTRL1 : Eraser Selection
#ifdef DBGMODE
printf("Clear bit 1 of CTRL1 : Eraser Selection\n");
#endif
m_registers[EF9365_REG_CTRL1] &= (~0x02);
break;
case 0x2: // Set bit 0 of CTRL1 : Pen/Eraser down selection
#ifdef DBGMODE
printf("Set bit 0 of CTRL1 : Pen/Eraser down selection\n");
#endif
m_registers[EF9365_REG_CTRL1] |= 0x01;
break;
case 0x3: // Clear bit 0 of CTRL1 : Pen/Eraser up selection
#ifdef DBGMODE
printf("Clear bit 0 of CTRL1 : Pen/Eraser up selection\n");
#endif
m_registers[EF9365_REG_CTRL1] &= (~0x01);
break;
case 0x4: // Clear screen
#ifdef DBGMODE
printf("Clear screen\n");
#endif
break;
case 0x5: // X and Y registers reset to 0
#ifdef DBGMODE
printf("X and Y registers reset to 0\n");
#endif
m_registers[EF9365_REG_X_MSB] = 0;
m_registers[EF9365_REG_X_LSB] = 0;
m_registers[EF9365_REG_Y_MSB] = 0;
m_registers[EF9365_REG_Y_LSB] = 0;
break;
case 0x6: // X and Y registers reset to 0 and clear screen
#ifdef DBGMODE
printf("X and Y registers reset to 0 and clear screen\n");
#endif
m_registers[EF9365_REG_X_MSB] = 0;
m_registers[EF9365_REG_X_LSB] = 0;
m_registers[EF9365_REG_Y_MSB] = 0;
m_registers[EF9365_REG_Y_LSB] = 0;
break;
case 0x7: // Clear screen, set CSIZE to code "minsize". All other registers reset to 0
#ifdef DBGMODE
printf("Clear screen, set CSIZE to code \"minsize\". All other registers reset to 0\n");
#endif
break;
case 0x8: // Light-pen initialization (/White forced low)
#ifdef DBGMODE
printf("Light-pen initialization (/White forced low)\n");
#endif
break;
case 0x9: // Light-pen initialization
#ifdef DBGMODE
printf("Light-pen initialization\n");
#endif
break;
case 0xA: // 5x8 block drawing (size according to CSIZE)
#ifdef DBGMODE
printf("5x8 block drawing (size according to CSIZE)\n");
#endif
break;
case 0xB: // 4x4 block drawing (size according to CSIZE)
#ifdef DBGMODE
printf("4x4 block drawing (size according to CSIZE)\n");
#endif
break;
case 0xC: // Screen scanning : pen or Eraser as defined by CTRL1
#ifdef DBGMODE
printf("Screen scanning : pen or Eraser as defined by CTRL1\n");
#endif
break;
case 0xD: // X reset to 0
#ifdef DBGMODE
printf("X reset to 0\n");
#endif
m_registers[EF9365_REG_X_MSB] = 0;
m_registers[EF9365_REG_X_LSB] = 0;
break;
case 0xE: // Y reset to 0
#ifdef DBGMODE
printf("Y reset to 0\n");
#endif
m_registers[EF9365_REG_Y_MSB] = 0;
m_registers[EF9365_REG_Y_LSB] = 0;
break;
case 0xF: // Direct image memory access request for the next free cycle.
#ifdef DBGMODE
printf("Direct image memory access request for the next free cycle.\n");
#endif
break;
default:
logerror("Unemulated EF9365 cmd: %02x\n", cmd);
}
}
else
{
if ( ( cmd>>4 ) == 1 )
{
if( ( cmd & 0xF ) < 0x8 )
{
// Vector generation ( for b2,b1,0 see small vector definition)
#ifdef DBGMODE
printf("Vector generation ( for b2,b1,0 see small vector definition)\n");
#endif
}
else
{
// Special direction vectors generation ( for b2,b1,0 see small vector definition)
#ifdef DBGMODE
printf("Special direction vectors generation ( for b2,b1,0 see small vector definition)\n");
#endif
}
}
else
{
if( ( cmd>>4 ) >= 0x8 )
{
// Small vector definition.
#ifdef DBGMODE
printf("Small vector definition.\n");
#endif
}
else
{
// Draw character
#ifdef DBGMODE
printf("Draw character\n");
#endif
draw_character( cmd - 0x20 );
}
}
}
}
/**************************************************************
EF9365 interface
**************************************************************/
UINT32 ef9365_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
int i,j,k;
unsigned long r,v,b;
k = 0;
for(i=0;i<256;i++)
{
for(j=0;j<256;j++)
{
r = v = b = 0;
if( m_videoram->read_byte(0x0000 + (k>>3)) & (0x80>>(k&7)))
{
b = 0xFF;
}
if( m_videoram->read_byte(0x2000 + (k>>3)) & (0x80>>(k&7)))
{
v = 0xFF;
}
if( m_videoram->read_byte(0x4000 + (k>>3)) & (0x80>>(k&7)))
{
r = 0xFF;
}
if( m_videoram->read_byte(0x6000 + (k>>3)) & (0x80>>(k&7)))
{
r = r / 2;
v = v / 2;
b = b / 2;
}
m_screen_out.pix32(i, j) = ( r<<16 ) | ( v<<8 ) | b;
k++;
}
}
copybitmap(bitmap, m_screen_out, 0, 0, 0, 0, cliprect);
return 0;
}
void ef9365_device::update_scanline(UINT16 scanline)
{
if (scanline == 250)
m_state |= (0x02); // vsync
if (scanline == 0)
{
m_state &= (~0x02);
draw_border(0);
}
else if (scanline < 120)
{
}
else if (scanline < 250)
{
}
}
READ8_MEMBER( ef9365_device::data_r )
{
if (offset & 0xF)
return m_registers[offset & 0xF];
if (m_bf)
m_state &= (~0x04);
else
m_state |= 0x04;
#ifdef DBGMODE
printf("rd ef9365 [0x%2x] = [0x%2x]\n", offset&0xF,m_state );
#endif
return m_state;
}
WRITE8_MEMBER( ef9365_device::data_w )
{
m_registers[offset & 0xF] = data;
#ifdef DBGMODE
printf("wr ef9365 [0x%2x] = [0x%2x]\n", offset&0xF,data );
#endif
if (!offset)
ef9365_exec(m_registers[0] & 0xff);
}

106
src/devices/video/ef9365.h Normal file
View File

@ -0,0 +1,106 @@
// license:BSD-3-Clause
// copyright-holders:Jean-François DEL NERO
/*********************************************************************
ef9365.h
Thomson EF9365 video controller
*********************************************************************/
#pragma once
#ifndef __EF9365_H__
#define __EF9365_H__
#define MCFG_EF9365_PALETTE(_palette_tag) \
ef9365_device::static_set_palette_tag(*device, "^" _palette_tag);
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> ef9365_device
class ef9365_device : public device_t,
public device_memory_interface,
public device_video_interface
{
public:
// construction/destruction
ef9365_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
// static configuration
static void static_set_palette_tag(device_t &device, const char *tag);
// device interface
DECLARE_READ8_MEMBER( data_r );
DECLARE_WRITE8_MEMBER( data_w );
void update_scanline(UINT16 scanline);
void static_set_color_filler( UINT8 color );
UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
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);
// device_config_memory_interface overrides
virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
// address space configurations
const address_space_config m_space_config;
// inline helper
private:
void draw_character( unsigned char c );
void set_busy_flag(int period);
void set_video_mode(void);
void draw_border(UINT16 line);
void ef9365_exec(UINT8 cmd);
// internal state
static const device_timer_id BUSY_TIMER = 0;
memory_region *m_charset;
address_space *m_videoram;
UINT8 m_current_color;
UINT8 m_bf; //busy flag
UINT8 m_registers[0x10]; //registers
UINT8 m_state; //status register
UINT8 m_border[80]; //border color
bitmap_rgb32 m_screen_out;
// timers
emu_timer *m_busy_timer;
required_device<palette_device> m_palette;
};
// device type definition
extern const device_type EF9365;
#define EF9365_REG_STATUS 0x00
#define EF9365_REG_CMD 0x00
#define EF9365_REG_CTRL1 0x01
#define EF9365_REG_CTRL2 0x02
#define EF9365_REG_CSIZE 0x03
#define EF9365_REG_DELTAX 0x05
#define EF9365_REG_DELTAY 0x07
#define EF9365_REG_X_MSB 0x08
#define EF9365_REG_X_LSB 0x09
#define EF9365_REG_Y_MSB 0x0A
#define EF9365_REG_Y_LSB 0x0B
#define EF9365_REG_XLP 0x0C
#define EF9365_REG_YLP 0x0D
#define EF9365_REG_CTRL1 0x01
#define EF9365_REG_CTRL1 0x01
#endif

View File

@ -1,9 +1,13 @@
// license:BSD-3-Clause
// copyright-holders:Miodrag Milanovic
// copyright-holders:Miodrag Milanovic, Jean-François DEL NERO
/***************************************************************************
Apollo 7 Squale
The following hardware description is an extract of the Squale hardware analysis
presented on this page : http://hxc2001.free.fr/Squale.
This is a work in progress and is subject to changes
PCB Ref Qty Manufacturer Ref Description / Datasheet
============================================================================================
U1 1 EF6809P 8-BIT MICROPROCESSOR UNIT (MPU)
@ -24,7 +28,7 @@
Memory map
==========
Periphiriques Adresses
Devices Adresses
=========================================================
EPROM 0xF100-0xFFFF
Extension Port 0xF080-0xF0FF
@ -43,32 +47,83 @@
Notes:
1) For 8KB versions of the monitor, the bank switching is done via bit 7 of REG1.
1) For 8KB versions of the monitor, the bank switching is done with the bit 7 of REG1.
2) VID_RD1 : [7..0] = I0,R0,G0,B0,I1,R1,G1,B1 (I=Intensity,R=Red,G=Green,B=Blue)
3) VID_RD2 : [7..0] = I2,R2,G2,B2,I3,R3,G3,B3 (I=Intensity,R=Red,G=Green,B=Blue)
3) REG1 : [7..0] = EPROM Bank,-,Modem,K7,I,R,G,B (I=Intensity,R=Red,V=Green,B=Blue)
****************************************************************************/
#include "emu.h"
#include "cpu/m6809/m6809.h"
#include "video/ef9365.h"
#include "machine/6821pia.h"
#include "machine/6850acia.h"
#include "sound/ay8910.h"
#define MAIN_CLOCK XTAL_14MHz
#define AY_CLOCK MAIN_CLOCK / 8 /* 1.75 Mhz */
#define CPU_CLOCK MAIN_CLOCK / 4 /* 3.50 Mhz */
class squale_state : public driver_device
{
public:
squale_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_acia(*this, "ef6850")
, m_ay8910(*this, "ay8910")
, m_pia_u72(*this, "pia_u72")
, m_pia_u75(*this, "pia_u75")
, m_ef9365(*this, "ef9365")
, m_maincpu(*this, "maincpu")
{ }
DECLARE_WRITE8_MEMBER(ctrl_w);
virtual void machine_start();
virtual void machine_reset();
TIMER_DEVICE_CALLBACK_MEMBER(squale_scanline);
private:
required_device<acia6850_device> m_acia;
required_device<ay8910_device> m_ay8910;
required_device<pia6821_device> m_pia_u72;
required_device<pia6821_device> m_pia_u75;
required_device<ef9365_device> m_ef9365;
required_device<cpu_device> m_maincpu;
};
/*************************
* Misc Handlers *
*************************/
WRITE8_MEMBER( squale_state::ctrl_w )
{
#ifdef DBGMODE
printf("write ctrl reg : 0x%X\n",data);
#endif
membank("rom_bank")->set_entry(data >> 7);
m_ef9365->static_set_color_filler(data & 0xF);
}
TIMER_DEVICE_CALLBACK_MEMBER( squale_state::squale_scanline )
{
m_ef9365->update_scanline((UINT16)param);
}
static ADDRESS_MAP_START(squale_mem, AS_PROGRAM, 8, squale_state)
ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x0000,0xefff) AM_RAM
AM_RANGE(0xf100,0xffff) AM_ROM AM_REGION("maincpu", 0x100)
AM_RANGE(0xf000,0xf00f) AM_DEVREADWRITE("ef9365", ef9365_device, data_r, data_w)
AM_RANGE(0xf010,0xf01f) AM_WRITE( ctrl_w )
AM_RANGE(0xf044,0xf047) AM_DEVREADWRITE("pia_u75", pia6821_device, read_alt, write_alt)
AM_RANGE(0xf048,0xf04b) AM_DEVREADWRITE("pia_u72", pia6821_device, read_alt, write_alt)
AM_RANGE(0xf050,0xf05f) AM_DEVREADWRITE("ef6850", acia6850_device, data_r, data_w)
AM_RANGE(0xf060,0xf06f) AM_DEVREADWRITE("ay8910", ay8910_device, data_r, address_data_w)
AM_RANGE(0xf100,0xffff) AM_ROMBANK("rom_bank");
ADDRESS_MAP_END
static ADDRESS_MAP_START( squale_io, AS_IO, 8, squale_state)
@ -79,18 +134,66 @@ ADDRESS_MAP_END
static INPUT_PORTS_START( squale )
INPUT_PORTS_END
void squale_state::machine_start()
{
membank("rom_bank")->configure_entry(0, memregion("maincpu")->base() + 0x100);
membank("rom_bank")->configure_entry(1, memregion("maincpu")->base() + 0x1100);
membank("rom_bank")->set_entry( 0 );
}
void squale_state::machine_reset()
{
}
static MACHINE_CONFIG_START( squale, squale_state )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu",M6809, XTAL_1MHz)
MCFG_CPU_ADD("maincpu",M6809, CPU_CLOCK)
MCFG_CPU_PROGRAM_MAP(squale_mem)
MCFG_CPU_IO_MAP(squale_io)
/* Cartridge pia */
MCFG_DEVICE_ADD("pia_u72", PIA6821, 0)
// TODO : Add port I/O handler
/* Keyboard pia */
MCFG_DEVICE_ADD("pia_u75", PIA6821, 0)
// TODO : Add port I/O handler
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("ay8910", AY8910, AY_CLOCK)
// TODO : Add port I/O handler
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
MCFG_DEVICE_ADD ("ef6850", ACIA6850, 0)
/* screen */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(60)
MCFG_SCREEN_UPDATE_DEVICE("ef9365", ef9365_device, screen_update)
MCFG_SCREEN_SIZE(336, 270)
MCFG_SCREEN_VISIBLE_AREA(00, 336-1, 00, 270-1)
MCFG_PALETTE_ADD("palette", 8)
MCFG_DEVICE_ADD("ef9365", EF9365, 0)
MCFG_EF9365_PALETTE("palette")
MCFG_TIMER_DRIVER_ADD_SCANLINE("squale_sl", squale_state, squale_scanline, "screen", 0, 10)
MACHINE_CONFIG_END
/* ROM definition */
ROM_START( squale )
ROM_REGION( 0x2000, "maincpu", 0 )
ROM_LOAD( "sqm2r1.bin", 0x0000, 0x2000, CRC(ed57c707) SHA1(c8bd33a6fb07fe7f881f2605ad867b7e82366bfc) )
ROM_DEFAULT_BIOS("v201")
ROM_SYSTEM_BIOS(0, "v201", "Version 2.1")
ROMX_LOAD( "sqmon_2r1.bin", 0x0000, 0x2000, CRC(ed57c707) SHA1(c8bd33a6fb07fe7f881f2605ad867b7e82366bfc), ROM_BIOS(1) )
// place ROM v1.2 signature here.
ROM_REGION( 0x1E0, "ef9365", 0 )
ROM_LOAD( "charset_ef9365.rom", 0x0000, 0x01E0, CRC(22BE2908) SHA1(3920ee887b8ca2887b3e0471bea7c1045a87fc10) )
ROM_END
/* Driver */