mirror of
https://github.com/holub/mame
synced 2025-07-05 18:08:04 +03:00
Ported DC, SMS and SG1000 to main folder, nw
This commit is contained in:
parent
249c2c6402
commit
f280fd9f99
24
.gitattributes
vendored
24
.gitattributes
vendored
@ -665,6 +665,8 @@ src/emu/fileio.c svneol=native#text/plain
|
|||||||
src/emu/fileio.h svneol=native#text/plain
|
src/emu/fileio.h svneol=native#text/plain
|
||||||
src/emu/hash.c svneol=native#text/plain
|
src/emu/hash.c svneol=native#text/plain
|
||||||
src/emu/hash.h svneol=native#text/plain
|
src/emu/hash.h svneol=native#text/plain
|
||||||
|
src/emu/hashfile.c svneol=native#text/plain
|
||||||
|
src/emu/hashfile.h svneol=native#text/plain
|
||||||
src/emu/image.c svneol=native#text/plain
|
src/emu/image.c svneol=native#text/plain
|
||||||
src/emu/image.h svneol=native#text/plain
|
src/emu/image.h svneol=native#text/plain
|
||||||
src/emu/imagedev/bitbngr.c svneol=native#text/plain
|
src/emu/imagedev/bitbngr.c svneol=native#text/plain
|
||||||
@ -857,6 +859,8 @@ src/emu/machine/msm58321.c svneol=native#text/plain
|
|||||||
src/emu/machine/msm58321.h svneol=native#text/plain
|
src/emu/machine/msm58321.h svneol=native#text/plain
|
||||||
src/emu/machine/msm6242.c svneol=native#text/plain
|
src/emu/machine/msm6242.c svneol=native#text/plain
|
||||||
src/emu/machine/msm6242.h svneol=native#text/plain
|
src/emu/machine/msm6242.h svneol=native#text/plain
|
||||||
|
src/emu/machine/msm8251.c svneol=native#text/plain
|
||||||
|
src/emu/machine/msm8251.h svneol=native#text/plain
|
||||||
src/emu/machine/nmc9306.c svneol=native#text/plain
|
src/emu/machine/nmc9306.c svneol=native#text/plain
|
||||||
src/emu/machine/nmc9306.h svneol=native#text/plain
|
src/emu/machine/nmc9306.h svneol=native#text/plain
|
||||||
src/emu/machine/nvram.c svneol=native#text/plain
|
src/emu/machine/nvram.c svneol=native#text/plain
|
||||||
@ -903,6 +907,8 @@ src/emu/machine/scsihd.c svneol=native#text/plain
|
|||||||
src/emu/machine/scsihd.h svneol=native#text/plain
|
src/emu/machine/scsihd.h svneol=native#text/plain
|
||||||
src/emu/machine/secflash.c svneol=native#text/plain
|
src/emu/machine/secflash.c svneol=native#text/plain
|
||||||
src/emu/machine/secflash.h svneol=native#text/plain
|
src/emu/machine/secflash.h svneol=native#text/plain
|
||||||
|
src/emu/machine/serial.c svneol=native#text/plain
|
||||||
|
src/emu/machine/serial.h svneol=native#text/plain
|
||||||
src/emu/machine/smc91c9x.c svneol=native#text/plain
|
src/emu/machine/smc91c9x.c svneol=native#text/plain
|
||||||
src/emu/machine/smc91c9x.h svneol=native#text/plain
|
src/emu/machine/smc91c9x.h svneol=native#text/plain
|
||||||
src/emu/machine/timekpr.c svneol=native#text/plain
|
src/emu/machine/timekpr.c svneol=native#text/plain
|
||||||
@ -917,6 +923,8 @@ src/emu/machine/upd4701.c svneol=native#text/plain
|
|||||||
src/emu/machine/upd4701.h svneol=native#text/plain
|
src/emu/machine/upd4701.h svneol=native#text/plain
|
||||||
src/emu/machine/upd7201.c svneol=native#text/plain
|
src/emu/machine/upd7201.c svneol=native#text/plain
|
||||||
src/emu/machine/upd7201.h svneol=native#text/plain
|
src/emu/machine/upd7201.h svneol=native#text/plain
|
||||||
|
src/emu/machine/upd765.c svneol=native#text/plain
|
||||||
|
src/emu/machine/upd765.h svneol=native#text/plain
|
||||||
src/emu/machine/wd33c93.c svneol=native#text/plain
|
src/emu/machine/wd33c93.c svneol=native#text/plain
|
||||||
src/emu/machine/wd33c93.h svneol=native#text/plain
|
src/emu/machine/wd33c93.h svneol=native#text/plain
|
||||||
src/emu/machine/x2212.c svneol=native#text/plain
|
src/emu/machine/x2212.c svneol=native#text/plain
|
||||||
@ -1783,6 +1791,7 @@ src/mame/drivers/darkseal.c svneol=native#text/plain
|
|||||||
src/mame/drivers/dassault.c svneol=native#text/plain
|
src/mame/drivers/dassault.c svneol=native#text/plain
|
||||||
src/mame/drivers/dblewing.c svneol=native#text/plain
|
src/mame/drivers/dblewing.c svneol=native#text/plain
|
||||||
src/mame/drivers/dbz.c svneol=native#text/plain
|
src/mame/drivers/dbz.c svneol=native#text/plain
|
||||||
|
src/mame/drivers/dc.c svneol=native#text/plain
|
||||||
src/mame/drivers/dcheese.c svneol=native#text/plain
|
src/mame/drivers/dcheese.c svneol=native#text/plain
|
||||||
src/mame/drivers/dcon.c svneol=native#text/plain
|
src/mame/drivers/dcon.c svneol=native#text/plain
|
||||||
src/mame/drivers/dday.c svneol=native#text/plain
|
src/mame/drivers/dday.c svneol=native#text/plain
|
||||||
@ -2407,6 +2416,7 @@ src/mame/drivers/segas16b.c svneol=native#text/plain
|
|||||||
src/mame/drivers/segas18.c svneol=native#text/plain
|
src/mame/drivers/segas18.c svneol=native#text/plain
|
||||||
src/mame/drivers/segas24.c svneol=native#text/plain
|
src/mame/drivers/segas24.c svneol=native#text/plain
|
||||||
src/mame/drivers/segas32.c svneol=native#text/plain
|
src/mame/drivers/segas32.c svneol=native#text/plain
|
||||||
|
src/mame/drivers/segasms.c svneol=native#text/plain
|
||||||
src/mame/drivers/segaxbd.c svneol=native#text/plain
|
src/mame/drivers/segaxbd.c svneol=native#text/plain
|
||||||
src/mame/drivers/segaybd.c svneol=native#text/plain
|
src/mame/drivers/segaybd.c svneol=native#text/plain
|
||||||
src/mame/drivers/seibuspi.c svneol=native#text/plain
|
src/mame/drivers/seibuspi.c svneol=native#text/plain
|
||||||
@ -2419,6 +2429,7 @@ src/mame/drivers/sf.c svneol=native#text/plain
|
|||||||
src/mame/drivers/sfbonus.c svneol=native#text/plain
|
src/mame/drivers/sfbonus.c svneol=native#text/plain
|
||||||
src/mame/drivers/sfcbox.c svneol=native#text/plain
|
src/mame/drivers/sfcbox.c svneol=native#text/plain
|
||||||
src/mame/drivers/sfkick.c svneol=native#text/plain
|
src/mame/drivers/sfkick.c svneol=native#text/plain
|
||||||
|
src/mame/drivers/sg1000.c svneol=native#text/plain
|
||||||
src/mame/drivers/sg1000a.c svneol=native#text/plain
|
src/mame/drivers/sg1000a.c svneol=native#text/plain
|
||||||
src/mame/drivers/shadfrce.c svneol=native#text/plain
|
src/mame/drivers/shadfrce.c svneol=native#text/plain
|
||||||
src/mame/drivers/shangha3.c svneol=native#text/plain
|
src/mame/drivers/shangha3.c svneol=native#text/plain
|
||||||
@ -2705,6 +2716,8 @@ src/mame/drivers/zodiack.c svneol=native#text/plain
|
|||||||
src/mame/drivers/zr107.c svneol=native#text/plain
|
src/mame/drivers/zr107.c svneol=native#text/plain
|
||||||
src/mame/etc/fd1094dp.c svneol=native#text/plain
|
src/mame/etc/fd1094dp.c svneol=native#text/plain
|
||||||
src/mame/etc/jrcrypt.c svneol=native#text/plain
|
src/mame/etc/jrcrypt.c svneol=native#text/plain
|
||||||
|
src/mame/formats/basicdsk.c svneol=native#text/plain
|
||||||
|
src/mame/formats/basicdsk.h svneol=native#text/plain
|
||||||
src/mame/includes/1942.h svneol=native#text/plain
|
src/mame/includes/1942.h svneol=native#text/plain
|
||||||
src/mame/includes/1943.h svneol=native#text/plain
|
src/mame/includes/1943.h svneol=native#text/plain
|
||||||
src/mame/includes/20pacgal.h svneol=native#text/plain
|
src/mame/includes/20pacgal.h svneol=native#text/plain
|
||||||
@ -3196,6 +3209,7 @@ src/mame/includes/segamsys.h svneol=native#text/plain
|
|||||||
src/mame/includes/segas16.h svneol=native#text/plain
|
src/mame/includes/segas16.h svneol=native#text/plain
|
||||||
src/mame/includes/segas24.h svneol=native#text/plain
|
src/mame/includes/segas24.h svneol=native#text/plain
|
||||||
src/mame/includes/segas32.h svneol=native#text/plain
|
src/mame/includes/segas32.h svneol=native#text/plain
|
||||||
|
src/mame/includes/segasms.h svneol=native#text/plain
|
||||||
src/mame/includes/sei_crtc.h svneol=native#text/plain
|
src/mame/includes/sei_crtc.h svneol=native#text/plain
|
||||||
src/mame/includes/seibuspi.h svneol=native#text/plain
|
src/mame/includes/seibuspi.h svneol=native#text/plain
|
||||||
src/mame/includes/seicross.h svneol=native#text/plain
|
src/mame/includes/seicross.h svneol=native#text/plain
|
||||||
@ -3203,6 +3217,7 @@ src/mame/includes/senjyo.h svneol=native#text/plain
|
|||||||
src/mame/includes/seta.h svneol=native#text/plain
|
src/mame/includes/seta.h svneol=native#text/plain
|
||||||
src/mame/includes/seta2.h svneol=native#text/plain
|
src/mame/includes/seta2.h svneol=native#text/plain
|
||||||
src/mame/includes/sf.h svneol=native#text/plain
|
src/mame/includes/sf.h svneol=native#text/plain
|
||||||
|
src/mame/includes/sg1000.h svneol=native#text/plain
|
||||||
src/mame/includes/shadfrce.h svneol=native#text/plain
|
src/mame/includes/shadfrce.h svneol=native#text/plain
|
||||||
src/mame/includes/shangha3.h svneol=native#text/plain
|
src/mame/includes/shangha3.h svneol=native#text/plain
|
||||||
src/mame/includes/shangkid.h svneol=native#text/plain
|
src/mame/includes/shangkid.h svneol=native#text/plain
|
||||||
@ -3510,6 +3525,7 @@ src/mame/layout/slots.lay svneol=native#text/plain
|
|||||||
src/mame/layout/sltblgpo.lay svneol=native#text/plain
|
src/mame/layout/sltblgpo.lay svneol=native#text/plain
|
||||||
src/mame/layout/sltblgtk.lay svneol=native#text/plain
|
src/mame/layout/sltblgtk.lay svneol=native#text/plain
|
||||||
src/mame/layout/smoto.lay svneol=native#text/plain
|
src/mame/layout/smoto.lay svneol=native#text/plain
|
||||||
|
src/mame/layout/sms1.lay svneol=native#text/plain
|
||||||
src/mame/layout/snookr10.lay svneol=native#text/plain
|
src/mame/layout/snookr10.lay svneol=native#text/plain
|
||||||
src/mame/layout/solarq.lay svneol=native#text/plain
|
src/mame/layout/solarq.lay svneol=native#text/plain
|
||||||
src/mame/layout/sos.lay svneol=native#text/plain
|
src/mame/layout/sos.lay svneol=native#text/plain
|
||||||
@ -3580,6 +3596,8 @@ src/mame/machine/cdislave.c svneol=native#text/plain
|
|||||||
src/mame/machine/cdislave.h svneol=native#text/plain
|
src/mame/machine/cdislave.h svneol=native#text/plain
|
||||||
src/mame/machine/chaknpop.c svneol=native#text/plain
|
src/mame/machine/chaknpop.c svneol=native#text/plain
|
||||||
src/mame/machine/cps2crpt.c svneol=native#text/plain
|
src/mame/machine/cps2crpt.c svneol=native#text/plain
|
||||||
|
src/mame/machine/ctronics.c svneol=native#text/plain
|
||||||
|
src/mame/machine/ctronics.h svneol=native#text/plain
|
||||||
src/mame/machine/cx4data.c svneol=native#text/plain
|
src/mame/machine/cx4data.c svneol=native#text/plain
|
||||||
src/mame/machine/cx4fn.c svneol=native#text/plain
|
src/mame/machine/cx4fn.c svneol=native#text/plain
|
||||||
src/mame/machine/cx4oam.c svneol=native#text/plain
|
src/mame/machine/cx4oam.c svneol=native#text/plain
|
||||||
@ -3587,6 +3605,7 @@ src/mame/machine/cx4ops.c svneol=native#text/plain
|
|||||||
src/mame/machine/dc-ctrl.c svneol=native#text/plain
|
src/mame/machine/dc-ctrl.c svneol=native#text/plain
|
||||||
src/mame/machine/dc-ctrl.h svneol=native#text/plain
|
src/mame/machine/dc-ctrl.h svneol=native#text/plain
|
||||||
src/mame/machine/dc.c svneol=native#text/plain
|
src/mame/machine/dc.c svneol=native#text/plain
|
||||||
|
src/mame/machine/dccons.c svneol=native#text/plain
|
||||||
src/mame/machine/dec0.c svneol=native#text/plain
|
src/mame/machine/dec0.c svneol=native#text/plain
|
||||||
src/mame/machine/deco102.c svneol=native#text/plain
|
src/mame/machine/deco102.c svneol=native#text/plain
|
||||||
src/mame/machine/deco156.c svneol=native#text/plain
|
src/mame/machine/deco156.c svneol=native#text/plain
|
||||||
@ -3609,6 +3628,8 @@ src/mame/machine/gaelcrpt.c svneol=native#text/plain
|
|||||||
src/mame/machine/galaxold.c svneol=native#text/plain
|
src/mame/machine/galaxold.c svneol=native#text/plain
|
||||||
src/mame/machine/gaplus.c svneol=native#text/plain
|
src/mame/machine/gaplus.c svneol=native#text/plain
|
||||||
src/mame/machine/gdcrypt.c svneol=native#text/plain
|
src/mame/machine/gdcrypt.c svneol=native#text/plain
|
||||||
|
src/mame/machine/gdrom.c svneol=native#text/plain
|
||||||
|
src/mame/machine/gdrom.h svneol=native#text/plain
|
||||||
src/mame/machine/harddriv.c svneol=native#text/plain
|
src/mame/machine/harddriv.c svneol=native#text/plain
|
||||||
src/mame/machine/irem_cpu.c svneol=native#text/plain
|
src/mame/machine/irem_cpu.c svneol=native#text/plain
|
||||||
src/mame/machine/irem_cpu.h svneol=native#text/plain
|
src/mame/machine/irem_cpu.h svneol=native#text/plain
|
||||||
@ -3720,6 +3741,7 @@ src/mame/machine/segaic16.c svneol=native#text/plain
|
|||||||
src/mame/machine/segaic16.h svneol=native#text/plain
|
src/mame/machine/segaic16.h svneol=native#text/plain
|
||||||
src/mame/machine/segamsys.c svneol=native#text/plain
|
src/mame/machine/segamsys.c svneol=native#text/plain
|
||||||
src/mame/machine/segas32.c svneol=native#text/plain
|
src/mame/machine/segas32.c svneol=native#text/plain
|
||||||
|
src/mame/machine/segasms.c svneol=native#text/plain
|
||||||
src/mame/machine/seibuspi.c svneol=native#text/plain
|
src/mame/machine/seibuspi.c svneol=native#text/plain
|
||||||
src/mame/machine/seibuspi.h svneol=native#text/plain
|
src/mame/machine/seibuspi.h svneol=native#text/plain
|
||||||
src/mame/machine/seicop.c svneol=native#text/plain
|
src/mame/machine/seicop.c svneol=native#text/plain
|
||||||
@ -4342,6 +4364,8 @@ src/mame/video/skykid.c svneol=native#text/plain
|
|||||||
src/mame/video/skyraid.c svneol=native#text/plain
|
src/mame/video/skyraid.c svneol=native#text/plain
|
||||||
src/mame/video/slapfght.c svneol=native#text/plain
|
src/mame/video/slapfght.c svneol=native#text/plain
|
||||||
src/mame/video/slapshot.c svneol=native#text/plain
|
src/mame/video/slapshot.c svneol=native#text/plain
|
||||||
|
src/mame/video/smsvdp.c svneol=native#text/plain
|
||||||
|
src/mame/video/smsvdp.h svneol=native#text/plain
|
||||||
src/mame/video/snes.c svneol=native#text/plain
|
src/mame/video/snes.c svneol=native#text/plain
|
||||||
src/mame/video/snk.c svneol=native#text/plain
|
src/mame/video/snk.c svneol=native#text/plain
|
||||||
src/mame/video/snk6502.c svneol=native#text/plain
|
src/mame/video/snk6502.c svneol=native#text/plain
|
||||||
|
@ -44,6 +44,7 @@ OBJDIRS += \
|
|||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
|
|
||||||
EMUOBJS = \
|
EMUOBJS = \
|
||||||
|
$(EMUOBJ)/hashfile.o \
|
||||||
$(EMUOBJ)/addrmap.o \
|
$(EMUOBJ)/addrmap.o \
|
||||||
$(EMUOBJ)/attotime.o \
|
$(EMUOBJ)/attotime.o \
|
||||||
$(EMUOBJ)/audit.o \
|
$(EMUOBJ)/audit.o \
|
||||||
@ -204,6 +205,7 @@ EMUMACHINEOBJS = \
|
|||||||
$(EMUMACHINE)/msm5832.o \
|
$(EMUMACHINE)/msm5832.o \
|
||||||
$(EMUMACHINE)/msm58321.o \
|
$(EMUMACHINE)/msm58321.o \
|
||||||
$(EMUMACHINE)/msm6242.o \
|
$(EMUMACHINE)/msm6242.o \
|
||||||
|
$(EMUMACHINE)/msm8251.o \
|
||||||
$(EMUMACHINE)/nmc9306.o \
|
$(EMUMACHINE)/nmc9306.o \
|
||||||
$(EMUMACHINE)/nvram.o \
|
$(EMUMACHINE)/nvram.o \
|
||||||
$(EMUMACHINE)/pc16552d.o \
|
$(EMUMACHINE)/pc16552d.o \
|
||||||
@ -225,6 +227,7 @@ EMUMACHINEOBJS = \
|
|||||||
$(EMUMACHINE)/scsidev.o \
|
$(EMUMACHINE)/scsidev.o \
|
||||||
$(EMUMACHINE)/scsihd.o \
|
$(EMUMACHINE)/scsihd.o \
|
||||||
$(EMUMACHINE)/secflash.o \
|
$(EMUMACHINE)/secflash.o \
|
||||||
|
$(EMUMACHINE)/serial.o \
|
||||||
$(EMUMACHINE)/smc91c9x.o \
|
$(EMUMACHINE)/smc91c9x.o \
|
||||||
$(EMUMACHINE)/timekpr.o \
|
$(EMUMACHINE)/timekpr.o \
|
||||||
$(EMUMACHINE)/tmp68301.o \
|
$(EMUMACHINE)/tmp68301.o \
|
||||||
@ -232,6 +235,7 @@ EMUMACHINEOBJS = \
|
|||||||
$(EMUMACHINE)/upd1990a.o \
|
$(EMUMACHINE)/upd1990a.o \
|
||||||
$(EMUMACHINE)/upd4701.o \
|
$(EMUMACHINE)/upd4701.o \
|
||||||
$(EMUMACHINE)/upd7201.o \
|
$(EMUMACHINE)/upd7201.o \
|
||||||
|
$(EMUMACHINE)/upd765.o \
|
||||||
$(EMUMACHINE)/wd33c93.o \
|
$(EMUMACHINE)/wd33c93.o \
|
||||||
$(EMUMACHINE)/x2212.o \
|
$(EMUMACHINE)/x2212.o \
|
||||||
$(EMUMACHINE)/x76f041.o \
|
$(EMUMACHINE)/x76f041.o \
|
||||||
|
617
src/emu/hashfile.c
Normal file
617
src/emu/hashfile.c
Normal file
@ -0,0 +1,617 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
|
||||||
|
hashfile.c
|
||||||
|
|
||||||
|
Code for parsing hash info (*.hsi) files
|
||||||
|
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "hashfile.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "expat.h"
|
||||||
|
#include "emuopts.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
typedef struct _hash_info hash_info;
|
||||||
|
struct _hash_info
|
||||||
|
{
|
||||||
|
hash_collection *hashes;
|
||||||
|
const char *extrainfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _hash_file hash_file;
|
||||||
|
|
||||||
|
typedef void (*hashfile_error_func)(const char *message);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
FUNCTION PROTOTYPES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/* opens a hash file; if is_preload is non-zero, the entire file is preloaded */
|
||||||
|
hash_file *hashfile_open(emu_options &options, const char *sysname, int is_preload, hashfile_error_func error_proc);
|
||||||
|
|
||||||
|
/* closes a hash file and associated resources */
|
||||||
|
void hashfile_close(hash_file *hashfile);
|
||||||
|
|
||||||
|
/* looks up information in a hash file */
|
||||||
|
const hash_info *hashfile_lookup(hash_file *hashfile, const hash_collection *hashes);
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
struct _hash_file
|
||||||
|
{
|
||||||
|
emu_file *file;
|
||||||
|
object_pool *pool;
|
||||||
|
astring functions[IO_COUNT];
|
||||||
|
|
||||||
|
hash_info **preloaded_hashes;
|
||||||
|
int preloaded_hash_count;
|
||||||
|
|
||||||
|
void (*error_proc)(const char *message);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum hash_parse_position
|
||||||
|
{
|
||||||
|
HASH_POS_ROOT,
|
||||||
|
HASH_POS_MAIN,
|
||||||
|
HASH_POS_HASH
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct hash_parse_state
|
||||||
|
{
|
||||||
|
XML_Parser parser;
|
||||||
|
hash_file *hashfile;
|
||||||
|
int done;
|
||||||
|
|
||||||
|
int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const hash_collection *hashes);
|
||||||
|
void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi);
|
||||||
|
void (*error_proc)(const char *message);
|
||||||
|
void *param;
|
||||||
|
|
||||||
|
enum hash_parse_position pos;
|
||||||
|
char **text_dest;
|
||||||
|
hash_info *hi;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
PROTOTYPES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
static void *expat_malloc(size_t size);
|
||||||
|
static void *expat_realloc(void *ptr, size_t size);
|
||||||
|
static void expat_free(void *ptr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
CORE IMPLEMENTATION
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
parse_error
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void ATTR_PRINTF(2,3) parse_error(struct hash_parse_state *state, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
if (state->error_proc)
|
||||||
|
{
|
||||||
|
va_start(va, fmt);
|
||||||
|
vsnprintf(buf, ARRAY_LENGTH(buf), fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
(*state->error_proc)(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
unknown_tag
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void unknown_tag(struct hash_parse_state *state, const char *tagname)
|
||||||
|
{
|
||||||
|
parse_error(state, "[%lu:%lu]: Unknown tag: %s\n",
|
||||||
|
XML_GetCurrentLineNumber(state->parser),
|
||||||
|
XML_GetCurrentColumnNumber(state->parser),
|
||||||
|
tagname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
unknown_attribute
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void unknown_attribute(struct hash_parse_state *state, const char *attrname)
|
||||||
|
{
|
||||||
|
parse_error(state, "[%lu:%lu]: Unknown attribute: %s\n",
|
||||||
|
XML_GetCurrentLineNumber(state->parser),
|
||||||
|
XML_GetCurrentColumnNumber(state->parser),
|
||||||
|
attrname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
unknown_attribute_value
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void unknown_attribute_value(struct hash_parse_state *state,
|
||||||
|
const char *attrname, const char *attrvalue)
|
||||||
|
{
|
||||||
|
parse_error(state, "[%lu:%lu]: Unknown attribute value: %s\n",
|
||||||
|
XML_GetCurrentLineNumber(state->parser),
|
||||||
|
XML_GetCurrentColumnNumber(state->parser),
|
||||||
|
attrvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
start_handler
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void start_handler(void *data, const char *tagname, const char **attributes)
|
||||||
|
{
|
||||||
|
struct hash_parse_state *state = (struct hash_parse_state *) data;
|
||||||
|
const char *name;
|
||||||
|
hash_info *hi;
|
||||||
|
char **text_dest;
|
||||||
|
hash_collection hashes;
|
||||||
|
astring all_functions;
|
||||||
|
char functions;
|
||||||
|
iodevice_t device;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
switch(state->pos)
|
||||||
|
{
|
||||||
|
case HASH_POS_ROOT:
|
||||||
|
if (!strcmp(tagname, "hashfile"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unknown_tag(state, tagname);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HASH_POS_MAIN:
|
||||||
|
if (!strcmp(tagname, "hash"))
|
||||||
|
{
|
||||||
|
// we are now examining a hash tag
|
||||||
|
name = NULL;
|
||||||
|
device = IO_COUNT;
|
||||||
|
|
||||||
|
while(attributes[0])
|
||||||
|
{
|
||||||
|
functions = 0;
|
||||||
|
if (!strcmp(attributes[0], "name"))
|
||||||
|
{
|
||||||
|
/* name attribute */
|
||||||
|
name = attributes[1];
|
||||||
|
}
|
||||||
|
else if (!strcmp(attributes[0], "crc32"))
|
||||||
|
{
|
||||||
|
/* crc32 attribute */
|
||||||
|
functions = hash_collection::HASH_CRC;
|
||||||
|
}
|
||||||
|
else if (!strcmp(attributes[0], "md5"))
|
||||||
|
{
|
||||||
|
/* md5 attribute */
|
||||||
|
functions = hash_collection::HASH_MD5;
|
||||||
|
}
|
||||||
|
else if (!strcmp(attributes[0], "sha1"))
|
||||||
|
{
|
||||||
|
/* sha1 attribute */
|
||||||
|
functions = hash_collection::HASH_SHA1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(attributes[0], "type"))
|
||||||
|
{
|
||||||
|
/* type attribute */
|
||||||
|
i = 0;//device_typeid(attributes[1]);
|
||||||
|
if (i < 0)
|
||||||
|
unknown_attribute_value(state, attributes[0], attributes[1]);
|
||||||
|
else
|
||||||
|
device = (iodevice_t) i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* unknown attribute */
|
||||||
|
unknown_attribute(state, attributes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functions)
|
||||||
|
{
|
||||||
|
hashes.add_from_string(functions, attributes[1], strlen(attributes[1]));
|
||||||
|
all_functions.cat(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do we use this hash? */
|
||||||
|
if (!state->selector_proc || state->selector_proc(state->hashfile, state->param, name, &hashes))
|
||||||
|
{
|
||||||
|
hi = (hash_info*)pool_malloc_lib(state->hashfile->pool, sizeof(hash_info));
|
||||||
|
if (!hi)
|
||||||
|
return;
|
||||||
|
memset(hi, 0, sizeof(*hi));
|
||||||
|
|
||||||
|
hi->hashes = &hashes;
|
||||||
|
state->hi = hi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unknown_tag(state, tagname);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HASH_POS_HASH:
|
||||||
|
text_dest = NULL;
|
||||||
|
|
||||||
|
if (!strcmp(tagname, "year")) {
|
||||||
|
}
|
||||||
|
else if (!strcmp(tagname, "manufacturer")){
|
||||||
|
}
|
||||||
|
else if (!strcmp(tagname, "status")){
|
||||||
|
}
|
||||||
|
else if (!strcmp(tagname, "pcb")){
|
||||||
|
}
|
||||||
|
else if (!strcmp(tagname, "extrainfo")) {
|
||||||
|
text_dest = (char **) &state->hi->extrainfo;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
unknown_tag(state, tagname);
|
||||||
|
|
||||||
|
if (text_dest && state->hi)
|
||||||
|
state->text_dest = text_dest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state->pos = (hash_parse_position) (state->pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
end_handler
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void end_handler(void *data, const char *name)
|
||||||
|
{
|
||||||
|
struct hash_parse_state *state = (struct hash_parse_state *) data;
|
||||||
|
state->text_dest = NULL;
|
||||||
|
|
||||||
|
state->pos = (hash_parse_position) (state->pos - 1);
|
||||||
|
switch(state->pos)
|
||||||
|
{
|
||||||
|
case HASH_POS_ROOT:
|
||||||
|
case HASH_POS_HASH:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HASH_POS_MAIN:
|
||||||
|
if (state->hi)
|
||||||
|
{
|
||||||
|
if (state->use_proc)
|
||||||
|
(*state->use_proc)(state->hashfile, state->param, state->hi);
|
||||||
|
state->hi = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
data_handler
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void data_handler(void *data, const XML_Char *s, int len)
|
||||||
|
{
|
||||||
|
struct hash_parse_state *state = (struct hash_parse_state *) data;
|
||||||
|
int text_len;
|
||||||
|
char *text;
|
||||||
|
|
||||||
|
if (state->text_dest)
|
||||||
|
{
|
||||||
|
text = *state->text_dest;
|
||||||
|
|
||||||
|
text_len = text ? strlen(text) : 0;
|
||||||
|
text = (char*)pool_realloc_lib(state->hashfile->pool, text, text_len + len + 1);
|
||||||
|
if (!text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memcpy(&text[text_len], s, len);
|
||||||
|
text[text_len + len] = '\0';
|
||||||
|
*state->text_dest = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
hashfile_parse
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void hashfile_parse(hash_file *hashfile,
|
||||||
|
int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const hash_collection *hashes),
|
||||||
|
void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi),
|
||||||
|
void (*error_proc)(const char *message),
|
||||||
|
void *param)
|
||||||
|
{
|
||||||
|
struct hash_parse_state state;
|
||||||
|
char buf[1024];
|
||||||
|
UINT32 len;
|
||||||
|
XML_Memory_Handling_Suite memcallbacks;
|
||||||
|
|
||||||
|
hashfile->file->seek(0, SEEK_SET);
|
||||||
|
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
state.hashfile = hashfile;
|
||||||
|
state.selector_proc = selector_proc;
|
||||||
|
state.use_proc = use_proc;
|
||||||
|
state.error_proc = error_proc;
|
||||||
|
state.param = param;
|
||||||
|
|
||||||
|
/* create the XML parser */
|
||||||
|
memcallbacks.malloc_fcn = expat_malloc;
|
||||||
|
memcallbacks.realloc_fcn = expat_realloc;
|
||||||
|
memcallbacks.free_fcn = expat_free;
|
||||||
|
state.parser = XML_ParserCreate_MM(NULL, &memcallbacks, NULL);
|
||||||
|
if (!state.parser)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
XML_SetUserData(state.parser, &state);
|
||||||
|
XML_SetElementHandler(state.parser, start_handler, end_handler);
|
||||||
|
XML_SetCharacterDataHandler(state.parser, data_handler);
|
||||||
|
|
||||||
|
while(!state.done)
|
||||||
|
{
|
||||||
|
len = hashfile->file->read(buf, sizeof(buf));
|
||||||
|
state.done = hashfile->file->eof();
|
||||||
|
if (XML_Parse(state.parser, buf, len, state.done) == XML_STATUS_ERROR)
|
||||||
|
{
|
||||||
|
parse_error(&state, "[%lu:%lu]: %s\n",
|
||||||
|
XML_GetCurrentLineNumber(state.parser),
|
||||||
|
XML_GetCurrentColumnNumber(state.parser),
|
||||||
|
XML_ErrorString(XML_GetErrorCode(state.parser)));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (state.parser)
|
||||||
|
XML_ParserFree(state.parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
preload_use_proc
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void preload_use_proc(hash_file *hashfile, void *param, hash_info *hi)
|
||||||
|
{
|
||||||
|
hash_info **new_preloaded_hashes;
|
||||||
|
|
||||||
|
new_preloaded_hashes = (hash_info **)pool_realloc_lib(hashfile->pool, hashfile->preloaded_hashes,
|
||||||
|
(hashfile->preloaded_hash_count + 1) * sizeof(*new_preloaded_hashes));
|
||||||
|
if (!new_preloaded_hashes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hashfile->preloaded_hashes = new_preloaded_hashes;
|
||||||
|
hashfile->preloaded_hashes[hashfile->preloaded_hash_count++] = hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
hashfile_open
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
hash_file *hashfile_open(emu_options &options, const char *sysname, int is_preload,
|
||||||
|
void (*error_proc)(const char *message))
|
||||||
|
{
|
||||||
|
hash_file *hashfile = NULL;
|
||||||
|
object_pool *pool = NULL;
|
||||||
|
file_error filerr;
|
||||||
|
|
||||||
|
/* create a pool for this hash file */
|
||||||
|
pool = pool_alloc_lib(error_proc);
|
||||||
|
if (!pool)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* allocate space for this hash file */
|
||||||
|
hashfile = (hash_file *) pool_malloc_lib(pool, sizeof(*hashfile));
|
||||||
|
if (!hashfile)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* set up the hashfile structure */
|
||||||
|
memset(hashfile, 0, sizeof(*hashfile));
|
||||||
|
hashfile->pool = pool;
|
||||||
|
hashfile->error_proc = error_proc;
|
||||||
|
|
||||||
|
/* open a file */
|
||||||
|
hashfile->file = global_alloc(emu_file(options.hash_path(), OPEN_FLAG_READ));
|
||||||
|
filerr = hashfile->file->open(sysname, ".hsi");
|
||||||
|
if (filerr != FILERR_NONE)
|
||||||
|
{
|
||||||
|
global_free(hashfile->file);
|
||||||
|
hashfile->file = NULL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_preload)
|
||||||
|
hashfile_parse(hashfile, NULL, preload_use_proc, hashfile->error_proc, NULL);
|
||||||
|
|
||||||
|
return hashfile;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (hashfile != NULL)
|
||||||
|
hashfile_close(hashfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
hashfile_close
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void hashfile_close(hash_file *hashfile)
|
||||||
|
{
|
||||||
|
global_free(hashfile->file);
|
||||||
|
pool_free_lib(hashfile->pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
singular_selector_proc
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
struct hashlookup_params
|
||||||
|
{
|
||||||
|
const hash_collection *hashes;
|
||||||
|
hash_info *hi;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int singular_selector_proc(hash_file *hashfile, void *param, const char *name, const hash_collection *hashes)
|
||||||
|
{
|
||||||
|
astring tempstr;
|
||||||
|
struct hashlookup_params *hlparams = (struct hashlookup_params *) param;
|
||||||
|
return (*hashes == *hlparams->hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
singular_use_proc
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void singular_use_proc(hash_file *hashfile, void *param, hash_info *hi)
|
||||||
|
{
|
||||||
|
struct hashlookup_params *hlparams = (struct hashlookup_params *) param;
|
||||||
|
hlparams->hi = hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
hashfile_lookup
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
const hash_info *hashfile_lookup(hash_file *hashfile, const hash_collection *hashes)
|
||||||
|
{
|
||||||
|
struct hashlookup_params param;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
param.hashes = hashes;
|
||||||
|
param.hi = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < hashfile->preloaded_hash_count; i++)
|
||||||
|
{
|
||||||
|
if (singular_selector_proc(hashfile, ¶m, NULL, hashfile->preloaded_hashes[i]->hashes))
|
||||||
|
return hashfile->preloaded_hashes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
hashfile_parse(hashfile, singular_selector_proc, singular_use_proc,
|
||||||
|
hashfile->error_proc, (void *) ¶m);
|
||||||
|
return param.hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *extra_info = NULL;
|
||||||
|
|
||||||
|
const char *read_hash_config(device_image_interface &image, const char *sysname)
|
||||||
|
{
|
||||||
|
hash_file *hashfile = NULL;
|
||||||
|
const hash_info *info = NULL;
|
||||||
|
|
||||||
|
/* open the hash file */
|
||||||
|
hashfile = hashfile_open(image.device().machine().options(), sysname, FALSE, NULL);
|
||||||
|
if (!hashfile)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* look up this entry in the hash file */
|
||||||
|
info = hashfile_lookup(hashfile, &image.hash());
|
||||||
|
|
||||||
|
if (!info || !info->extrainfo)
|
||||||
|
{
|
||||||
|
hashfile_close(hashfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
extra_info = auto_strdup(image.device().machine(),info->extrainfo);
|
||||||
|
if (!extra_info)
|
||||||
|
{
|
||||||
|
hashfile_close(hashfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy the relevant entries */
|
||||||
|
hashfile_close(hashfile);
|
||||||
|
|
||||||
|
return extra_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *hashfile_extrainfo(device_image_interface &image)
|
||||||
|
{
|
||||||
|
const char *rc;
|
||||||
|
|
||||||
|
/* now read the hash file */
|
||||||
|
image.crc();
|
||||||
|
extra_info = NULL;
|
||||||
|
int drv = driver_list::find(image.device().machine().system());
|
||||||
|
do
|
||||||
|
{
|
||||||
|
rc = read_hash_config(image,driver_list::driver(drv).name);
|
||||||
|
drv = driver_list::compatible_with(drv);
|
||||||
|
}
|
||||||
|
while(rc!=NULL && drv != -1);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
EXPAT INTERFACES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
expat_malloc/expat_realloc/expat_free -
|
||||||
|
wrappers for memory allocation functions so
|
||||||
|
that they pass through out memory tracking
|
||||||
|
systems
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void *expat_malloc(size_t size)
|
||||||
|
{
|
||||||
|
return global_alloc_array_clear(UINT8,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *expat_realloc(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
if (ptr) global_free(ptr);
|
||||||
|
return global_alloc_array_clear(UINT8,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expat_free(void *ptr)
|
||||||
|
{
|
||||||
|
global_free(ptr);
|
||||||
|
}
|
17
src/emu/hashfile.h
Normal file
17
src/emu/hashfile.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
|
||||||
|
hashfile.h
|
||||||
|
|
||||||
|
Code for parsing hash info (*.hsi) files
|
||||||
|
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef __HASHFILE_H__
|
||||||
|
#define __HASHFILE_H__
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
|
||||||
|
|
||||||
|
const char *hashfile_extrainfo(device_image_interface &image);
|
||||||
|
|
||||||
|
#endif /* __HASHFILE_H__ */
|
825
src/emu/machine/msm8251.c
Normal file
825
src/emu/machine/msm8251.c
Normal file
@ -0,0 +1,825 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
|
||||||
|
msm8251.c
|
||||||
|
|
||||||
|
MSM/Intel 8251 Universal Synchronous/Asynchronous Receiver Transmitter code
|
||||||
|
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
#include "msm8251.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
MACROS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#define VERBOSE 0
|
||||||
|
|
||||||
|
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
typedef struct _msm8251_t msm8251_t;
|
||||||
|
struct _msm8251_t
|
||||||
|
{
|
||||||
|
devcb_resolved_read_line in_rxd_func;
|
||||||
|
devcb_resolved_write_line out_txd_func;
|
||||||
|
devcb_resolved_read_line in_dsr_func;
|
||||||
|
devcb_resolved_write_line out_dtr_func;
|
||||||
|
devcb_resolved_write_line out_rts_func;
|
||||||
|
devcb_resolved_write_line out_rxrdy_func;
|
||||||
|
devcb_resolved_write_line out_txrdy_func;
|
||||||
|
devcb_resolved_write_line out_txempty_func;
|
||||||
|
devcb_resolved_write_line out_syndet_func;
|
||||||
|
|
||||||
|
/* flags controlling how msm8251_control_w operates */
|
||||||
|
UINT8 flags;
|
||||||
|
/* offset into sync_bytes used during sync byte transfer */
|
||||||
|
UINT8 sync_byte_offset;
|
||||||
|
/* number of sync bytes written so far */
|
||||||
|
UINT8 sync_byte_count;
|
||||||
|
/* the sync bytes written */
|
||||||
|
UINT8 sync_bytes[2];
|
||||||
|
/* status of msm8251 */
|
||||||
|
UINT8 status;
|
||||||
|
UINT8 command;
|
||||||
|
/* mode byte - bit definitions depend on mode - e.g. synchronous, asynchronous */
|
||||||
|
UINT8 mode_byte;
|
||||||
|
|
||||||
|
/* data being received */
|
||||||
|
UINT8 data;
|
||||||
|
|
||||||
|
/* receive reg */
|
||||||
|
serial_receive_register receive_reg;
|
||||||
|
/* transmit reg */
|
||||||
|
serial_transmit_register transmit_reg;
|
||||||
|
|
||||||
|
data_form form;
|
||||||
|
|
||||||
|
/* the serial connection that data is transfered over */
|
||||||
|
/* this is usually connected to the serial device */
|
||||||
|
serial_connection connection;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
PROTOTYPES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
static void msm8251_in_callback(running_machine &machine, int id, unsigned long state);
|
||||||
|
static void msm8251_update_tx_empty(device_t *device);
|
||||||
|
static void msm8251_update_tx_ready(device_t *device);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
INLINE FUNCTIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
INLINE msm8251_t *get_token(device_t *device)
|
||||||
|
{
|
||||||
|
assert(device != NULL);
|
||||||
|
assert(device->type() == MSM8251);
|
||||||
|
|
||||||
|
return (msm8251_t *) downcast<legacy_device_base *>(device)->token();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
INLINE const msm8251_interface *get_interface(device_t *device)
|
||||||
|
{
|
||||||
|
assert(device != NULL);
|
||||||
|
assert(device->type() == MSM8251);
|
||||||
|
|
||||||
|
return (const msm8251_interface *) device->static_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
GLOBAL VARIABLES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
const msm8251_interface default_msm8251_interface = { DEVCB_NULL, };
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
IMPLEMENTATION
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_in_callback
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void msm8251_in_callback(running_machine &machine, int id, unsigned long state)
|
||||||
|
{
|
||||||
|
device_t *device;
|
||||||
|
msm8251_t *uart;
|
||||||
|
int changed;
|
||||||
|
|
||||||
|
/* NPW 29-Nov-2008 - These two lines are a hack and indicate why our "serial" infrastructure needs to be updated */
|
||||||
|
device = machine.device("uart");
|
||||||
|
uart = get_token(device);
|
||||||
|
|
||||||
|
changed = uart->connection.input_state^state;
|
||||||
|
|
||||||
|
uart->connection.input_state = state;
|
||||||
|
|
||||||
|
/* did cts change state? */
|
||||||
|
if (changed & SERIAL_STATE_CTS)
|
||||||
|
{
|
||||||
|
/* yes */
|
||||||
|
/* update tx ready */
|
||||||
|
/* msm8251_update_tx_ready(device); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
DEVICE_START( msm8251 )
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static DEVICE_START( msm8251 )
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
const msm8251_interface *intf = get_interface(device);
|
||||||
|
|
||||||
|
serial_helper_setup();
|
||||||
|
|
||||||
|
// resolve callbacks
|
||||||
|
uart->out_rxrdy_func.resolve(intf->out_rxrdy_func, *device);
|
||||||
|
uart->out_txrdy_func.resolve(intf->out_txrdy_func, *device);
|
||||||
|
uart->out_txempty_func.resolve(intf->out_txempty_func, *device);
|
||||||
|
|
||||||
|
/* setup this side of the serial connection */
|
||||||
|
serial_connection_init(device->machine(),&uart->connection);
|
||||||
|
serial_connection_set_in_callback(device->machine(),&uart->connection, msm8251_in_callback);
|
||||||
|
uart->connection.input_state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_update_rx_ready
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void msm8251_update_rx_ready(device_t *device)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
int state;
|
||||||
|
|
||||||
|
state = uart->status & MSM8251_STATUS_RX_READY;
|
||||||
|
|
||||||
|
/* masked? */
|
||||||
|
if ((uart->command & (1<<2))==0)
|
||||||
|
{
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart->out_rxrdy_func(state != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_receive_clock
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void msm8251_receive_clock(device_t *device)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
/* receive enable? */
|
||||||
|
if (uart->command & (1<<2))
|
||||||
|
{
|
||||||
|
//logerror("MSM8251\n");
|
||||||
|
/* get bit received from other side and update receive register */
|
||||||
|
receive_register_update_bit(&uart->receive_reg, get_in_data_bit(uart->connection.input_state));
|
||||||
|
|
||||||
|
if (uart->receive_reg.flags & RECEIVE_REGISTER_FULL)
|
||||||
|
{
|
||||||
|
receive_register_extract(&uart->receive_reg, &uart->form);
|
||||||
|
msm8251_receive_character(device, uart->receive_reg.byte_received);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_transmit_clock
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void msm8251_transmit_clock(device_t *device)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
/* transmit enable? */
|
||||||
|
if (uart->command & (1<<0))
|
||||||
|
{
|
||||||
|
|
||||||
|
/* transmit register full? */
|
||||||
|
if ((uart->status & MSM8251_STATUS_TX_READY)==0)
|
||||||
|
{
|
||||||
|
/* if transmit reg is empty */
|
||||||
|
if ((uart->transmit_reg.flags & TRANSMIT_REGISTER_EMPTY)!=0)
|
||||||
|
{
|
||||||
|
/* set it up */
|
||||||
|
transmit_register_setup(&uart->transmit_reg, &uart->form, uart->data);
|
||||||
|
/* msm8251 transmit reg now empty */
|
||||||
|
uart->status |=MSM8251_STATUS_TX_EMPTY;
|
||||||
|
/* ready for next transmit */
|
||||||
|
uart->status |=MSM8251_STATUS_TX_READY;
|
||||||
|
|
||||||
|
msm8251_update_tx_empty(device);
|
||||||
|
msm8251_update_tx_ready(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if transmit is not empty... transmit data */
|
||||||
|
if ((uart->transmit_reg.flags & TRANSMIT_REGISTER_EMPTY)==0)
|
||||||
|
{
|
||||||
|
// logerror("MSM8251\n");
|
||||||
|
transmit_register_send_bit(device->machine(),&uart->transmit_reg, &uart->connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* hunt mode? */
|
||||||
|
/* after each bit has been shifted in, it is compared against the current sync byte */
|
||||||
|
if (uart->command & (1<<7))
|
||||||
|
{
|
||||||
|
/* data matches sync byte? */
|
||||||
|
if (uart->data == uart->sync_bytes[uart->sync_byte_offset])
|
||||||
|
{
|
||||||
|
/* sync byte matches */
|
||||||
|
/* update for next sync byte? */
|
||||||
|
uart->sync_byte_offset++;
|
||||||
|
|
||||||
|
/* do all sync bytes match? */
|
||||||
|
if (uart->sync_byte_offset == uart->sync_byte_count)
|
||||||
|
{
|
||||||
|
/* ent hunt mode */
|
||||||
|
uart->command &=~(1<<7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* if there is no match, reset */
|
||||||
|
uart->sync_byte_offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_update_tx_ready
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void msm8251_update_tx_ready(device_t *device)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
/* clear tx ready state */
|
||||||
|
int tx_ready;
|
||||||
|
|
||||||
|
/* tx ready output is set if:
|
||||||
|
DB Buffer Empty &
|
||||||
|
CTS is set &
|
||||||
|
Transmit enable is 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
tx_ready = 0;
|
||||||
|
|
||||||
|
/* transmit enable? */
|
||||||
|
if ((uart->command & (1<<0))!=0)
|
||||||
|
{
|
||||||
|
/* other side has rts set (comes in as CTS at this side) */
|
||||||
|
if (uart->connection.input_state & SERIAL_STATE_CTS)
|
||||||
|
{
|
||||||
|
if (uart->status & MSM8251_STATUS_TX_EMPTY)
|
||||||
|
{
|
||||||
|
/* enable transfer */
|
||||||
|
tx_ready = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uart->out_txrdy_func(tx_ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_update_tx_empty
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void msm8251_update_tx_empty(device_t *device)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
if (uart->status & MSM8251_STATUS_TX_EMPTY)
|
||||||
|
{
|
||||||
|
/* tx is in marking state (high) when tx empty! */
|
||||||
|
set_out_data_bit(uart->connection.State, 1);
|
||||||
|
serial_connection_out(device->machine(),&uart->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
uart->out_txempty_func((uart->status & MSM8251_STATUS_TX_EMPTY) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
DEVICE_RESET( msm8251 )
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static DEVICE_RESET( msm8251 )
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
LOG(("MSM8251: Reset\n"));
|
||||||
|
|
||||||
|
/* what is the default setup when the 8251 has been reset??? */
|
||||||
|
|
||||||
|
/* msm8251 datasheet explains the state of tx pin at reset */
|
||||||
|
/* tx is set to 1 */
|
||||||
|
set_out_data_bit(uart->connection.State,1);
|
||||||
|
|
||||||
|
/* assumption, rts is set to 1 */
|
||||||
|
uart->connection.State &= ~SERIAL_STATE_RTS;
|
||||||
|
serial_connection_out(device->machine(), &uart->connection);
|
||||||
|
|
||||||
|
transmit_register_reset(&uart->transmit_reg);
|
||||||
|
receive_register_reset(&uart->receive_reg);
|
||||||
|
/* expecting mode byte */
|
||||||
|
uart->flags |= MSM8251_EXPECTING_MODE;
|
||||||
|
/* not expecting a sync byte */
|
||||||
|
uart->flags &= ~MSM8251_EXPECTING_SYNC_BYTE;
|
||||||
|
|
||||||
|
/* no character to read by cpu */
|
||||||
|
/* transmitter is ready and is empty */
|
||||||
|
uart->status = MSM8251_STATUS_TX_EMPTY | MSM8251_STATUS_TX_READY;
|
||||||
|
uart->mode_byte = 0;
|
||||||
|
uart->command = 0;
|
||||||
|
|
||||||
|
/* update tx empty pin output */
|
||||||
|
msm8251_update_tx_empty(device);
|
||||||
|
/* update rx ready pin output */
|
||||||
|
msm8251_update_rx_ready(device);
|
||||||
|
/* update tx ready pin output */
|
||||||
|
msm8251_update_tx_ready(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
WRITE8_DEVICE_HANDLER(msm8251_control_w)
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
WRITE8_DEVICE_HANDLER(msm8251_control_w)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
if (uart->flags & MSM8251_EXPECTING_MODE)
|
||||||
|
{
|
||||||
|
if (uart->flags & MSM8251_EXPECTING_SYNC_BYTE)
|
||||||
|
{
|
||||||
|
LOG(("MSM8251: Sync byte\n"));
|
||||||
|
|
||||||
|
LOG(("Sync byte: %02x\n", data));
|
||||||
|
/* store sync byte written */
|
||||||
|
uart->sync_bytes[uart->sync_byte_offset] = data;
|
||||||
|
uart->sync_byte_offset++;
|
||||||
|
|
||||||
|
if (uart->sync_byte_offset == uart->sync_byte_count)
|
||||||
|
{
|
||||||
|
/* finished transfering sync bytes, now expecting command */
|
||||||
|
uart->flags &= ~(MSM8251_EXPECTING_MODE | MSM8251_EXPECTING_SYNC_BYTE);
|
||||||
|
uart->sync_byte_offset = 0;
|
||||||
|
// uart->status = MSM8251_STATUS_TX_EMPTY | MSM8251_STATUS_TX_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(("MSM8251: Mode byte\n"));
|
||||||
|
|
||||||
|
uart->mode_byte = data;
|
||||||
|
|
||||||
|
/* Synchronous or Asynchronous? */
|
||||||
|
if ((data & 0x03)!=0)
|
||||||
|
{
|
||||||
|
/* Asynchronous
|
||||||
|
|
||||||
|
bit 7,6: stop bit length
|
||||||
|
0 = inhibit
|
||||||
|
1 = 1 bit
|
||||||
|
2 = 1.5 bits
|
||||||
|
3 = 2 bits
|
||||||
|
bit 5: parity type
|
||||||
|
0 = parity odd
|
||||||
|
1 = parity even
|
||||||
|
bit 4: parity test enable
|
||||||
|
0 = disable
|
||||||
|
1 = enable
|
||||||
|
bit 3,2: character length
|
||||||
|
0 = 5 bits
|
||||||
|
1 = 6 bits
|
||||||
|
2 = 7 bits
|
||||||
|
3 = 8 bits
|
||||||
|
bit 1,0: baud rate factor
|
||||||
|
0 = defines command byte for synchronous or asynchronous
|
||||||
|
1 = x1
|
||||||
|
2 = x16
|
||||||
|
3 = x64
|
||||||
|
*/
|
||||||
|
|
||||||
|
LOG(("MSM8251: Asynchronous operation\n"));
|
||||||
|
|
||||||
|
LOG(("Character length: %d\n", (((data>>2) & 0x03)+5)));
|
||||||
|
|
||||||
|
if (data & (1<<4))
|
||||||
|
{
|
||||||
|
LOG(("enable parity checking\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(("parity check disabled\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data & (1<<5))
|
||||||
|
{
|
||||||
|
LOG(("even parity\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(("odd parity\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
UINT8 stop_bit_length;
|
||||||
|
|
||||||
|
stop_bit_length = (data>>6) & 0x03;
|
||||||
|
|
||||||
|
switch (stop_bit_length)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
/* inhibit */
|
||||||
|
LOG(("stop bit: inhibit\n"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
/* 1 */
|
||||||
|
LOG(("stop bit: 1 bit\n"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
/* 1.5 */
|
||||||
|
LOG(("stop bit: 1.5 bits\n"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
/* 2 */
|
||||||
|
LOG(("stop bit: 2 bits\n"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uart->form.word_length = ((data>>2) & 0x03)+5;
|
||||||
|
uart->form.parity = SERIAL_PARITY_NONE;
|
||||||
|
switch ((data>>6) & 0x03)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
uart->form.stop_bit_count = 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
uart->form.stop_bit_count = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
receive_register_setup(&uart->receive_reg, &uart->form);
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* data bits */
|
||||||
|
uart->receive_char_length = (((data>>2) & 0x03)+5);
|
||||||
|
|
||||||
|
if (data & (1<<4))
|
||||||
|
{
|
||||||
|
/* parity */
|
||||||
|
uart->receive_char_length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stop bits */
|
||||||
|
uart->receive_char_length++;
|
||||||
|
|
||||||
|
uart->receive_flags &=~MSM8251_TRANSFER_RECEIVE_SYNCHRONISED;
|
||||||
|
uart->receive_flags |= MSM8251_TRANSFER_RECEIVE_WAITING_FOR_START_BIT;
|
||||||
|
#endif
|
||||||
|
/* not expecting mode byte now */
|
||||||
|
uart->flags &= ~MSM8251_EXPECTING_MODE;
|
||||||
|
// uart->status = MSM8251_STATUS_TX_EMPTY | MSM8251_STATUS_TX_READY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* bit 7: Number of sync characters
|
||||||
|
0 = 1 character
|
||||||
|
1 = 2 character
|
||||||
|
bit 6: Synchronous mode
|
||||||
|
0 = Internal synchronisation
|
||||||
|
1 = External synchronisation
|
||||||
|
bit 5: parity type
|
||||||
|
0 = parity odd
|
||||||
|
1 = parity even
|
||||||
|
bit 4: parity test enable
|
||||||
|
0 = disable
|
||||||
|
1 = enable
|
||||||
|
bit 3,2: character length
|
||||||
|
0 = 5 bits
|
||||||
|
1 = 6 bits
|
||||||
|
2 = 7 bits
|
||||||
|
3 = 8 bits
|
||||||
|
bit 1,0 = 0
|
||||||
|
*/
|
||||||
|
LOG(("MSM8251: Synchronous operation\n"));
|
||||||
|
|
||||||
|
/* setup for sync byte(s) */
|
||||||
|
uart->flags |= MSM8251_EXPECTING_SYNC_BYTE;
|
||||||
|
uart->sync_byte_offset = 0;
|
||||||
|
if (data & 0x07)
|
||||||
|
{
|
||||||
|
uart->sync_byte_count = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uart->sync_byte_count = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* command */
|
||||||
|
LOG(("MSM8251: Command byte\n"));
|
||||||
|
|
||||||
|
uart->command = data;
|
||||||
|
|
||||||
|
LOG(("Command byte: %02x\n", data));
|
||||||
|
|
||||||
|
if (data & (1<<7))
|
||||||
|
{
|
||||||
|
LOG(("hunt mode\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data & (1<<5))
|
||||||
|
{
|
||||||
|
LOG(("/rts set to 0\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(("/rts set to 1\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data & (1<<2))
|
||||||
|
{
|
||||||
|
LOG(("receive enable\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(("receive disable\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data & (1<<1))
|
||||||
|
{
|
||||||
|
LOG(("/dtr set to 0\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(("/dtr set to 1\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data & (1<<0))
|
||||||
|
{
|
||||||
|
LOG(("transmit enable\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(("transmit disable\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* bit 7:
|
||||||
|
0 = normal operation
|
||||||
|
1 = hunt mode
|
||||||
|
bit 6:
|
||||||
|
0 = normal operation
|
||||||
|
1 = internal reset
|
||||||
|
bit 5:
|
||||||
|
0 = /RTS set to 1
|
||||||
|
1 = /RTS set to 0
|
||||||
|
bit 4:
|
||||||
|
0 = normal operation
|
||||||
|
1 = reset error flag
|
||||||
|
bit 3:
|
||||||
|
0 = normal operation
|
||||||
|
1 = send break character
|
||||||
|
bit 2:
|
||||||
|
0 = receive disable
|
||||||
|
1 = receive enable
|
||||||
|
bit 1:
|
||||||
|
0 = /DTR set to 1
|
||||||
|
1 = /DTR set to 0
|
||||||
|
bit 0:
|
||||||
|
0 = transmit disable
|
||||||
|
1 = transmit enable
|
||||||
|
*/
|
||||||
|
|
||||||
|
uart->connection.State &=~SERIAL_STATE_RTS;
|
||||||
|
if (data & (1<<5))
|
||||||
|
{
|
||||||
|
/* rts set to 0 */
|
||||||
|
uart->connection.State |= SERIAL_STATE_RTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart->connection.State &=~SERIAL_STATE_DTR;
|
||||||
|
if (data & (1<<1))
|
||||||
|
{
|
||||||
|
uart->connection.State |= SERIAL_STATE_DTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((data & (1<<0))==0)
|
||||||
|
{
|
||||||
|
/* held in high state when transmit disable */
|
||||||
|
set_out_data_bit(uart->connection.State,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* refresh outputs */
|
||||||
|
serial_connection_out(device->machine(), &uart->connection);
|
||||||
|
|
||||||
|
if (data & (1<<4))
|
||||||
|
{
|
||||||
|
uart->status &= ~(MSM8251_STATUS_PARITY_ERROR | MSM8251_STATUS_OVERRUN_ERROR | MSM8251_STATUS_FRAMING_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data & (1<<6))
|
||||||
|
{
|
||||||
|
device->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
msm8251_update_rx_ready(device);
|
||||||
|
msm8251_update_tx_ready(device);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
READ8_DEVICE_HANDLER(msm8251_status_r)
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ8_DEVICE_HANDLER(msm8251_status_r)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
LOG(("status: %02x\n", uart->status));
|
||||||
|
return uart->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
WRITE8_DEVICE_HANDLER(msm8251_data_w)
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
WRITE8_DEVICE_HANDLER(msm8251_data_w)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
uart->data = data;
|
||||||
|
|
||||||
|
logerror("write data: %02x\n",data);
|
||||||
|
|
||||||
|
/* writing clears */
|
||||||
|
uart->status &=~MSM8251_STATUS_TX_READY;
|
||||||
|
|
||||||
|
/* if transmitter is active, then tx empty will be signalled */
|
||||||
|
|
||||||
|
msm8251_update_tx_ready(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_receive_character - called when last
|
||||||
|
bit of data has been received
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void msm8251_receive_character(device_t *device, UINT8 ch)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
logerror("msm8251 receive char: %02x\n",ch);
|
||||||
|
|
||||||
|
uart->data = ch;
|
||||||
|
|
||||||
|
/* char has not been read and another has arrived! */
|
||||||
|
if (uart->status & MSM8251_STATUS_RX_READY)
|
||||||
|
{
|
||||||
|
uart->status |= MSM8251_STATUS_OVERRUN_ERROR;
|
||||||
|
}
|
||||||
|
uart->status |= MSM8251_STATUS_RX_READY;
|
||||||
|
|
||||||
|
msm8251_update_rx_ready(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
READ8_DEVICE_HANDLER(msm8251_data_r) - read data
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ8_DEVICE_HANDLER(msm8251_data_r)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
|
||||||
|
logerror("read data: %02x, STATUS=%02x\n",uart->data,uart->status);
|
||||||
|
/* reading clears */
|
||||||
|
uart->status &= ~MSM8251_STATUS_RX_READY;
|
||||||
|
|
||||||
|
msm8251_update_rx_ready(device);
|
||||||
|
return uart->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_connect_to_serial_device - initialise
|
||||||
|
transfer using serial device - set the callback
|
||||||
|
which will be called when serial device has
|
||||||
|
updated it's state
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void msm8251_connect_to_serial_device(device_t *device, device_t *image)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
serial_device_connect(image, &uart->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
msm8251_connect
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void msm8251_connect(device_t *device, serial_connection *other_connection)
|
||||||
|
{
|
||||||
|
msm8251_t *uart = get_token(device);
|
||||||
|
serial_connection_link(device->machine(), &uart->connection, other_connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
DEVICE_GET_INFO( msm8251 )
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
DEVICE_GET_INFO( msm8251 )
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||||
|
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(msm8251_t); break;
|
||||||
|
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
|
||||||
|
|
||||||
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||||
|
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(msm8251); break;
|
||||||
|
case DEVINFO_FCT_STOP: /* Nothing */ break;
|
||||||
|
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(msm8251); break;
|
||||||
|
|
||||||
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||||
|
case DEVINFO_STR_NAME: strcpy(info->s, "Intel 8251 UART"); break;
|
||||||
|
case DEVINFO_STR_FAMILY: strcpy(info->s, "Intel 8251 UART"); break;
|
||||||
|
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
|
||||||
|
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||||
|
case DEVINFO_STR_CREDITS: /* Nothing */ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_LEGACY_DEVICE(MSM8251, msm8251);
|
88
src/emu/machine/msm8251.h
Normal file
88
src/emu/machine/msm8251.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
|
||||||
|
msm8251.h
|
||||||
|
|
||||||
|
MSM/Intel 8251 Universal Synchronous/Asynchronous Receiver Transmitter code
|
||||||
|
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef __MSM8251_H__
|
||||||
|
#define __MSM8251_H__
|
||||||
|
|
||||||
|
#include "machine/serial.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
CONSTANTS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
DECLARE_LEGACY_DEVICE(MSM8251, msm8251);
|
||||||
|
|
||||||
|
#define MSM8251_EXPECTING_MODE 0x01
|
||||||
|
#define MSM8251_EXPECTING_SYNC_BYTE 0x02
|
||||||
|
|
||||||
|
#define MSM8251_STATUS_FRAMING_ERROR 0x020
|
||||||
|
#define MSM8251_STATUS_OVERRUN_ERROR 0x010
|
||||||
|
#define MSM8251_STATUS_PARITY_ERROR 0x08
|
||||||
|
#define MSM8251_STATUS_TX_EMPTY 0x04
|
||||||
|
#define MSM8251_STATUS_RX_READY 0x02
|
||||||
|
#define MSM8251_STATUS_TX_READY 0x01
|
||||||
|
|
||||||
|
#define MCFG_MSM8251_ADD(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, MSM8251, 0) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_MSM8251_REMOVE(_tag) \
|
||||||
|
MCFG_DEVICE_REMOVE(_tag)
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
typedef struct _msm8251_interface msm8251_interface;
|
||||||
|
struct _msm8251_interface
|
||||||
|
{
|
||||||
|
devcb_read_line in_rxd_func;
|
||||||
|
devcb_write_line out_txd_func;
|
||||||
|
devcb_read_line in_dsr_func;
|
||||||
|
devcb_write_line out_dtr_func;
|
||||||
|
devcb_write_line out_rts_func;
|
||||||
|
devcb_write_line out_rxrdy_func;
|
||||||
|
devcb_write_line out_txrdy_func;
|
||||||
|
devcb_write_line out_txempty_func;
|
||||||
|
devcb_write_line out_syndet_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
PROTOTYPES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
extern const msm8251_interface default_msm8251_interface;
|
||||||
|
|
||||||
|
/* read data register */
|
||||||
|
READ8_DEVICE_HANDLER(msm8251_data_r);
|
||||||
|
|
||||||
|
/* read status register */
|
||||||
|
READ8_DEVICE_HANDLER(msm8251_status_r);
|
||||||
|
|
||||||
|
/* write data register */
|
||||||
|
WRITE8_DEVICE_HANDLER(msm8251_data_w);
|
||||||
|
|
||||||
|
/* write control word */
|
||||||
|
WRITE8_DEVICE_HANDLER(msm8251_control_w);
|
||||||
|
|
||||||
|
/* The 8251 has seperate transmit and receive clocks */
|
||||||
|
/* use these two functions to update the msm8251 for each clock */
|
||||||
|
/* on NC100 system, the clocks are the same */
|
||||||
|
void msm8251_transmit_clock(device_t *device);
|
||||||
|
void msm8251_receive_clock(device_t *device);
|
||||||
|
|
||||||
|
/* connecting to serial output */
|
||||||
|
void msm8251_connect_to_serial_device(device_t *device, device_t *image);
|
||||||
|
void msm8251_connect(device_t *device, serial_connection *other_connection);
|
||||||
|
|
||||||
|
void msm8251_receive_character(device_t *device, UINT8 ch);
|
||||||
|
|
||||||
|
#endif /* __MSM8251_H__ */
|
733
src/emu/machine/serial.c
Normal file
733
src/emu/machine/serial.c
Normal file
@ -0,0 +1,733 @@
|
|||||||
|
/* internal serial transmission */
|
||||||
|
|
||||||
|
/* select a file on host filesystem to transfer using serial method,
|
||||||
|
setup serial interface software in driver and let the transfer begin */
|
||||||
|
|
||||||
|
/* this is used in the Amstrad NC Notepad emulation */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
the output starts at 1 level. It changes to 0 when the start bit has been transmitted.
|
||||||
|
This therefore signals that data is following.
|
||||||
|
When all data bits have been received, stop bits are transmitted with a value of 1.
|
||||||
|
|
||||||
|
msm8251 expects this in asynchronous mode:
|
||||||
|
packet format:
|
||||||
|
|
||||||
|
bit count function value
|
||||||
|
1 start bit 0
|
||||||
|
note 1 data bits x
|
||||||
|
note 2 parity bit x
|
||||||
|
note 3 stop bits 1
|
||||||
|
|
||||||
|
Note:
|
||||||
|
1. Data size can be defined (usual value is 8)
|
||||||
|
2. Parity bit (if parity is set to odd or even). Value of bit
|
||||||
|
is defined by data parity.
|
||||||
|
3. There should be at least 1 stop bit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define VERBOSE 0
|
||||||
|
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
||||||
|
|
||||||
|
/* a read/write bit stream. used to transmit data and to receive data */
|
||||||
|
typedef struct _data_stream data_stream;
|
||||||
|
struct _data_stream
|
||||||
|
{
|
||||||
|
/* pointer to buffer */
|
||||||
|
unsigned char *pData;
|
||||||
|
/* length of buffer */
|
||||||
|
unsigned long DataLength;
|
||||||
|
|
||||||
|
/* bit offset within current byte */
|
||||||
|
unsigned long BitCount;
|
||||||
|
/* byte offset within data */
|
||||||
|
unsigned long ByteCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _serial_t serial_t;
|
||||||
|
struct _serial_t
|
||||||
|
{
|
||||||
|
/* transmit data bit-stream */
|
||||||
|
data_stream transmit;
|
||||||
|
/* receive data bit-stream */
|
||||||
|
data_stream receive;
|
||||||
|
|
||||||
|
/* register to receive data */
|
||||||
|
serial_receive_register receive_reg;
|
||||||
|
/* register to transmit data */
|
||||||
|
serial_transmit_register transmit_reg;
|
||||||
|
|
||||||
|
/* connection to transmit/receive data over */
|
||||||
|
serial_connection connection;
|
||||||
|
|
||||||
|
/* data form to transmit/receive */
|
||||||
|
data_form form;
|
||||||
|
|
||||||
|
int transmit_state;
|
||||||
|
|
||||||
|
/* baud rate */
|
||||||
|
unsigned long BaudRate;
|
||||||
|
|
||||||
|
/* baud rate timer */
|
||||||
|
emu_timer *timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
INLINE serial_t *get_safe_token(device_t *device)
|
||||||
|
{
|
||||||
|
assert(device != NULL);
|
||||||
|
//assert(device->type() == SERIAL);
|
||||||
|
|
||||||
|
return (serial_t *)downcast<legacy_device_base *>(device)->token();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* the serial streams */
|
||||||
|
static TIMER_CALLBACK(serial_device_baud_rate_callback);
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************/
|
||||||
|
|
||||||
|
static unsigned char serial_parity_table[256];
|
||||||
|
|
||||||
|
void serial_helper_setup(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* if sum of all bits in the byte is even, then the data
|
||||||
|
has even parity, otherwise it has odd parity */
|
||||||
|
for (i=0; i<256; i++)
|
||||||
|
{
|
||||||
|
int data;
|
||||||
|
int sum;
|
||||||
|
int b;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
data = i;
|
||||||
|
|
||||||
|
for (b=0; b<8; b++)
|
||||||
|
{
|
||||||
|
sum+=data & 0x01;
|
||||||
|
|
||||||
|
data = data>>1;
|
||||||
|
}
|
||||||
|
|
||||||
|
serial_parity_table[i] = sum & 0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char serial_helper_get_parity(unsigned char data)
|
||||||
|
{
|
||||||
|
return serial_parity_table[data & 0x0ff];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_device_in_callback(running_machine &machine, int id, unsigned long status)
|
||||||
|
{
|
||||||
|
/* serial_t *ser = get_safe_token(device);
|
||||||
|
|
||||||
|
ser->connection.input_state = status;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** SERIAL DEVICE ******/
|
||||||
|
void serial_device_setup(device_t *device, int baud_rate, int num_data_bits, int stop_bit_count, int parity_code)
|
||||||
|
{
|
||||||
|
serial_t *ser = get_safe_token(device);
|
||||||
|
|
||||||
|
ser->BaudRate = baud_rate;
|
||||||
|
ser->form.word_length = num_data_bits;
|
||||||
|
ser->form.stop_bit_count = stop_bit_count;
|
||||||
|
ser->form.parity = parity_code;
|
||||||
|
ser->timer = device->machine().scheduler().timer_alloc(FUNC(serial_device_baud_rate_callback), (void *)device);
|
||||||
|
|
||||||
|
serial_connection_init(device->machine(),&ser->connection);
|
||||||
|
serial_connection_set_in_callback(device->machine(),&ser->connection, serial_device_in_callback);
|
||||||
|
|
||||||
|
/* signal to other end it is clear to send! */
|
||||||
|
/* data is initially high state */
|
||||||
|
/* set /rts */
|
||||||
|
ser->connection.State |= SERIAL_STATE_RTS;
|
||||||
|
/* signal to other end data is ready to be accepted */
|
||||||
|
/* set /dtr */
|
||||||
|
ser->connection.State |= SERIAL_STATE_DTR;
|
||||||
|
set_out_data_bit(ser->connection.State, 1);
|
||||||
|
serial_connection_out(device->machine(),&ser->connection);
|
||||||
|
transmit_register_reset(&ser->transmit_reg);
|
||||||
|
receive_register_reset(&ser->receive_reg);
|
||||||
|
receive_register_setup(&ser->receive_reg, &ser->form);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long serial_device_get_state(device_t *device)
|
||||||
|
{
|
||||||
|
serial_t *ser = get_safe_token(device);
|
||||||
|
|
||||||
|
return ser->connection.State;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serial_device_set_transmit_state(device_t *device, int state)
|
||||||
|
{
|
||||||
|
int previous_state;
|
||||||
|
serial_t *ser = get_safe_token(device);
|
||||||
|
|
||||||
|
previous_state = ser->transmit_state;
|
||||||
|
|
||||||
|
ser->transmit_state = state;
|
||||||
|
|
||||||
|
if ((state^previous_state)!=0)
|
||||||
|
{
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
/* start timer */
|
||||||
|
ser->timer->adjust(attotime::zero, 0, attotime::from_hz(ser->BaudRate));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* remove timer */
|
||||||
|
ser->timer->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get a bit from input stream */
|
||||||
|
static int data_stream_get_data_bit_from_data_byte(data_stream *stream)
|
||||||
|
{
|
||||||
|
int data_bit;
|
||||||
|
int data_byte;
|
||||||
|
|
||||||
|
if (stream->ByteCount<stream->DataLength)
|
||||||
|
{
|
||||||
|
/* get data from buffer */
|
||||||
|
data_byte= stream->pData[stream->ByteCount];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* over end of buffer, so return 0 */
|
||||||
|
data_byte= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get bit from data */
|
||||||
|
data_bit = (data_byte>>(7-stream->BitCount)) & 0x01;
|
||||||
|
|
||||||
|
/* update bit count */
|
||||||
|
stream->BitCount++;
|
||||||
|
/* ripple overflow onto byte count */
|
||||||
|
stream->ByteCount+=stream->BitCount>>3;
|
||||||
|
/* lock bit count into range */
|
||||||
|
stream->BitCount &=0x07;
|
||||||
|
|
||||||
|
/* do not let it read over end of data */
|
||||||
|
if (stream->ByteCount>=stream->DataLength)
|
||||||
|
{
|
||||||
|
stream->ByteCount = stream->DataLength-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void receive_register_setup(serial_receive_register *receive, data_form *data_form)
|
||||||
|
{
|
||||||
|
receive->bit_count = data_form->word_length + data_form->stop_bit_count;
|
||||||
|
|
||||||
|
if (data_form->parity != SERIAL_PARITY_NONE)
|
||||||
|
{
|
||||||
|
receive->bit_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* this is generic code to be used in serial chip implementations */
|
||||||
|
/* the majority of serial chips work in the same way and this code will work */
|
||||||
|
/* for them */
|
||||||
|
|
||||||
|
/* receive a bit */
|
||||||
|
void receive_register_update_bit(serial_receive_register *receive, int bit)
|
||||||
|
{
|
||||||
|
int previous_bit;
|
||||||
|
|
||||||
|
LOG(("receive register receive bit: %1x\n",bit));
|
||||||
|
previous_bit = receive->register_data & 1;
|
||||||
|
|
||||||
|
/* shift previous bit 7 out */
|
||||||
|
receive->register_data = receive->register_data<<1;
|
||||||
|
/* shift new bit in */
|
||||||
|
receive->register_data = (receive->register_data & 0xfffe) | bit;
|
||||||
|
/* update bit count received */
|
||||||
|
receive->bit_count_received++;
|
||||||
|
|
||||||
|
/* asyncrhonouse mode */
|
||||||
|
if (receive->flags & RECEIVE_REGISTER_WAITING_FOR_START_BIT)
|
||||||
|
{
|
||||||
|
/* the previous bit is stored in uart.receive char bit 0 */
|
||||||
|
/* has the bit state changed? */
|
||||||
|
if (((previous_bit ^ bit) & 0x01)!=0)
|
||||||
|
{
|
||||||
|
/* yes */
|
||||||
|
if (bit==0)
|
||||||
|
{
|
||||||
|
//logerror("receive register saw start bit\n");
|
||||||
|
|
||||||
|
/* seen start bit! */
|
||||||
|
/* not waiting for start bit now! */
|
||||||
|
receive->flags &=~RECEIVE_REGISTER_WAITING_FOR_START_BIT;
|
||||||
|
receive->flags |=RECEIVE_REGISTER_SYNCHRONISED;
|
||||||
|
/* reset bit count received */
|
||||||
|
receive->bit_count_received = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (receive->flags & RECEIVE_REGISTER_SYNCHRONISED)
|
||||||
|
{
|
||||||
|
/* received all bits? */
|
||||||
|
if (receive->bit_count_received==receive->bit_count)
|
||||||
|
{
|
||||||
|
receive->bit_count_received = 0;
|
||||||
|
receive->flags &=~RECEIVE_REGISTER_SYNCHRONISED;
|
||||||
|
receive->flags |= RECEIVE_REGISTER_WAITING_FOR_START_BIT;
|
||||||
|
//logerror("receive register full\n");
|
||||||
|
receive->flags |= RECEIVE_REGISTER_FULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void receive_register_reset(serial_receive_register *receive_reg)
|
||||||
|
{
|
||||||
|
receive_reg->bit_count_received = 0;
|
||||||
|
receive_reg->flags &=~RECEIVE_REGISTER_FULL;
|
||||||
|
receive_reg->flags &=~RECEIVE_REGISTER_SYNCHRONISED;
|
||||||
|
receive_reg->flags |= RECEIVE_REGISTER_WAITING_FOR_START_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void receive_register_extract(serial_receive_register *receive_reg, data_form *data_form)
|
||||||
|
{
|
||||||
|
unsigned long data_shift;
|
||||||
|
UINT8 data;
|
||||||
|
|
||||||
|
receive_register_reset(receive_reg);
|
||||||
|
|
||||||
|
data_shift = 0;
|
||||||
|
|
||||||
|
/* if parity is even or odd, there should be a parity bit in the stream! */
|
||||||
|
if (data_form->parity!=SERIAL_PARITY_NONE)
|
||||||
|
{
|
||||||
|
data_shift++;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_shift+=data_form->stop_bit_count;
|
||||||
|
|
||||||
|
/* strip off stop bits and parity */
|
||||||
|
data = receive_reg->register_data>>data_shift;
|
||||||
|
|
||||||
|
/* mask off other bits so data byte has 0's in unused bits */
|
||||||
|
data = data & (0x0ff
|
||||||
|
>>
|
||||||
|
(8-(data_form->word_length)));
|
||||||
|
|
||||||
|
receive_reg->byte_received = data;
|
||||||
|
|
||||||
|
/* parity enable? */
|
||||||
|
switch (data_form->parity)
|
||||||
|
{
|
||||||
|
case SERIAL_PARITY_NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* check parity */
|
||||||
|
case SERIAL_PARITY_ODD:
|
||||||
|
case SERIAL_PARITY_EVEN:
|
||||||
|
{
|
||||||
|
//unsigned char computed_parity;
|
||||||
|
//unsigned char parity_received;
|
||||||
|
|
||||||
|
/* get state of parity bit received */
|
||||||
|
//parity_received = (receive_reg->register_data>>data_form->stop_bit_count) & 0x01;
|
||||||
|
|
||||||
|
/* compute parity for received bits */
|
||||||
|
//computed_parity = serial_helper_get_parity(data);
|
||||||
|
|
||||||
|
if (data_form->parity == SERIAL_PARITY_ODD)
|
||||||
|
{
|
||||||
|
/* odd parity */
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* even parity */
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** TRANSMIT REGISTER *****/
|
||||||
|
|
||||||
|
void transmit_register_reset(serial_transmit_register *transmit_reg)
|
||||||
|
{
|
||||||
|
transmit_reg->flags |=TRANSMIT_REGISTER_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* used to construct data in stream format */
|
||||||
|
static void transmit_register_add_bit(serial_transmit_register *transmit_reg, int bit)
|
||||||
|
{
|
||||||
|
/* combine bit */
|
||||||
|
transmit_reg->register_data = transmit_reg->register_data<<1;
|
||||||
|
transmit_reg->register_data &=~1;
|
||||||
|
transmit_reg->register_data|=(bit & 0x01);
|
||||||
|
transmit_reg->bit_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* generate data in stream format ready for transfer */
|
||||||
|
void transmit_register_setup(serial_transmit_register *transmit_reg, data_form *data_form,unsigned char data_byte)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char transmit_data;
|
||||||
|
|
||||||
|
|
||||||
|
transmit_reg->bit_count_transmitted = 0;
|
||||||
|
transmit_reg->bit_count = 0;
|
||||||
|
transmit_reg->flags &=~TRANSMIT_REGISTER_EMPTY;
|
||||||
|
|
||||||
|
/* start bit */
|
||||||
|
transmit_register_add_bit(transmit_reg,0);
|
||||||
|
|
||||||
|
/* data bits */
|
||||||
|
transmit_data = data_byte;
|
||||||
|
for (i=0; i<data_form->word_length; i++)
|
||||||
|
{
|
||||||
|
int databit;
|
||||||
|
|
||||||
|
/* get bit from data */
|
||||||
|
databit = (transmit_data>>(data_form->word_length-1)) & 0x01;
|
||||||
|
/* add bit to formatted byte */
|
||||||
|
transmit_register_add_bit(transmit_reg, databit);
|
||||||
|
transmit_data = transmit_data<<1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parity */
|
||||||
|
if (data_form->parity!=SERIAL_PARITY_NONE)
|
||||||
|
{
|
||||||
|
/* odd or even parity */
|
||||||
|
unsigned char parity;
|
||||||
|
|
||||||
|
/* get parity */
|
||||||
|
/* if parity = 0, data has even parity - i.e. there is an even number of one bits in the data */
|
||||||
|
/* if parity = 1, data has odd parity - i.e. there is an odd number of one bits in the data */
|
||||||
|
parity = serial_helper_get_parity(data_byte);
|
||||||
|
|
||||||
|
transmit_register_add_bit(transmit_reg, parity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stop bit(s) */
|
||||||
|
for (i=0; i<data_form->stop_bit_count; i++)
|
||||||
|
{
|
||||||
|
transmit_register_add_bit(transmit_reg,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* get a bit from the transmit register */
|
||||||
|
static int transmit_register_get_data_bit(serial_transmit_register *transmit_reg)
|
||||||
|
{
|
||||||
|
int bit;
|
||||||
|
|
||||||
|
bit = (transmit_reg->register_data>>
|
||||||
|
(transmit_reg->bit_count - 1 -
|
||||||
|
transmit_reg->bit_count_transmitted)) & 0x01;
|
||||||
|
|
||||||
|
transmit_reg->bit_count_transmitted++;
|
||||||
|
|
||||||
|
/* have all bits of this stream formatted byte been sent? */
|
||||||
|
if (transmit_reg->bit_count_transmitted==transmit_reg->bit_count)
|
||||||
|
{
|
||||||
|
/* yes - generate a new byte to send */
|
||||||
|
transmit_reg->flags |= TRANSMIT_REGISTER_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void transmit_register_send_bit(running_machine &machine, serial_transmit_register *transmit_reg, serial_connection *connection)
|
||||||
|
{
|
||||||
|
int data;
|
||||||
|
|
||||||
|
data = transmit_register_get_data_bit(transmit_reg);
|
||||||
|
|
||||||
|
/* set tx data bit */
|
||||||
|
set_out_data_bit(connection->State, data);
|
||||||
|
|
||||||
|
/* state out through connection */
|
||||||
|
serial_connection_out(machine, connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_protocol_none_sent_char(device_t *device)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int bit;
|
||||||
|
unsigned char data_byte;
|
||||||
|
serial_t *ser = get_safe_token(device);
|
||||||
|
|
||||||
|
/* generate byte to transmit */
|
||||||
|
data_byte = 0;
|
||||||
|
for (i=0; i<ser->form.word_length; i++)
|
||||||
|
{
|
||||||
|
data_byte = data_byte<<1;
|
||||||
|
bit = data_stream_get_data_bit_from_data_byte(&ser->transmit);
|
||||||
|
data_byte = data_byte|bit;
|
||||||
|
}
|
||||||
|
/* setup register */
|
||||||
|
transmit_register_setup(&ser->transmit_reg,&ser->form, data_byte);
|
||||||
|
|
||||||
|
logerror("serial device transmitted char: %02x\n",data_byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TIMER_CALLBACK(serial_device_baud_rate_callback)
|
||||||
|
{
|
||||||
|
serial_t *ser = get_safe_token((device_t*)ptr);
|
||||||
|
|
||||||
|
/* receive data into receive register */
|
||||||
|
receive_register_update_bit(&ser->receive_reg, get_in_data_bit(ser->connection.input_state));
|
||||||
|
|
||||||
|
if (ser->receive_reg.flags & RECEIVE_REGISTER_FULL)
|
||||||
|
{
|
||||||
|
//logerror("SERIAL DEVICE\n");
|
||||||
|
receive_register_extract(&ser->receive_reg, &ser->form);
|
||||||
|
|
||||||
|
logerror("serial device receive char: %02x\n",ser->receive_reg.byte_received);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is transmit empty? */
|
||||||
|
if (ser->transmit_reg.flags & TRANSMIT_REGISTER_EMPTY)
|
||||||
|
{
|
||||||
|
/* char has been sent, execute callback */
|
||||||
|
serial_protocol_none_sent_char((device_t*)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* other side says it is clear to send? */
|
||||||
|
if (ser->connection.input_state & SERIAL_STATE_CTS)
|
||||||
|
{
|
||||||
|
/* send bit */
|
||||||
|
transmit_register_send_bit(machine, &ser->transmit_reg, &ser->connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* connect the specified connection to this serial device */
|
||||||
|
void serial_device_connect(device_t *device, serial_connection *connection)
|
||||||
|
{
|
||||||
|
serial_t *ser = get_safe_token(device);
|
||||||
|
serial_connection_link(device->machine(), connection, &ser->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* load image */
|
||||||
|
static int serial_device_load_internal(device_image_interface &image, unsigned char **ptr, int *pDataSize)
|
||||||
|
{
|
||||||
|
int datasize;
|
||||||
|
unsigned char *data;
|
||||||
|
|
||||||
|
/* get file size */
|
||||||
|
datasize = image.length();
|
||||||
|
|
||||||
|
if (datasize!=0)
|
||||||
|
{
|
||||||
|
/* malloc memory for this data */
|
||||||
|
data = (unsigned char *)malloc(datasize);
|
||||||
|
|
||||||
|
if (data!=NULL)
|
||||||
|
{
|
||||||
|
/* read whole file */
|
||||||
|
image.fread(data, datasize);
|
||||||
|
|
||||||
|
*ptr = data;
|
||||||
|
*pDataSize = datasize;
|
||||||
|
|
||||||
|
logerror("File loaded!\r\n");
|
||||||
|
|
||||||
|
/* ok! */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset position in stream */
|
||||||
|
static void data_stream_reset(data_stream *stream)
|
||||||
|
{
|
||||||
|
/* reset byte offset */
|
||||||
|
stream->ByteCount= 0;
|
||||||
|
/* reset bit count */
|
||||||
|
stream->BitCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free stream */
|
||||||
|
static void data_stream_free(data_stream *stream)
|
||||||
|
{
|
||||||
|
if (stream->pData!=NULL)
|
||||||
|
{
|
||||||
|
free(stream->pData);
|
||||||
|
stream->pData = NULL;
|
||||||
|
}
|
||||||
|
stream->DataLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialise stream */
|
||||||
|
static void data_stream_init(data_stream *stream, unsigned char *pData, unsigned long DataLength)
|
||||||
|
{
|
||||||
|
stream->pData = pData;
|
||||||
|
stream->DataLength = DataLength;
|
||||||
|
data_stream_reset(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE_START(serial)
|
||||||
|
{
|
||||||
|
//serial_t *ser = get_safe_token(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE_RESET(serial)
|
||||||
|
{
|
||||||
|
// serial_t *ser = get_safe_token(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE_IMAGE_LOAD(serial)
|
||||||
|
{
|
||||||
|
int data_length;
|
||||||
|
unsigned char *data;
|
||||||
|
device_t *device = &image.device();
|
||||||
|
|
||||||
|
serial_t *ser = get_safe_token(device);
|
||||||
|
|
||||||
|
/* load file and setup transmit data */
|
||||||
|
if (serial_device_load_internal(image, &data, &data_length))
|
||||||
|
{
|
||||||
|
data_stream_init(&ser->transmit, data, data_length);
|
||||||
|
return IMAGE_INIT_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IMAGE_INIT_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEVICE_IMAGE_UNLOAD(serial)
|
||||||
|
{
|
||||||
|
device_t *device = &image.device();
|
||||||
|
serial_t *ser = get_safe_token(device);
|
||||||
|
|
||||||
|
/* stop transmit */
|
||||||
|
serial_device_set_transmit_state(device, 0);
|
||||||
|
/* free streams */
|
||||||
|
data_stream_free(&ser->transmit);
|
||||||
|
data_stream_free(&ser->receive);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEVICE_GET_INFO( serial )
|
||||||
|
{
|
||||||
|
switch ( state )
|
||||||
|
{
|
||||||
|
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(serial_t); break;
|
||||||
|
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
|
||||||
|
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_SERIAL; break;
|
||||||
|
case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
|
||||||
|
case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break;
|
||||||
|
case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break;
|
||||||
|
|
||||||
|
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( serial ); break;
|
||||||
|
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( serial ); break;
|
||||||
|
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( serial ); break;
|
||||||
|
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(serial ); break;
|
||||||
|
case DEVINFO_STR_NAME: strcpy( info->s, "Serial port"); break;
|
||||||
|
case DEVINFO_STR_FAMILY: strcpy(info->s, "Serial port"); break;
|
||||||
|
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, ""); break;
|
||||||
|
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
|
||||||
|
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||||
|
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/*******************************************************************************/
|
||||||
|
/********* SERIAL CONNECTION ***********/
|
||||||
|
|
||||||
|
|
||||||
|
/* this converts state at this end to a state the other end can accept */
|
||||||
|
/* e.g. CTS at this end becomes RTS at other end.
|
||||||
|
RTS at this end becomes CTS at other end.
|
||||||
|
TX at this end becomes RX at other end.
|
||||||
|
RX at this end becomes TX at other end.
|
||||||
|
etc
|
||||||
|
|
||||||
|
The same thing is done inside the serial null-terminal lead */
|
||||||
|
|
||||||
|
static unsigned long serial_connection_spin_bits(unsigned long input_status)
|
||||||
|
{
|
||||||
|
|
||||||
|
return
|
||||||
|
/* cts -> rts */
|
||||||
|
(((input_status & 0x01)<<1) |
|
||||||
|
/* rts -> cts */
|
||||||
|
((input_status>>1) & 0x01) |
|
||||||
|
/* dsr -> dtr */
|
||||||
|
(((input_status>>2) & 0x01)<<3) |
|
||||||
|
/* dtr -> dsr */
|
||||||
|
(((input_status>>3) & 0x01)<<2) |
|
||||||
|
/* rx -> tx */
|
||||||
|
(((input_status>>4) & 0x01)<<5) |
|
||||||
|
/* tx -> rx */
|
||||||
|
(((input_status>>5) & 0x01)<<4));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* setup callbacks for connection */
|
||||||
|
void serial_connection_init(running_machine &machine, serial_connection *connection)
|
||||||
|
{
|
||||||
|
connection->out_callback = NULL;
|
||||||
|
connection->in_callback = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set callback which will be executed when in status has changed */
|
||||||
|
void serial_connection_set_in_callback(running_machine &machine, serial_connection *connection, void (*in_cb)(running_machine &machine, int id, unsigned long status))
|
||||||
|
{
|
||||||
|
connection->in_callback = in_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output new state through connection */
|
||||||
|
void serial_connection_out(running_machine &machine, serial_connection *connection)
|
||||||
|
{
|
||||||
|
if (connection->out_callback!=NULL)
|
||||||
|
{
|
||||||
|
unsigned long state_at_other_end;
|
||||||
|
|
||||||
|
state_at_other_end = serial_connection_spin_bits(connection->State);
|
||||||
|
|
||||||
|
connection->out_callback(machine, connection->id, state_at_other_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* join two serial connections together */
|
||||||
|
void serial_connection_link(running_machine &machine, serial_connection *connection_a, serial_connection *connection_b)
|
||||||
|
{
|
||||||
|
/* both connections should have their in connection setup! */
|
||||||
|
/* the in connection is the callback they use to update their state based
|
||||||
|
on the output from the other side */
|
||||||
|
connection_a->out_callback = connection_b->in_callback;
|
||||||
|
connection_b->out_callback = connection_a->in_callback;
|
||||||
|
|
||||||
|
/* let b know the state of a */
|
||||||
|
serial_connection_out(machine,connection_a);
|
||||||
|
/* let a know the state of b */
|
||||||
|
serial_connection_out(machine,connection_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_LEGACY_IMAGE_DEVICE(SERIAL, serial);
|
247
src/emu/machine/serial.h
Normal file
247
src/emu/machine/serial.h
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* machine/serial.h
|
||||||
|
*
|
||||||
|
* internal serial transmission
|
||||||
|
*
|
||||||
|
* This code is used to transmit a file stored on the host filesystem
|
||||||
|
* (e.g. PC harddrive) to an emulated system.
|
||||||
|
*
|
||||||
|
* The file is converted into a serial bit-stream which can be received
|
||||||
|
* by the emulated serial chip in the emulated system.
|
||||||
|
*
|
||||||
|
* The file can be transmitted using different protocols.
|
||||||
|
*
|
||||||
|
* A and B are two computers linked with a serial connection
|
||||||
|
* A and B can transmit and receive data, through the same connection
|
||||||
|
*
|
||||||
|
* These flags apply to A and B, and give the state of the input & output
|
||||||
|
* signals at each side.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SERIAL_H_
|
||||||
|
#define SERIAL_H_
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
CTS = Clear to Send. (INPUT)
|
||||||
|
Other end of connection is ready to accept data
|
||||||
|
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
|
||||||
|
This output is active low on serial chips (e.g. 0 is CTS is set),
|
||||||
|
but here it is active high!
|
||||||
|
*/
|
||||||
|
#define SERIAL_STATE_CTS 0x0001
|
||||||
|
|
||||||
|
/*
|
||||||
|
RTS = Request to Send. (OUTPUT)
|
||||||
|
This end is ready to send data, and requests if the other
|
||||||
|
end is ready to accept it
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
|
||||||
|
This output is active low on serial chips (e.g. 0 is RTS is set),
|
||||||
|
but here it is active high!
|
||||||
|
*/
|
||||||
|
#define SERIAL_STATE_RTS 0x0002
|
||||||
|
|
||||||
|
/*
|
||||||
|
DSR = Data Set ready. (INPUT)
|
||||||
|
Other end of connection has data
|
||||||
|
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
|
||||||
|
This output is active low on serial chips (e.g. 0 is DSR is set),
|
||||||
|
but here it is active high!
|
||||||
|
*/
|
||||||
|
#define SERIAL_STATE_DSR 0x0004
|
||||||
|
|
||||||
|
/*
|
||||||
|
DTR = Data terminal Ready. (OUTPUT)
|
||||||
|
TX contains new data.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
|
||||||
|
This output is active low on serial chips (e.g. 0 is DTR is set),
|
||||||
|
but here it is active high!
|
||||||
|
*/
|
||||||
|
#define SERIAL_STATE_DTR 0x0008
|
||||||
|
/* RX = Recieve data. (INPUT) */
|
||||||
|
#define SERIAL_STATE_RX_DATA 0x00010
|
||||||
|
/* TX = Transmit data. (OUTPUT) */
|
||||||
|
#define SERIAL_STATE_TX_DATA 0x00020
|
||||||
|
|
||||||
|
/* parity selections */
|
||||||
|
/* if all the bits are added in a byte, if the result is:
|
||||||
|
even -> parity is even
|
||||||
|
odd -> parity is odd
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SERIAL_PARITY_NONE, /* no parity. a parity bit will not be in the transmitted/received data */
|
||||||
|
SERIAL_PARITY_ODD, /* odd parity */
|
||||||
|
SERIAL_PARITY_EVEN /* even parity */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* this macro is used to extract the received data from the status */
|
||||||
|
#define get_in_data_bit(x) ((x & SERIAL_STATE_RX_DATA)>>4)
|
||||||
|
|
||||||
|
/* this macro is used to set the transmitted data in the status */
|
||||||
|
#define set_out_data_bit(x, data) \
|
||||||
|
x&=~SERIAL_STATE_TX_DATA; \
|
||||||
|
x|=(data<<5)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/**** SERIAL CONNECTION ***/
|
||||||
|
|
||||||
|
|
||||||
|
/* this structure represents a serial connection */
|
||||||
|
typedef struct _serial_connection serial_connection;
|
||||||
|
struct _serial_connection
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
/* state of this side */
|
||||||
|
unsigned long State;
|
||||||
|
|
||||||
|
/* state of other side - store here */
|
||||||
|
unsigned long input_state;
|
||||||
|
|
||||||
|
/* this callback is executed when this side has refreshed it's state,
|
||||||
|
to let the other end know */
|
||||||
|
void (*out_callback)(running_machine &machine, int id, unsigned long state);
|
||||||
|
/* this callback is executed when the other side has refreshed it's state,
|
||||||
|
to let the other end know */
|
||||||
|
void (*in_callback)(running_machine &machine, int id, unsigned long state);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------- defined in machine/serial.c -----------*/
|
||||||
|
|
||||||
|
/* setup out and in callbacks */
|
||||||
|
void serial_connection_init(running_machine &machine, serial_connection *connection);
|
||||||
|
|
||||||
|
/* set callback which will be executed when in status has changed */
|
||||||
|
void serial_connection_set_in_callback(running_machine &machine, serial_connection *connection, void (*in_cb)(running_machine &machine, int id, unsigned long status));
|
||||||
|
|
||||||
|
/* output status, if callback is setup it will be executed with the new status */
|
||||||
|
void serial_connection_out(running_machine &machine, serial_connection *connection);
|
||||||
|
|
||||||
|
/* join two serial connections */
|
||||||
|
void serial_connection_link(running_machine &machine, serial_connection *connection_a, serial_connection *connection_b);
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
|
||||||
|
/* form of data being transmitted and received */
|
||||||
|
typedef struct _data_form data_form;
|
||||||
|
struct _data_form
|
||||||
|
{
|
||||||
|
/* length of word in bits */
|
||||||
|
unsigned long word_length;
|
||||||
|
/* parity state */
|
||||||
|
unsigned long parity;
|
||||||
|
/* number of stop bits */
|
||||||
|
unsigned long stop_bit_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/**** RECEIVE AND TRANSMIT GENERIC CODE ****/
|
||||||
|
|
||||||
|
/* this can be used by most of the serial chip implementations,
|
||||||
|
because they all work in roughly the same way.
|
||||||
|
There is generic code to send and receive data in the specified form */
|
||||||
|
|
||||||
|
/* receive is waiting for start bit. The transition from high-low indicates
|
||||||
|
start of start bit. This is used to synchronise with the data being transfered */
|
||||||
|
#define RECEIVE_REGISTER_WAITING_FOR_START_BIT 0x01
|
||||||
|
/* receive is synchronised with data, data bits will be clocked in */
|
||||||
|
#define RECEIVE_REGISTER_SYNCHRONISED 0x02
|
||||||
|
/* set if receive register has been filled */
|
||||||
|
#define RECEIVE_REGISTER_FULL 0x04
|
||||||
|
|
||||||
|
|
||||||
|
/* the receive register holds data in receive form! */
|
||||||
|
/* this must be extracted to get the data byte received */
|
||||||
|
typedef struct _serial_receive_register serial_receive_register;
|
||||||
|
struct _serial_receive_register
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
unsigned long register_data;
|
||||||
|
/* flags */
|
||||||
|
unsigned long flags;
|
||||||
|
/* bit count received */
|
||||||
|
unsigned long bit_count_received;
|
||||||
|
/* length of data to receive - includes data bits, parity bit and stop bit */
|
||||||
|
unsigned long bit_count;
|
||||||
|
|
||||||
|
/* the byte of data received */
|
||||||
|
unsigned char byte_received;
|
||||||
|
};
|
||||||
|
|
||||||
|
void receive_register_setup(serial_receive_register *receive, data_form *data_form);
|
||||||
|
void receive_register_update_bit(serial_receive_register *receive, int bit_state);
|
||||||
|
void receive_register_extract(serial_receive_register *receive_reg, data_form *data_form);
|
||||||
|
void receive_register_reset(serial_receive_register *receive_reg);
|
||||||
|
|
||||||
|
/* the transmit register is the final stage
|
||||||
|
in the serial transmit procedure */
|
||||||
|
/* normally, data is written to the transmit reg,
|
||||||
|
then it is assembled into transmit form and transmitted */
|
||||||
|
/* the transmit register holds data in transmit form */
|
||||||
|
|
||||||
|
/* register is empty and ready to be filled with data */
|
||||||
|
#define TRANSMIT_REGISTER_EMPTY 0x0001
|
||||||
|
|
||||||
|
typedef struct _serial_transmit_register serial_transmit_register;
|
||||||
|
struct _serial_transmit_register
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
unsigned long register_data;
|
||||||
|
/* flags */
|
||||||
|
unsigned long flags;
|
||||||
|
/* number of bits transmitted */
|
||||||
|
unsigned long bit_count_transmitted;
|
||||||
|
/* length of data to send */
|
||||||
|
unsigned long bit_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* setup transmit reg ready for transmit */
|
||||||
|
void transmit_register_setup(serial_transmit_register *transmit_reg, data_form *data_form,unsigned char data_byte);
|
||||||
|
void transmit_register_send_bit(running_machine &machine, serial_transmit_register *transmit_reg, serial_connection *connection);
|
||||||
|
void transmit_register_reset(serial_transmit_register *transmit_reg);
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/**** SERIAL HELPER ****/
|
||||||
|
|
||||||
|
void serial_helper_setup(void);
|
||||||
|
|
||||||
|
/*******************************************************************************/
|
||||||
|
/**** SERIAL DEVICE ****/
|
||||||
|
|
||||||
|
unsigned long serial_device_get_state(device_t *device);
|
||||||
|
|
||||||
|
/* connect this device to the emulated serial chip */
|
||||||
|
/* id is the serial device to connect to */
|
||||||
|
/* connection is the serial connection to connect to the serial device */
|
||||||
|
void serial_device_connect(device_t *image, serial_connection *connection);
|
||||||
|
|
||||||
|
DECLARE_LEGACY_IMAGE_DEVICE(SERIAL, serial);
|
||||||
|
|
||||||
|
#define MCFG_SERIAL_ADD(_tag) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, SERIAL, 0)
|
||||||
|
|
||||||
|
DEVICE_START(serial);
|
||||||
|
DEVICE_IMAGE_LOAD(serial);
|
||||||
|
|
||||||
|
void serial_device_setup(device_t *image, int baud_rate, int num_data_bits, int stop_bit_count, int parity_code);
|
||||||
|
|
||||||
|
/* set the transmit state of the serial device */
|
||||||
|
void serial_device_set_transmit_state(device_t *image, int state);
|
||||||
|
|
||||||
|
#endif /* SERIAL_H_ */
|
2457
src/emu/machine/upd765.c
Normal file
2457
src/emu/machine/upd765.c
Normal file
File diff suppressed because it is too large
Load Diff
161
src/emu/machine/upd765.h
Normal file
161
src/emu/machine/upd765.h
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
machine/upd765.h
|
||||||
|
|
||||||
|
Functions to emulate a NEC upd765/Intel 8272 compatible
|
||||||
|
floppy disk controller
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __UPD765_H__
|
||||||
|
#define __UPD765_H__
|
||||||
|
|
||||||
|
#include "devcb.h"
|
||||||
|
#include "imagedev/flopdrv.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
MACROS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
DECLARE_LEGACY_DEVICE(UPD765A, upd765a);
|
||||||
|
DECLARE_LEGACY_DEVICE(UPD765B, upd765b);
|
||||||
|
DECLARE_LEGACY_DEVICE(SMC37C78, smc37c78);
|
||||||
|
DECLARE_LEGACY_DEVICE(UPD72065, upd72065);
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/* RDY pin connected state */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
UPD765_RDY_PIN_NOT_CONNECTED = 0,
|
||||||
|
UPD765_RDY_PIN_CONNECTED = 1
|
||||||
|
} UPD765_RDY_PIN;
|
||||||
|
|
||||||
|
#define UPD765_DAM_DELETED_DATA 0x0f8
|
||||||
|
#define UPD765_DAM_DATA 0x0fb
|
||||||
|
|
||||||
|
typedef device_t *(*upd765_get_image_func)(device_t *device, int floppy_index);
|
||||||
|
#define UPD765_GET_IMAGE(name) device_t *name(device_t *device, int floppy_index )
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct upd765_interface
|
||||||
|
{
|
||||||
|
/* interrupt issued */
|
||||||
|
devcb_write_line out_int_func;
|
||||||
|
|
||||||
|
/* dma data request */
|
||||||
|
devcb_write_line out_drq_func;
|
||||||
|
|
||||||
|
/* image lookup */
|
||||||
|
upd765_get_image_func get_image;
|
||||||
|
|
||||||
|
UPD765_RDY_PIN rdy_pin;
|
||||||
|
|
||||||
|
const char *floppy_drive_tags[4];
|
||||||
|
} upd765_interface;
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
FUNCTION PROTOTYPES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/* read of data register */
|
||||||
|
READ8_DEVICE_HANDLER(upd765_data_r);
|
||||||
|
/* write to data register */
|
||||||
|
WRITE8_DEVICE_HANDLER(upd765_data_w);
|
||||||
|
/* read of main status register */
|
||||||
|
READ8_DEVICE_HANDLER(upd765_status_r);
|
||||||
|
|
||||||
|
/* dma acknowledge with write */
|
||||||
|
WRITE8_DEVICE_HANDLER(upd765_dack_w);
|
||||||
|
/* dma acknowledge with read */
|
||||||
|
READ8_DEVICE_HANDLER(upd765_dack_r);
|
||||||
|
|
||||||
|
/* reset upd765 */
|
||||||
|
void upd765_reset(device_t *device, int);
|
||||||
|
|
||||||
|
/* reset pin of upd765 */
|
||||||
|
WRITE_LINE_DEVICE_HANDLER(upd765_reset_w);
|
||||||
|
|
||||||
|
/* set upd765 terminal count input state */
|
||||||
|
WRITE_LINE_DEVICE_HANDLER(upd765_tc_w);
|
||||||
|
|
||||||
|
/* set upd765 ready input*/
|
||||||
|
WRITE_LINE_DEVICE_HANDLER(upd765_ready_w);
|
||||||
|
|
||||||
|
void upd765_idle(device_t *device);
|
||||||
|
|
||||||
|
/*********************/
|
||||||
|
/* STATUS REGISTER 1 */
|
||||||
|
|
||||||
|
/* this is set if a TC signal was not received after the sector data was read */
|
||||||
|
#define UPD765_ST1_END_OF_CYLINDER (1<<7)
|
||||||
|
/* this is set if the sector ID being searched for is not found */
|
||||||
|
#define UPD765_ST1_NO_DATA (1<<2)
|
||||||
|
/* set if disc is write protected and a write/format operation was performed */
|
||||||
|
#define UPD765_ST1_NOT_WRITEABLE (1<<1)
|
||||||
|
|
||||||
|
/*********************/
|
||||||
|
/* STATUS REGISTER 2 */
|
||||||
|
|
||||||
|
/* C parameter specified did not match C value read from disc */
|
||||||
|
#define UPD765_ST2_WRONG_CYLINDER (1<<4)
|
||||||
|
/* C parameter specified did not match C value read from disc, and C read from disc was 0x0ff */
|
||||||
|
#define UPD765_ST2_BAD_CYLINDER (1<<1)
|
||||||
|
/* this is set if the FDC encounters a Deleted Data Mark when executing a read data
|
||||||
|
command, or FDC encounters a Data Mark when executing a read deleted data command */
|
||||||
|
#define UPD765_ST2_CONTROL_MARK (1<<6)
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
DEVICE CONFIGURATION MACROS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#define MCFG_UPD765A_ADD(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, UPD765A, 0) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_UPD765A_MODIFY(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_MODIFY(_tag) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_UPD765A_REMOVE(_tag) \
|
||||||
|
MCFG_DEVICE_REMOVE(_tag)
|
||||||
|
|
||||||
|
#define MCFG_UPD765B_ADD(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, UPD765B, 0) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_UPD765B_MODIFY(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_MODIFY(_tag) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_UPD765B_REMOVE(_tag) \
|
||||||
|
MCFG_DEVICE_REMOVE(_tag)
|
||||||
|
|
||||||
|
#define MCFG_SMC37C78_ADD(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, SMC37C78, 0) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_SMC37C78_MODIFY(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_MODIFY(_tag) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_SMC37C78_REMOVE(_tag) \
|
||||||
|
MCFG_DEVICE_REMOVE(_tag)
|
||||||
|
|
||||||
|
#define MCFG_UPD72065_ADD(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, UPD72065, 0) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_UPD72065_MODIFY(_tag, _intrf) \
|
||||||
|
MCFG_DEVICE_MODIFY(_tag) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intrf)
|
||||||
|
|
||||||
|
#define MCFG_UPD72065_REMOVE(_tag) \
|
||||||
|
MCFG_DEVICE_REMOVE(_tag)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __UPD765_H__ */
|
379
src/mame/drivers/dc.c
Normal file
379
src/mame/drivers/dc.c
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
dc.c - Sega Dreamcast driver
|
||||||
|
by R. Belmont
|
||||||
|
|
||||||
|
SH-4 @ 200 MHz
|
||||||
|
ARM7DI @ 2.8223 MHz (no T or M extensions)
|
||||||
|
PowerVR 3D video
|
||||||
|
AICA audio
|
||||||
|
GD-ROM drive (modified ATAPI interface)
|
||||||
|
|
||||||
|
NTSC/N NTSC/I PAL/N PAL/I VGA
|
||||||
|
(x/240) (x/480) (x/240) (x/480) (640x480)
|
||||||
|
VTOTAL 262 524 312 624 524
|
||||||
|
HTOTAL 857 857 863 863 857
|
||||||
|
|
||||||
|
PCLKs = 26917135 (NTSC 480 @ 59.94), 26944080 (VGA 480 @ 60.0), 13458568 (NTSC 240 @ 59.94),
|
||||||
|
25925600 (PAL 480 @ 50.00), 13462800 (PAL 240 @ 50.00)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
#include "cpu/arm7/arm7.h"
|
||||||
|
#include "cpu/sh4/sh4.h"
|
||||||
|
#include "cpu/arm7/arm7core.h"
|
||||||
|
#include "sound/aica.h"
|
||||||
|
#include "includes/dc.h"
|
||||||
|
#include "imagedev/chd_cd.h"
|
||||||
|
#include "machine/maple-dc.h"
|
||||||
|
#define CPU_CLOCK (200000000)
|
||||||
|
|
||||||
|
#ifdef MESS
|
||||||
|
UINT16 actel_id;
|
||||||
|
int jvsboard_type;
|
||||||
|
#else
|
||||||
|
extern UINT16 actel_id;
|
||||||
|
extern int jvsboard_type;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// things from mess/machine/dc.c
|
||||||
|
void dreamcast_atapi_init(running_machine &machine);
|
||||||
|
void dreamcast_atapi_reset(running_machine &machine);
|
||||||
|
extern READ64_HANDLER( dc_mess_gdrom_r );
|
||||||
|
extern WRITE64_HANDLER( dc_mess_gdrom_w );
|
||||||
|
extern READ64_HANDLER( dc_mess_g1_ctrl_r );
|
||||||
|
extern WRITE64_HANDLER( dc_mess_g1_ctrl_w );
|
||||||
|
|
||||||
|
static UINT32 *dc_sound_ram;
|
||||||
|
static UINT64 *dc_ram;
|
||||||
|
|
||||||
|
static READ64_HANDLER( dcus_idle_skip_r )
|
||||||
|
{
|
||||||
|
if (cpu_get_pc(&space->device())==0xc0ba52a)
|
||||||
|
device_spin_until_time(&space->device(), attotime::from_usec(2500));
|
||||||
|
// device_spinuntil_int(&space->device());
|
||||||
|
|
||||||
|
return dc_ram[0x2303b0/8];
|
||||||
|
}
|
||||||
|
|
||||||
|
static READ64_HANDLER( dcjp_idle_skip_r )
|
||||||
|
{
|
||||||
|
if (cpu_get_pc(&space->device())==0xc0bac62)
|
||||||
|
device_spin_until_time(&space->device(), attotime::from_usec(2500));
|
||||||
|
// device_spinuntil_int(&space->device());
|
||||||
|
|
||||||
|
return dc_ram[0x2302f8/8];
|
||||||
|
}
|
||||||
|
|
||||||
|
static DRIVER_INIT(dc)
|
||||||
|
{
|
||||||
|
dreamcast_atapi_init(machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DRIVER_INIT(dcus)
|
||||||
|
{
|
||||||
|
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xc2303b0, 0xc2303b7, FUNC(dcus_idle_skip_r));
|
||||||
|
|
||||||
|
DRIVER_INIT_CALL(dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DRIVER_INIT(dcjp)
|
||||||
|
{
|
||||||
|
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xc2302f8, 0xc2302ff, FUNC(dcjp_idle_skip_r));
|
||||||
|
|
||||||
|
DRIVER_INIT_CALL(dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT64 PDTRA, PCTRA;
|
||||||
|
static READ64_HANDLER( dc_pdtra_r )
|
||||||
|
{
|
||||||
|
UINT64 out = PCTRA<<32;
|
||||||
|
|
||||||
|
out |= PDTRA & ~3;
|
||||||
|
|
||||||
|
// if both bits are inputs
|
||||||
|
if (!(PCTRA & 0x5))
|
||||||
|
{
|
||||||
|
out |= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// one's input one's output, always pull up both bits
|
||||||
|
if (((PCTRA & 5) == 1) || ((PCTRA & 5) == 4))
|
||||||
|
{
|
||||||
|
if (PDTRA & 3)
|
||||||
|
{
|
||||||
|
out |= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WRITE64_HANDLER( dc_pdtra_w )
|
||||||
|
{
|
||||||
|
PCTRA = (data>>16) & 0xffff;
|
||||||
|
PDTRA = (data & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static READ64_HANDLER( dc_arm_r )
|
||||||
|
{
|
||||||
|
return *((UINT64 *)dc_sound_ram+offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WRITE64_HANDLER( dc_arm_w )
|
||||||
|
{
|
||||||
|
COMBINE_DATA((UINT64 *)dc_sound_ram + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SB_LMMODE0
|
||||||
|
static WRITE64_HANDLER( ta_texture_directpath0_w )
|
||||||
|
{
|
||||||
|
int mode = pvrctrl_regs[SB_LMMODE0]&1;
|
||||||
|
if (mode&1)
|
||||||
|
{
|
||||||
|
printf("ta_texture_directpath0_w 32-bit access!\n");
|
||||||
|
COMBINE_DATA(&dc_framebuffer_ram[offset]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
COMBINE_DATA(&dc_texture_ram[offset]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SB_LMMODE1
|
||||||
|
static WRITE64_HANDLER( ta_texture_directpath1_w )
|
||||||
|
{
|
||||||
|
int mode = pvrctrl_regs[SB_LMMODE1]&1;
|
||||||
|
if (mode&1)
|
||||||
|
{
|
||||||
|
printf("ta_texture_directpath0_w 32-bit access!\n");
|
||||||
|
COMBINE_DATA(&dc_framebuffer_ram[offset]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
COMBINE_DATA(&dc_texture_ram[offset]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ADDRESS_MAP_START( dc_map, AS_PROGRAM, 64 )
|
||||||
|
AM_RANGE(0x00000000, 0x001fffff) AM_ROM AM_WRITENOP // BIOS
|
||||||
|
AM_RANGE(0x00200000, 0x0021ffff) AM_ROM AM_REGION("maincpu", 0x200000) // flash
|
||||||
|
AM_RANGE(0x005f6800, 0x005f69ff) AM_READWRITE( dc_sysctrl_r, dc_sysctrl_w )
|
||||||
|
AM_RANGE(0x005f6c00, 0x005f6cff) AM_DEVREADWRITE32_MODERN( "maple_dc", maple_dc_device, sb_mdstar_r, sb_mdstar_w, U64(0xffffffff00000000) )
|
||||||
|
AM_RANGE(0x005f7000, 0x005f70ff) AM_READWRITE( dc_mess_gdrom_r, dc_mess_gdrom_w )
|
||||||
|
AM_RANGE(0x005f7400, 0x005f74ff) AM_READWRITE( dc_mess_g1_ctrl_r, dc_mess_g1_ctrl_w )
|
||||||
|
AM_RANGE(0x005f7800, 0x005f78ff) AM_READWRITE( dc_g2_ctrl_r, dc_g2_ctrl_w )
|
||||||
|
AM_RANGE(0x005f7c00, 0x005f7cff) AM_READWRITE( pvr_ctrl_r, pvr_ctrl_w )
|
||||||
|
AM_RANGE(0x005f8000, 0x005f9fff) AM_READWRITE( pvr_ta_r, pvr_ta_w )
|
||||||
|
AM_RANGE(0x00600000, 0x006007ff) AM_READWRITE( dc_modem_r, dc_modem_w )
|
||||||
|
AM_RANGE(0x00700000, 0x00707fff) AM_DEVREADWRITE("aica", dc_aica_reg_r, dc_aica_reg_w )
|
||||||
|
AM_RANGE(0x00710000, 0x0071000f) AM_READWRITE( dc_rtc_r, dc_rtc_w )
|
||||||
|
AM_RANGE(0x00800000, 0x009fffff) AM_READWRITE( dc_arm_r, dc_arm_w )
|
||||||
|
|
||||||
|
/* Area 1 */
|
||||||
|
AM_RANGE(0x04000000, 0x04ffffff) AM_RAM AM_BASE( &dc_texture_ram ) // texture memory 64 bit access
|
||||||
|
AM_RANGE(0x05000000, 0x05ffffff) AM_RAM AM_BASE( &dc_framebuffer_ram ) // apparently this actually accesses the same memory as the 64-bit texture memory access, but in a different format, keep it apart for now
|
||||||
|
|
||||||
|
/* Area 3 */
|
||||||
|
AM_RANGE(0x0c000000, 0x0cffffff) AM_RAM AM_SHARE("share4") AM_BASE(&dc_ram)
|
||||||
|
AM_RANGE(0x0d000000, 0x0dffffff) AM_RAM AM_SHARE("share4")// extra ram on Naomi (mirror on DC)
|
||||||
|
AM_RANGE(0x0e000000, 0x0effffff) AM_RAM AM_SHARE("share4")// mirror
|
||||||
|
AM_RANGE(0x0f000000, 0x0fffffff) AM_RAM AM_SHARE("share4")// mirror
|
||||||
|
|
||||||
|
/* Area 4 */
|
||||||
|
AM_RANGE(0x10000000, 0x107fffff) AM_WRITE( ta_fifo_poly_w )
|
||||||
|
AM_RANGE(0x10800000, 0x10ffffff) AM_WRITE( ta_fifo_yuv_w )
|
||||||
|
AM_RANGE(0x11000000, 0x117fffff) AM_WRITE( ta_texture_directpath0_w ) AM_MIRROR(0x00800000) // access to texture / fraembfufer memory (either 32-bit or 64-bit area depending on SB_LMMODE0 register - cannot be written directly, only through dma / store queue
|
||||||
|
|
||||||
|
AM_RANGE(0x12000000, 0x127fffff) AM_WRITE( ta_fifo_poly_w )
|
||||||
|
AM_RANGE(0x12800000, 0x12ffffff) AM_WRITE( ta_fifo_yuv_w )
|
||||||
|
AM_RANGE(0x13000000, 0x137fffff) AM_WRITE( ta_texture_directpath1_w ) AM_MIRROR(0x00800000) // access to texture / fraembfufer memory (either 32-bit or 64-bit area depending on SB_LMMODE1 register - cannot be written directly, only through dma / store queue
|
||||||
|
|
||||||
|
AM_RANGE(0x8c000000, 0x8cffffff) AM_RAM AM_SHARE("share4") // another RAM mirror
|
||||||
|
|
||||||
|
AM_RANGE(0xa0000000, 0xa01fffff) AM_ROM AM_REGION("maincpu", 0)
|
||||||
|
ADDRESS_MAP_END
|
||||||
|
|
||||||
|
static ADDRESS_MAP_START( dc_port, AS_IO, 64 )
|
||||||
|
AM_RANGE(0x00000000, 0x00000007) AM_READWRITE( dc_pdtra_r, dc_pdtra_w )
|
||||||
|
ADDRESS_MAP_END
|
||||||
|
|
||||||
|
static ADDRESS_MAP_START( dc_audio_map, AS_PROGRAM, 32 )
|
||||||
|
AM_RANGE(0x00000000, 0x001fffff) AM_RAM AM_BASE(&dc_sound_ram) /* shared with SH-4 */
|
||||||
|
AM_RANGE(0x00800000, 0x00807fff) AM_DEVREADWRITE("aica", dc_arm_aica_r, dc_arm_aica_w)
|
||||||
|
ADDRESS_MAP_END
|
||||||
|
|
||||||
|
static MACHINE_RESET( dc_console )
|
||||||
|
{
|
||||||
|
device_t *aica = machine.device("aica");
|
||||||
|
MACHINE_RESET_CALL(dc);
|
||||||
|
aica_set_ram_base(aica, dc_sound_ram, 2*1024*1024);
|
||||||
|
dreamcast_atapi_reset(machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aica_irq(device_t *device, int irq)
|
||||||
|
{
|
||||||
|
cputag_set_input_line(device->machine(), "soundcpu", ARM7_FIRQ_LINE, irq ? ASSERT_LINE : CLEAR_LINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const aica_interface dc_aica_interface =
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
aica_irq
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sh4_config sh4cpu_config = { 1, 0, 1, 0, 0, 0, 1, 1, 0, CPU_CLOCK };
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_START( dc, driver_device )
|
||||||
|
/* basic machine hardware */
|
||||||
|
MCFG_CPU_ADD("maincpu", SH4, CPU_CLOCK)
|
||||||
|
MCFG_CPU_CONFIG(sh4cpu_config)
|
||||||
|
MCFG_CPU_PROGRAM_MAP(dc_map)
|
||||||
|
MCFG_CPU_IO_MAP(dc_port)
|
||||||
|
|
||||||
|
MCFG_CPU_ADD("soundcpu", ARM7, ((XTAL_33_8688MHz*2)/3)/8) // AICA bus clock is 2/3rds * 33.8688. ARM7 gets 1 bus cycle out of each 8.
|
||||||
|
MCFG_CPU_PROGRAM_MAP(dc_audio_map)
|
||||||
|
|
||||||
|
MCFG_MACHINE_START( dc )
|
||||||
|
MCFG_MACHINE_RESET( dc_console )
|
||||||
|
|
||||||
|
MCFG_MAPLE_DC_ADD( "maple_dc", "maincpu" )
|
||||||
|
|
||||||
|
/* video hardware */
|
||||||
|
MCFG_SCREEN_ADD("screen", RASTER)
|
||||||
|
MCFG_SCREEN_REFRESH_RATE(60)
|
||||||
|
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */)
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_SIZE(640, 480)
|
||||||
|
MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1)
|
||||||
|
MCFG_SCREEN_UPDATE(dc)
|
||||||
|
|
||||||
|
MCFG_PALETTE_LENGTH(0x1000)
|
||||||
|
|
||||||
|
MCFG_VIDEO_START(dc)
|
||||||
|
|
||||||
|
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||||
|
MCFG_SOUND_ADD("aica", AICA, 0)
|
||||||
|
MCFG_SOUND_CONFIG(dc_aica_interface)
|
||||||
|
MCFG_SOUND_ROUTE(0, "lspeaker", 2.0)
|
||||||
|
MCFG_SOUND_ROUTE(0, "rspeaker", 2.0)
|
||||||
|
|
||||||
|
MCFG_CDROM_ADD( "cdrom" )
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
ROM_START(dc)
|
||||||
|
ROM_REGION(0x220000, "maincpu", 0)
|
||||||
|
ROM_LOAD( "dc101d_us.bin", 0x000000, 0x200000, CRC(89f2b1a1) SHA1(8951d1bb219ab2ff8583033d2119c899cc81f18c) ) // BIOS
|
||||||
|
ROM_LOAD( "dcus_ntsc.bin", 0x200000, 0x020000, CRC(c611b498) SHA1(94d44d7f9529ec1642ba3771ed3c5f756d5bc872) ) // Flash
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START( dceu )
|
||||||
|
ROM_REGION(0x220000, "maincpu", 0)
|
||||||
|
ROM_LOAD( "dc101d_eu.bin", 0x000000, 0x200000, CRC(a2564fad) SHA1(edc5d3d70a93c935703d26119b37731fd317d2bf) ) // BIOS
|
||||||
|
ROM_LOAD( "dceu_pal.bin", 0x200000, 0x020000, CRC(b7e5aeeb) SHA1(11e02433e13b793ec7ffe0ae2356750bb8a575b4) ) // Flash
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START( dcjp )
|
||||||
|
ROM_REGION(0x220000, "maincpu", 0)
|
||||||
|
ROM_LOAD( "dc1004jp.bin", 0x000000, 0x200000, CRC(5454841f) SHA1(1ea132c0fbbf07ef76789eadc07908045c089bd6) ) // BIOS
|
||||||
|
/* ROM_LOAD( "dcjp_ntsc.bad", 0x200000, 0x020000, BAD_DUMP CRC(307a7035) SHA1(1411423a9d071340ea52c56e19c1aafc4e1309ee) ) // Hacked Flash */
|
||||||
|
ROM_LOAD( "dcjp_ntsc.bin", 0x200000, 0x020000, CRC(5F92BF76) SHA1(BE78B834F512AB2CF3D67B96E377C9F3093FF82A) ) // Flash
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START( dcdev )
|
||||||
|
ROM_REGION(0x220000, "maincpu", 0)
|
||||||
|
ROM_LOAD( "hkt-0120.bin", 0x000000, 0x200000, CRC(2186E0E5) SHA1(6BD18FB83F8FDB56F1941E079580E5DD672A6DAD) ) // BIOS
|
||||||
|
ROM_LOAD( "hkt-0120-flash.bin", 0x200000, 0x020000, CRC(7784C304) SHA1(31EF57F550D8CD13E40263CBC657253089E53034) ) // Flash
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
static INPUT_PORTS_START( dc )
|
||||||
|
PORT_START("P1L")
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 )
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
|
||||||
|
PORT_START("P1H")
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN1 )
|
||||||
|
PORT_SERVICE_NO_TOGGLE( 0x40, IP_ACTIVE_LOW )
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE1 )
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1)
|
||||||
|
|
||||||
|
PORT_START("P2L")
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START2 )
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
|
||||||
|
PORT_START("P2H")
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN2 )
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE2 )
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(2)
|
||||||
|
|
||||||
|
PORT_START("P3L")
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(3)
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(3)
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(3)
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(3)
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START3 )
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3)
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(3)
|
||||||
|
PORT_START("P3H")
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN3 )
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE3 )
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(3)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(3)
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(3)
|
||||||
|
|
||||||
|
PORT_START("P4L")
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(4)
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(4)
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(4)
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(4)
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START4 )
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(4)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(4)
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(4)
|
||||||
|
PORT_START("P4H")
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN4 )
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE4 )
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(4)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(4)
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(4)
|
||||||
|
|
||||||
|
PORT_START("MAMEDEBUG") \
|
||||||
|
PORT_DIPNAME( 0x01, 0x00, "Bilinear Filtering" )
|
||||||
|
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
|
||||||
|
PORT_DIPSETTING( 0x01, DEF_STR( On ) )
|
||||||
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
|
||||||
|
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
|
||||||
|
CONS( 1999, dc, dcjp, 0, dc, dc, dcus, "Sega", "Dreamcast (USA, NTSC)", GAME_NOT_WORKING )
|
||||||
|
CONS( 1998, dcjp, 0, 0, dc, dc, dcjp, "Sega", "Dreamcast (Japan, NTSC)", GAME_NOT_WORKING )
|
||||||
|
CONS( 1999, dceu, dcjp, 0, dc, dc, dcus, "Sega", "Dreamcast (Europe, PAL)", GAME_NOT_WORKING )
|
||||||
|
CONS( 1998, dcdev, dcjp, 0, dc, dc, dc, "Sega", "HKT-0120 Sega Dreamcast Development Box", GAME_NOT_WORKING )
|
783
src/mame/drivers/segasms.c
Normal file
783
src/mame/drivers/segasms.c
Normal file
@ -0,0 +1,783 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
Contributors:
|
||||||
|
|
||||||
|
Marat Fayzullin (MG source)
|
||||||
|
Charles Mac Donald
|
||||||
|
Mathis Rosenhauer
|
||||||
|
Brad Oliver
|
||||||
|
Michael Luong
|
||||||
|
|
||||||
|
To do:
|
||||||
|
|
||||||
|
- PSG control for Game Gear (needs custom SN76489 with stereo output for each channel)
|
||||||
|
- SIO interface for Game Gear (needs netplay, I guess)
|
||||||
|
- SMS lightgun support
|
||||||
|
- LCD persistence emulation for GG
|
||||||
|
- SMS 3D glass support
|
||||||
|
|
||||||
|
The Game Gear SIO and PSG hardware are not emulated but have some
|
||||||
|
placeholders in 'machine/sms.c'
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
Apr 02 - Added raster palette effects for SMS & GG (ML)
|
||||||
|
- Added sprite collision (ML)
|
||||||
|
- Added zoomed sprites (ML)
|
||||||
|
May 02 - Fixed paging bug (ML)
|
||||||
|
- Fixed sprite and tile priority bug (ML)
|
||||||
|
- Fixed bug #66 (ML)
|
||||||
|
- Fixed bug #78 (ML)
|
||||||
|
- try to implement LCD persistence emulation for GG (ML)
|
||||||
|
Jun 10, 02 - Added bios emulation (ML)
|
||||||
|
Jun 12, 02 - Added PAL & NTSC systems (ML)
|
||||||
|
Jun 25, 02 - Added border emulation (ML)
|
||||||
|
Jun 27, 02 - Version bits for Game Gear (bits 6 of port 00) (ML)
|
||||||
|
Nov-Dec, 05 - Numerous cleanups, fixes, updates (WP)
|
||||||
|
Mar, 07 - More cleanups, fixes, mapper additions, etc (WP)
|
||||||
|
|
||||||
|
SMS Store Unit memory map for the second CPU:
|
||||||
|
|
||||||
|
0000-3FFF - BIOS
|
||||||
|
4000-47FF - RAM
|
||||||
|
8000 - System Control Register (R/W)
|
||||||
|
Reading:
|
||||||
|
bit7 - ready (0 = ready, 1 = not ready)
|
||||||
|
bit6-bit5 - unknown
|
||||||
|
bit4-bit3 - timer selection bit switches
|
||||||
|
bit2-bit0 - unknown
|
||||||
|
Writing:
|
||||||
|
bit7-bit4 - unknown, maybe led of selected game to set?
|
||||||
|
bit3 - unknown, 1 seems to be written all the time
|
||||||
|
bit2 - unknown, 1 seems to be written all the time
|
||||||
|
bit1 - reset signal for sms cpu, 0 = reset low, 1 = reset high
|
||||||
|
bit0 - which cpu receives interrupt signals, 0 = sms cpu, 1 = controlling cpu
|
||||||
|
C000 - Card/Cartridge selction register (W)
|
||||||
|
bit7-bit4 - slot to select
|
||||||
|
bit3 - slot type (0 = cartridge, 1 = card ?)
|
||||||
|
bit2-bit0 - unknown
|
||||||
|
C400 - ???? (used once)
|
||||||
|
D800 - Selection buttons #1, 1-8 (R)
|
||||||
|
DC00 - Selection buttons #2, 9-16 (R)
|
||||||
|
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
#include "cpu/z80/z80.h"
|
||||||
|
#include "sound/sn76496.h"
|
||||||
|
#include "sound/2413intf.h"
|
||||||
|
#include "includes/segasms.h"
|
||||||
|
#include "video/smsvdp.h"
|
||||||
|
#include "imagedev/cartslot.h"
|
||||||
|
|
||||||
|
#include "sms1.lh"
|
||||||
|
|
||||||
|
#define MASTER_CLOCK_PAL 53203400 /* This might be a tiny bit too low */
|
||||||
|
|
||||||
|
|
||||||
|
static ADDRESS_MAP_START( sms1_mem, AS_PROGRAM, 8 )
|
||||||
|
AM_RANGE(0x0000, 0x03ff) AM_ROMBANK("bank1") /* First 0x0400 part always points to first page */
|
||||||
|
AM_RANGE(0x0400, 0x3fff) AM_ROMBANK("bank2") /* switchable rom bank */
|
||||||
|
AM_RANGE(0x4000, 0x5fff) AM_ROMBANK("bank3") /* switchable rom bank */
|
||||||
|
AM_RANGE(0x6000, 0x7fff) AM_ROMBANK("bank4") /* switchable rom bank */
|
||||||
|
AM_RANGE(0x8000, 0x9fff) AM_READ_BANK("bank5") AM_WRITE(sms_cartram_w) /* ROM bank / on-cart RAM */
|
||||||
|
AM_RANGE(0xa000, 0xbfff) AM_READ_BANK("bank6") AM_WRITE(sms_cartram2_w) /* ROM bank / on-cart RAM */
|
||||||
|
AM_RANGE(0xc000, 0xdff7) AM_MIRROR(0x2000) AM_RAM /* RAM (mirror at 0xE000) */
|
||||||
|
AM_RANGE(0xdff8, 0xdfff) AM_RAM /* RAM "underneath" frame registers */
|
||||||
|
AM_RANGE(0xfff8, 0xfffb) AM_READWRITE(sms_sscope_r, sms_sscope_w) /* 3-D glasses */
|
||||||
|
AM_RANGE(0xfffc, 0xffff) AM_READWRITE(sms_mapper_r, sms_mapper_w) /* Bankswitch control */
|
||||||
|
ADDRESS_MAP_END
|
||||||
|
|
||||||
|
static ADDRESS_MAP_START( sms_mem, AS_PROGRAM, 8 )
|
||||||
|
AM_RANGE(0x0000, 0x03ff) AM_ROMBANK("bank1") /* First 0x0400 part always points to first page */
|
||||||
|
AM_RANGE(0x0400, 0x3fff) AM_ROMBANK("bank2") /* switchable rom bank */
|
||||||
|
AM_RANGE(0x4000, 0x5fff) AM_ROMBANK("bank3") /* switchable rom bank */
|
||||||
|
AM_RANGE(0x6000, 0x7fff) AM_ROMBANK("bank4") /* switchable rom bank */
|
||||||
|
AM_RANGE(0x8000, 0x9fff) AM_READ_BANK("bank5") AM_WRITE(sms_cartram_w) /* ROM bank / on-cart RAM */
|
||||||
|
AM_RANGE(0xa000, 0xbfff) AM_READ_BANK("bank6") AM_WRITE(sms_cartram2_w) /* ROM bank / on-cart RAM */
|
||||||
|
AM_RANGE(0xc000, 0xdffb) AM_MIRROR(0x2000) AM_RAM /* RAM (mirror at 0xE000) */
|
||||||
|
AM_RANGE(0xdffc, 0xdfff) AM_RAM /* RAM "underneath" frame registers */
|
||||||
|
AM_RANGE(0xfffc, 0xffff) AM_READWRITE(sms_mapper_r, sms_mapper_w) /* Bankswitch control */
|
||||||
|
ADDRESS_MAP_END
|
||||||
|
|
||||||
|
static ADDRESS_MAP_START( sms_store_mem, AS_PROGRAM, 8 )
|
||||||
|
AM_RANGE(0x0000, 0x3fff) AM_ROM /* BIOS */
|
||||||
|
AM_RANGE(0x4000, 0x47ff) AM_RAM /* RAM */
|
||||||
|
AM_RANGE(0x6000, 0x7fff) AM_ROMBANK("bank10") /* Cartridge/card peek area */
|
||||||
|
AM_RANGE(0x8000, 0x8000) AM_READWRITE(sms_store_control_r, sms_store_control_w) /* Control */
|
||||||
|
AM_RANGE(0xc000, 0xc000) AM_READWRITE(sms_store_cart_select_r, sms_store_cart_select_w) /* cartridge/card slot selector */
|
||||||
|
AM_RANGE(0xd800, 0xd800) AM_READ(sms_store_select1) /* Game selector port #1 */
|
||||||
|
AM_RANGE(0xdc00, 0xdc00) AM_READ(sms_store_select2) /* Game selector port #2 */
|
||||||
|
ADDRESS_MAP_END
|
||||||
|
|
||||||
|
static ADDRESS_MAP_START( sms_io, AS_IO, 8 )
|
||||||
|
ADDRESS_MAP_GLOBAL_MASK(0xff)
|
||||||
|
ADDRESS_MAP_UNMAP_HIGH
|
||||||
|
AM_RANGE(0x00, 0x00) AM_MIRROR(0x3e) AM_WRITE(sms_bios_w)
|
||||||
|
AM_RANGE(0x01, 0x01) AM_MIRROR(0x3e) AM_WRITE(sms_io_control_w)
|
||||||
|
AM_RANGE(0x40, 0x7f) AM_READ(sms_count_r)
|
||||||
|
AM_RANGE(0x40, 0x7f) AM_DEVWRITE("smsiii", sn76496_w)
|
||||||
|
AM_RANGE(0x80, 0x80) AM_MIRROR(0x3e) AM_DEVREADWRITE("sms_vdp", sms_vdp_data_r, sms_vdp_data_w)
|
||||||
|
AM_RANGE(0x81, 0x81) AM_MIRROR(0x3e) AM_DEVREADWRITE("sms_vdp", sms_vdp_ctrl_r, sms_vdp_ctrl_w)
|
||||||
|
AM_RANGE(0xc0, 0xc0) AM_MIRROR(0x1e) AM_READ(sms_input_port_0_r)
|
||||||
|
AM_RANGE(0xc1, 0xc1) AM_MIRROR(0x1e) AM_READ(sms_input_port_1_r)
|
||||||
|
AM_RANGE(0xe0, 0xe0) AM_MIRROR(0x0e) AM_READ(sms_input_port_0_r)
|
||||||
|
AM_RANGE(0xe1, 0xe1) AM_MIRROR(0x0e) AM_READ(sms_input_port_1_r)
|
||||||
|
AM_RANGE(0xf0, 0xf0) AM_READWRITE(sms_input_port_0_r, sms_ym2413_register_port_0_w)
|
||||||
|
AM_RANGE(0xf1, 0xf1) AM_READWRITE(sms_input_port_1_r, sms_ym2413_data_port_0_w)
|
||||||
|
AM_RANGE(0xf2, 0xf2) AM_READWRITE(sms_fm_detect_r, sms_fm_detect_w)
|
||||||
|
AM_RANGE(0xf3, 0xf3) AM_READ(sms_input_port_1_r)
|
||||||
|
AM_RANGE(0xf4, 0xf4) AM_MIRROR(0x02) AM_READ(sms_input_port_0_r)
|
||||||
|
AM_RANGE(0xf5, 0xf5) AM_MIRROR(0x02) AM_READ(sms_input_port_1_r)
|
||||||
|
AM_RANGE(0xf8, 0xf8) AM_MIRROR(0x06) AM_READ(sms_input_port_0_r)
|
||||||
|
AM_RANGE(0xf9, 0xf9) AM_MIRROR(0x06) AM_READ(sms_input_port_1_r)
|
||||||
|
ADDRESS_MAP_END
|
||||||
|
|
||||||
|
static ADDRESS_MAP_START( gg_io, AS_IO, 8 )
|
||||||
|
ADDRESS_MAP_GLOBAL_MASK(0xff)
|
||||||
|
ADDRESS_MAP_UNMAP_HIGH
|
||||||
|
AM_RANGE(0x00, 0x00) AM_READ(gg_input_port_2_r)
|
||||||
|
AM_RANGE(0x01, 0x05) AM_READWRITE(gg_sio_r, gg_sio_w)
|
||||||
|
AM_RANGE(0x06, 0x06) AM_DEVWRITE("gamegear", sn76496_stereo_w)
|
||||||
|
AM_RANGE(0x07, 0x07) AM_WRITE(sms_io_control_w)
|
||||||
|
AM_RANGE(0x08, 0x08) AM_MIRROR(0x06) AM_WRITE(sms_bios_w)
|
||||||
|
AM_RANGE(0x09, 0x09) AM_MIRROR(0x06) AM_WRITE(sms_io_control_w)
|
||||||
|
AM_RANGE(0x10, 0x10) AM_MIRROR(0x0e) AM_WRITE(sms_bios_w)
|
||||||
|
AM_RANGE(0x11, 0x11) AM_MIRROR(0x0e) AM_WRITE(sms_io_control_w)
|
||||||
|
AM_RANGE(0x20, 0x20) AM_MIRROR(0x1e) AM_WRITE(sms_bios_w)
|
||||||
|
AM_RANGE(0x21, 0x21) AM_MIRROR(0x1e) AM_WRITE(sms_io_control_w)
|
||||||
|
AM_RANGE(0x40, 0x7f) AM_READ(sms_count_r)
|
||||||
|
AM_RANGE(0x40, 0x7f) AM_DEVWRITE("gamegear", sn76496_w)
|
||||||
|
AM_RANGE(0x80, 0x80) AM_MIRROR(0x3e) AM_DEVREADWRITE("sms_vdp", sms_vdp_data_r, sms_vdp_data_w)
|
||||||
|
AM_RANGE(0x81, 0x81) AM_MIRROR(0x3e) AM_DEVREADWRITE("sms_vdp", sms_vdp_ctrl_r, sms_vdp_ctrl_w)
|
||||||
|
AM_RANGE(0xc0, 0xc0) AM_READ_PORT("PORT_DC")
|
||||||
|
AM_RANGE(0xc1, 0xc1) AM_READ_PORT("PORT_DD")
|
||||||
|
AM_RANGE(0xdc, 0xdc) AM_READ_PORT("PORT_DC")
|
||||||
|
AM_RANGE(0xdd, 0xdd) AM_READ_PORT("PORT_DD")
|
||||||
|
ADDRESS_MAP_END
|
||||||
|
|
||||||
|
|
||||||
|
static INPUT_PORTS_START( sms )
|
||||||
|
PORT_START("PORT_DC")
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_CATEGORY(10) PORT_PLAYER(1) PORT_8WAY
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(10) PORT_PLAYER(1) PORT_8WAY
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(10) PORT_PLAYER(1) PORT_8WAY
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(10) PORT_PLAYER(1) PORT_8WAY
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CATEGORY(10) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CATEGORY(10) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_CATEGORY(20) PORT_PLAYER(2) PORT_8WAY
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(20) PORT_PLAYER(2) PORT_8WAY
|
||||||
|
|
||||||
|
PORT_START("PORT_DD")
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(20) PORT_PLAYER(2) PORT_8WAY
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(20) PORT_PLAYER(2) PORT_8WAY
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CATEGORY(20) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CATEGORY(20) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) /* Software Reset bit */
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) /* Port A TH */
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) /* Port B TH */
|
||||||
|
|
||||||
|
PORT_START("PAUSE")
|
||||||
|
PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START ) PORT_NAME(DEF_STR(Pause))
|
||||||
|
|
||||||
|
PORT_START("LPHASER0") /* Light phaser X - player 1 */
|
||||||
|
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR( X, 1.0, 0.0, 0 ) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) PORT_CATEGORY(11) PORT_PLAYER(1) PORT_CHANGED(lgun1_changed, NULL)
|
||||||
|
|
||||||
|
PORT_START("LPHASER1") /* Light phaser Y - player 1 */
|
||||||
|
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR( Y, 1.0, 0.0, 0 ) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) PORT_CATEGORY(11) PORT_PLAYER(1) PORT_CHANGED(lgun1_changed, NULL)
|
||||||
|
|
||||||
|
PORT_START("LPHASER2") /* Light phaser X - player 2 */
|
||||||
|
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR( X, 1.0, 0.0, 0 ) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) PORT_CATEGORY(21) PORT_PLAYER(2) PORT_CHANGED(lgun2_changed, NULL)
|
||||||
|
|
||||||
|
PORT_START("LPHASER3") /* Light phaser Y - player 2 */
|
||||||
|
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR( Y, 1.0, 0.0, 0 ) PORT_SENSITIVITY(50) PORT_KEYDELTA(25) PORT_CATEGORY(21) PORT_PLAYER(2) PORT_CHANGED(lgun2_changed, NULL)
|
||||||
|
|
||||||
|
PORT_START("RFU") /* Rapid Fire Unit */
|
||||||
|
PORT_CONFNAME( 0x03, 0x00, "Rapid Fire Unit - Player 1" )
|
||||||
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
||||||
|
PORT_CONFSETTING( 0x01, "Button A" )
|
||||||
|
PORT_CONFSETTING( 0x02, "Button B" )
|
||||||
|
PORT_CONFSETTING( 0x03, "Button A + B" )
|
||||||
|
PORT_CONFNAME( 0x0c, 0x00, "Rapid Fire Unit - Player 2" )
|
||||||
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
||||||
|
PORT_CONFSETTING( 0x04, "Button A" )
|
||||||
|
PORT_CONFSETTING( 0x08, "Button B" )
|
||||||
|
PORT_CONFSETTING( 0x0c, "Button A + B" )
|
||||||
|
|
||||||
|
PORT_START("PADDLE0") /* Paddle player 1 */
|
||||||
|
PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(20) PORT_CENTERDELTA(0) PORT_MINMAX(0,255) PORT_CATEGORY(12) PORT_PLAYER(1)
|
||||||
|
|
||||||
|
PORT_START("PADDLE1") /* Paddle player 2 */
|
||||||
|
PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(20) PORT_CENTERDELTA(0) PORT_MINMAX(0,255) PORT_CATEGORY(22) PORT_PLAYER(2)
|
||||||
|
|
||||||
|
PORT_START("CTRLIPT") /* Light Phaser and Paddle Control buttons */
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CATEGORY(11) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CATEGORY(12) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CATEGORY(13) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CATEGORY(13) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CATEGORY(21) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CATEGORY(22) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CATEGORY(23) PORT_PLAYER(2)
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CATEGORY(23) PORT_PLAYER(2)
|
||||||
|
|
||||||
|
PORT_START("CTRLSEL") /* Controller selection */
|
||||||
|
PORT_CATEGORY_CLASS( 0x0f, 0x00, "Player 1 Controller" )
|
||||||
|
PORT_CATEGORY_ITEM( 0x00, DEF_STR( Joystick ), 10 )
|
||||||
|
PORT_CATEGORY_ITEM( 0x01, "Light Phaser", 11 )
|
||||||
|
PORT_CATEGORY_ITEM( 0x02, "Sega Paddle Control", 12 )
|
||||||
|
PORT_CATEGORY_ITEM( 0x03, "Sega Sports Pad", 13 )
|
||||||
|
PORT_CATEGORY_CLASS( 0xf0, 0x00, "Player 2 Controller" )
|
||||||
|
PORT_CATEGORY_ITEM( 0x00, DEF_STR( Joystick ), 20 )
|
||||||
|
PORT_CATEGORY_ITEM( 0x10, "Light Phaser", 21 )
|
||||||
|
PORT_CATEGORY_ITEM( 0x20, "Sega Paddle Control", 22 )
|
||||||
|
PORT_CATEGORY_ITEM( 0x30, "Sega Sports Pad", 23 )
|
||||||
|
|
||||||
|
PORT_START("SPORT0") /* Player 1 Sports Pad X axis */
|
||||||
|
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) PORT_RESET PORT_REVERSE PORT_CATEGORY(13) PORT_PLAYER(1)
|
||||||
|
|
||||||
|
PORT_START("SPORT1") /* Player 1 Sports Pad Y axis */
|
||||||
|
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) PORT_RESET PORT_REVERSE PORT_CATEGORY(13) PORT_PLAYER(1)
|
||||||
|
|
||||||
|
PORT_START("SPORT2") /* Player 2 Sports Pad X axis */
|
||||||
|
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) PORT_RESET PORT_REVERSE PORT_CATEGORY(23) PORT_PLAYER(2)
|
||||||
|
|
||||||
|
PORT_START("SPORT3") /* Player 2 Sports Pad Y axis */
|
||||||
|
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) PORT_RESET PORT_REVERSE PORT_CATEGORY(23) PORT_PLAYER(2)
|
||||||
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
static INPUT_PORTS_START( sms1 )
|
||||||
|
PORT_INCLUDE( sms )
|
||||||
|
|
||||||
|
PORT_START("RESET")
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("Reset Button")
|
||||||
|
|
||||||
|
PORT_START("SEGASCOPE")
|
||||||
|
PORT_CONFNAME( 0x01, 0x00, "SegaScope (3-D Glasses)" )
|
||||||
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
||||||
|
PORT_CONFSETTING( 0x01, DEF_STR( On ) )
|
||||||
|
|
||||||
|
PORT_START("SSCOPE_BINOCULAR")
|
||||||
|
PORT_CONFNAME( 0x03, 0x00, "SegaScope - Binocular Hack" ) PORT_CONDITION("SEGASCOPE", 0x01, PORTCOND_EQUALS, 0x01)
|
||||||
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
||||||
|
PORT_CONFSETTING( 0x01, "Left Lens" )
|
||||||
|
PORT_CONFSETTING( 0x02, "Right Lens" )
|
||||||
|
PORT_CONFSETTING( 0x03, "Both Lens" )
|
||||||
|
PORT_BIT( 0x03, 0x00, IPT_UNUSED ) PORT_CONDITION("SEGASCOPE", 0x01, PORTCOND_EQUALS, 0x00)
|
||||||
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
static INPUT_PORTS_START( smsj )
|
||||||
|
PORT_INCLUDE( sms1 )
|
||||||
|
|
||||||
|
PORT_START("TVDRAW")
|
||||||
|
PORT_CONFNAME( 0x01, 0x00, "Terebi Oekaki Graphics Tablet" )
|
||||||
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
||||||
|
PORT_CONFSETTING( 0x01, DEF_STR( On ) )
|
||||||
|
|
||||||
|
PORT_START("TVDRAW_X")
|
||||||
|
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Tablet - X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_PLAYER(1)
|
||||||
|
PORT_CONDITION("TVDRAW", 0x01, PORTCOND_EQUALS, 0x01)
|
||||||
|
|
||||||
|
PORT_START("TVDRAW_Y")
|
||||||
|
PORT_BIT( 0xff, 0x60, IPT_LIGHTGUN_Y ) PORT_NAME("Tablet - Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(0, 191) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_PLAYER(1)
|
||||||
|
PORT_CONDITION("TVDRAW", 0x01, PORTCOND_EQUALS, 0x01)
|
||||||
|
|
||||||
|
PORT_START("TVDRAW_PEN")
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Tablet - Pen") PORT_CONDITION("TVDRAW", 0x01, PORTCOND_EQUALS, 0x01)
|
||||||
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
static INPUT_PORTS_START( gg )
|
||||||
|
PORT_START("PORT_DC")
|
||||||
|
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY
|
||||||
|
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_8WAY
|
||||||
|
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_8WAY
|
||||||
|
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_8WAY
|
||||||
|
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
|
||||||
|
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||||
|
|
||||||
|
PORT_START("PORT_DD")
|
||||||
|
PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||||
|
|
||||||
|
PORT_START("START")
|
||||||
|
PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||||
|
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("Start") /* Game Gear START */
|
||||||
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
static PALETTE_INIT( sms )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
int r = i & 0x03;
|
||||||
|
int g = (i & 0x0c) >> 2;
|
||||||
|
int b = (i & 0x30) >> 4;
|
||||||
|
palette_set_color_rgb(machine, i, r << 6, g << 6, b << 6);
|
||||||
|
}
|
||||||
|
/* TMS9918 palette */
|
||||||
|
palette_set_color_rgb(machine, 64+ 0, 0, 0, 0);
|
||||||
|
palette_set_color_rgb(machine, 64+ 1, 0, 0, 0);
|
||||||
|
palette_set_color_rgb(machine, 64+ 2, 33, 200, 66);
|
||||||
|
palette_set_color_rgb(machine, 64+ 3, 94, 220, 120);
|
||||||
|
palette_set_color_rgb(machine, 64+ 4, 84, 85, 237);
|
||||||
|
palette_set_color_rgb(machine, 64+ 5, 125, 118, 252);
|
||||||
|
palette_set_color_rgb(machine, 64+ 6, 212, 82, 77);
|
||||||
|
palette_set_color_rgb(machine, 64+ 7, 66, 235, 245);
|
||||||
|
palette_set_color_rgb(machine, 64+ 8, 252, 85, 84);
|
||||||
|
palette_set_color_rgb(machine, 64+ 9, 255, 121, 120);
|
||||||
|
palette_set_color_rgb(machine, 64+10, 212, 193, 84);
|
||||||
|
palette_set_color_rgb(machine, 64+11, 230, 206, 128);
|
||||||
|
palette_set_color_rgb(machine, 64+12, 33, 176, 59);
|
||||||
|
palette_set_color_rgb(machine, 64+13, 201, 91, 186);
|
||||||
|
palette_set_color_rgb(machine, 64+14, 204, 204, 204);
|
||||||
|
palette_set_color_rgb(machine, 64+15, 255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PALETTE_INIT( gamegear )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 4096; i++)
|
||||||
|
{
|
||||||
|
int r = i & 0x000f;
|
||||||
|
int g = (i & 0x00f0) >> 4;
|
||||||
|
int b = (i & 0x0f00) >> 8;
|
||||||
|
palette_set_color_rgb(machine, i, r << 4, g << 4, b << 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void sms_int_callback( running_machine &machine, int state )
|
||||||
|
{
|
||||||
|
cputag_set_input_line(machine, "maincpu", 0, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const smsvdp_interface _315_5124_intf =
|
||||||
|
{
|
||||||
|
MODEL_315_5124,
|
||||||
|
sms_int_callback,
|
||||||
|
sms_pause_callback
|
||||||
|
};
|
||||||
|
|
||||||
|
static const smsvdp_interface _315_5246_intf =
|
||||||
|
{
|
||||||
|
MODEL_315_5246,
|
||||||
|
sms_int_callback,
|
||||||
|
sms_pause_callback
|
||||||
|
};
|
||||||
|
|
||||||
|
static const smsvdp_interface _315_5378_intf =
|
||||||
|
{
|
||||||
|
MODEL_315_5378,
|
||||||
|
sms_int_callback,
|
||||||
|
sms_pause_callback
|
||||||
|
};
|
||||||
|
|
||||||
|
static const smsvdp_interface sms_store_intf =
|
||||||
|
{
|
||||||
|
MODEL_315_5124,
|
||||||
|
sms_store_int_callback,
|
||||||
|
sms_pause_callback
|
||||||
|
};
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_FRAGMENT( sms_cartslot )
|
||||||
|
MCFG_CARTSLOT_ADD("cart1")
|
||||||
|
MCFG_CARTSLOT_EXTENSION_LIST("sms,bin")
|
||||||
|
MCFG_CARTSLOT_NOT_MANDATORY
|
||||||
|
MCFG_CARTSLOT_INTERFACE("sms_cart")
|
||||||
|
MCFG_CARTSLOT_START(sms_cart)
|
||||||
|
MCFG_CARTSLOT_LOAD(sms_cart)
|
||||||
|
|
||||||
|
MCFG_SOFTWARE_LIST_ADD("cart_list","sms")
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_FRAGMENT( gg_cartslot )
|
||||||
|
MCFG_CARTSLOT_ADD("cart1")
|
||||||
|
MCFG_CARTSLOT_EXTENSION_LIST("gg,bin")
|
||||||
|
MCFG_CARTSLOT_MANDATORY
|
||||||
|
MCFG_CARTSLOT_INTERFACE("gamegear_cart")
|
||||||
|
MCFG_CARTSLOT_START(sms_cart)
|
||||||
|
MCFG_CARTSLOT_LOAD(sms_cart)
|
||||||
|
|
||||||
|
MCFG_SOFTWARE_LIST_ADD("cart_list","gamegear")
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_START( sms_ntsc_base, sms_state )
|
||||||
|
/* basic machine hardware */
|
||||||
|
MCFG_CPU_ADD("maincpu", Z80, XTAL_53_693175MHz/15)
|
||||||
|
MCFG_CPU_PROGRAM_MAP(sms_mem)
|
||||||
|
MCFG_CPU_IO_MAP(sms_io)
|
||||||
|
|
||||||
|
MCFG_QUANTUM_TIME(attotime::from_hz(60))
|
||||||
|
|
||||||
|
MCFG_MACHINE_START(sms)
|
||||||
|
MCFG_MACHINE_RESET(sms)
|
||||||
|
|
||||||
|
/* sound hardware */
|
||||||
|
MCFG_SPEAKER_STANDARD_MONO("mono")
|
||||||
|
MCFG_SOUND_ADD("smsiii", SMSIII, XTAL_53_693175MHz/15)
|
||||||
|
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
|
||||||
|
|
||||||
|
MCFG_FRAGMENT_ADD( sms_cartslot )
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_DERIVED( sms2_ntsc, sms_ntsc_base )
|
||||||
|
/* video hardware */
|
||||||
|
MCFG_SCREEN_ADD("screen", RASTER)
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(XTAL_53_693175MHz/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS - 2, LBORDER_START + LBORDER_X_PIXELS + 256 + 10, NTSC_Y_PIXELS, TBORDER_START + NTSC_224_TBORDER_Y_PIXELS, TBORDER_START + NTSC_224_TBORDER_Y_PIXELS + 224)
|
||||||
|
MCFG_SCREEN_UPDATE(sms)
|
||||||
|
|
||||||
|
MCFG_PALETTE_LENGTH(64+16)
|
||||||
|
MCFG_PALETTE_INIT(sms)
|
||||||
|
|
||||||
|
MCFG_SMSVDP_ADD("sms_vdp", _315_5246_intf)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_DERIVED( sms1_ntsc, sms_ntsc_base )
|
||||||
|
|
||||||
|
MCFG_CPU_MODIFY("maincpu")
|
||||||
|
MCFG_CPU_PROGRAM_MAP(sms1_mem) // This adds the SegaScope handlers for 3-D glasses
|
||||||
|
MCFG_CPU_IO_MAP(sms_io)
|
||||||
|
|
||||||
|
/* video hardware */
|
||||||
|
MCFG_SCREEN_ADD("screen", RASTER)
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(XTAL_53_693175MHz/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS - 2, LBORDER_START + LBORDER_X_PIXELS + 256 + 10, NTSC_Y_PIXELS, TBORDER_START + NTSC_224_TBORDER_Y_PIXELS, TBORDER_START + NTSC_224_TBORDER_Y_PIXELS + 224)
|
||||||
|
MCFG_SCREEN_UPDATE(sms1)
|
||||||
|
|
||||||
|
MCFG_SCREEN_ADD("left_lcd", LCD) // This is needed for SegaScope Left LCD
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(XTAL_53_693175MHz/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS - 2, LBORDER_START + LBORDER_X_PIXELS + 256 + 10, NTSC_Y_PIXELS, TBORDER_START + NTSC_224_TBORDER_Y_PIXELS, TBORDER_START + NTSC_224_TBORDER_Y_PIXELS + 224)
|
||||||
|
MCFG_SCREEN_UPDATE(sms1)
|
||||||
|
|
||||||
|
MCFG_SCREEN_ADD("right_lcd", LCD) // This is needed for SegaScope Right LCD
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(XTAL_53_693175MHz/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS - 2, LBORDER_START + LBORDER_X_PIXELS + 256 + 10, NTSC_Y_PIXELS, TBORDER_START + NTSC_224_TBORDER_Y_PIXELS, TBORDER_START + NTSC_224_TBORDER_Y_PIXELS + 224)
|
||||||
|
MCFG_SCREEN_UPDATE(sms1)
|
||||||
|
|
||||||
|
MCFG_DEFAULT_LAYOUT(layout_sms1)
|
||||||
|
|
||||||
|
MCFG_PALETTE_LENGTH(64+16)
|
||||||
|
MCFG_PALETTE_INIT(sms)
|
||||||
|
|
||||||
|
MCFG_VIDEO_START(sms1)
|
||||||
|
|
||||||
|
MCFG_SMSVDP_ADD("sms_vdp", _315_5124_intf)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
#define MCFG_SMSSDISP_CARTSLOT_ADD(_tag) \
|
||||||
|
MCFG_CARTSLOT_ADD(_tag) \
|
||||||
|
MCFG_CARTSLOT_EXTENSION_LIST("sms,bin") \
|
||||||
|
MCFG_CARTSLOT_NOT_MANDATORY \
|
||||||
|
MCFG_CARTSLOT_INTERFACE("sms_cart") \
|
||||||
|
MCFG_CARTSLOT_START(sms_cart) \
|
||||||
|
MCFG_CARTSLOT_LOAD(sms_cart)
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_DERIVED( sms_sdisp, sms2_ntsc )
|
||||||
|
|
||||||
|
MCFG_DEVICE_REMOVE("sms_vdp")
|
||||||
|
MCFG_SMSVDP_ADD("sms_vdp", sms_store_intf)
|
||||||
|
|
||||||
|
MCFG_CPU_ADD("control", Z80, XTAL_53_693175MHz/15)
|
||||||
|
MCFG_CPU_PROGRAM_MAP(sms_store_mem)
|
||||||
|
/* Both CPUs seem to communicate with the VDP etc? */
|
||||||
|
MCFG_CPU_IO_MAP(sms_io)
|
||||||
|
|
||||||
|
MCFG_CARTSLOT_MODIFY("cart1")
|
||||||
|
MCFG_CARTSLOT_EXTENSION_LIST("sms,bin")
|
||||||
|
MCFG_CARTSLOT_MANDATORY
|
||||||
|
MCFG_CARTSLOT_INTERFACE("sms_cart")
|
||||||
|
MCFG_CARTSLOT_START(sms_cart)
|
||||||
|
MCFG_CARTSLOT_LOAD(sms_cart)
|
||||||
|
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart2")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart3")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart4")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart5")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart6")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart7")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart8")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart9")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart10")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart11")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart12")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart13")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart14")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart15")
|
||||||
|
MCFG_SMSSDISP_CARTSLOT_ADD("cart16")
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_START( sms_pal_base, sms_state )
|
||||||
|
/* basic machine hardware */
|
||||||
|
MCFG_CPU_ADD("maincpu", Z80, MASTER_CLOCK_PAL/15)
|
||||||
|
MCFG_CPU_PROGRAM_MAP(sms_mem)
|
||||||
|
MCFG_CPU_IO_MAP(sms_io)
|
||||||
|
|
||||||
|
MCFG_QUANTUM_TIME(attotime::from_hz(60))
|
||||||
|
|
||||||
|
MCFG_MACHINE_START(sms)
|
||||||
|
MCFG_MACHINE_RESET(sms)
|
||||||
|
|
||||||
|
/* sound hardware */
|
||||||
|
MCFG_SPEAKER_STANDARD_MONO("mono")
|
||||||
|
MCFG_SOUND_ADD("smsiii", SMSIII, MASTER_CLOCK_PAL/15)
|
||||||
|
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
|
||||||
|
|
||||||
|
MCFG_FRAGMENT_ADD( sms_cartslot )
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_DERIVED( sms2_pal, sms_pal_base )
|
||||||
|
|
||||||
|
/* video hardware */
|
||||||
|
MCFG_SCREEN_ADD("screen", RASTER)
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(MASTER_CLOCK_PAL/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS - 2, LBORDER_START + LBORDER_X_PIXELS + 256 + 10, PAL_Y_PIXELS, TBORDER_START + PAL_240_TBORDER_Y_PIXELS, TBORDER_START + PAL_240_TBORDER_Y_PIXELS + 240)
|
||||||
|
MCFG_SCREEN_UPDATE(sms)
|
||||||
|
|
||||||
|
MCFG_PALETTE_LENGTH(64+16)
|
||||||
|
MCFG_PALETTE_INIT(sms)
|
||||||
|
|
||||||
|
MCFG_SMSVDP_ADD("sms_vdp", _315_5246_intf)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_DERIVED( sms1_pal, sms_pal_base )
|
||||||
|
|
||||||
|
MCFG_CPU_MODIFY("maincpu")
|
||||||
|
MCFG_CPU_PROGRAM_MAP(sms1_mem) // This adds the SegaScope handlers for 3-D glasses
|
||||||
|
MCFG_CPU_IO_MAP(sms_io)
|
||||||
|
|
||||||
|
/* video hardware */
|
||||||
|
MCFG_SCREEN_ADD("screen", RASTER)
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(MASTER_CLOCK_PAL/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS - 2, LBORDER_START + LBORDER_X_PIXELS + 256 + 10, PAL_Y_PIXELS, TBORDER_START + PAL_240_TBORDER_Y_PIXELS, TBORDER_START + PAL_240_TBORDER_Y_PIXELS + 240)
|
||||||
|
MCFG_SCREEN_UPDATE(sms1)
|
||||||
|
|
||||||
|
MCFG_SCREEN_ADD("left_lcd", LCD) // This is needed for SegaScope Left LCD
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(MASTER_CLOCK_PAL/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS - 2, LBORDER_START + LBORDER_X_PIXELS + 256 + 10, PAL_Y_PIXELS, TBORDER_START + PAL_240_TBORDER_Y_PIXELS, TBORDER_START + PAL_240_TBORDER_Y_PIXELS + 240)
|
||||||
|
MCFG_SCREEN_UPDATE(sms1)
|
||||||
|
|
||||||
|
MCFG_SCREEN_ADD("right_lcd", LCD) // This is needed for SegaScope Right LCD
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(MASTER_CLOCK_PAL/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS - 2, LBORDER_START + LBORDER_X_PIXELS + 256 + 10, PAL_Y_PIXELS, TBORDER_START + PAL_240_TBORDER_Y_PIXELS, TBORDER_START + PAL_240_TBORDER_Y_PIXELS + 240)
|
||||||
|
MCFG_SCREEN_UPDATE(sms1)
|
||||||
|
|
||||||
|
MCFG_PALETTE_LENGTH(64+16)
|
||||||
|
MCFG_PALETTE_INIT(sms)
|
||||||
|
|
||||||
|
MCFG_DEFAULT_LAYOUT(layout_sms1)
|
||||||
|
|
||||||
|
MCFG_SMSVDP_ADD("sms_vdp", _315_5124_intf)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_DERIVED( sms_fm, sms1_ntsc )
|
||||||
|
|
||||||
|
MCFG_SOUND_ADD("ym2413", YM2413, XTAL_53_693175MHz/15)
|
||||||
|
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_DERIVED( sg1000m3, sms_fm )
|
||||||
|
|
||||||
|
MCFG_CARTSLOT_MODIFY("cart1")
|
||||||
|
MCFG_CARTSLOT_EXTENSION_LIST("sms,bin,sg")
|
||||||
|
MCFG_CARTSLOT_MANDATORY
|
||||||
|
MCFG_CARTSLOT_START(sms_cart)
|
||||||
|
MCFG_CARTSLOT_LOAD(sms_cart)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_DERIVED( sms2_fm, sms2_ntsc )
|
||||||
|
|
||||||
|
MCFG_SOUND_ADD("ym2413", YM2413, XTAL_53_693175MHz/15)
|
||||||
|
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_START( gamegear, sms_state )
|
||||||
|
/* basic machine hardware */
|
||||||
|
MCFG_CPU_ADD("maincpu", Z80, XTAL_53_693175MHz/15)
|
||||||
|
MCFG_CPU_PROGRAM_MAP(sms_mem)
|
||||||
|
MCFG_CPU_IO_MAP(gg_io)
|
||||||
|
|
||||||
|
MCFG_QUANTUM_TIME(attotime::from_hz(60))
|
||||||
|
|
||||||
|
MCFG_MACHINE_START(sms)
|
||||||
|
MCFG_MACHINE_RESET(sms)
|
||||||
|
|
||||||
|
/* video hardware */
|
||||||
|
MCFG_SCREEN_ADD("screen", LCD)
|
||||||
|
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
|
||||||
|
MCFG_SCREEN_RAW_PARAMS(XTAL_53_693175MHz/10, SMS_X_PIXELS, LBORDER_START + LBORDER_X_PIXELS + 6*8, LBORDER_START + LBORDER_X_PIXELS + 26*8, NTSC_Y_PIXELS, TBORDER_START + NTSC_192_TBORDER_Y_PIXELS + 3*8, TBORDER_START + NTSC_192_TBORDER_Y_PIXELS + 21*8 )
|
||||||
|
MCFG_SCREEN_UPDATE(gamegear)
|
||||||
|
|
||||||
|
MCFG_PALETTE_LENGTH(4096)
|
||||||
|
MCFG_PALETTE_INIT(gamegear)
|
||||||
|
|
||||||
|
MCFG_VIDEO_START(gamegear)
|
||||||
|
|
||||||
|
MCFG_SMSVDP_ADD("sms_vdp", _315_5378_intf)
|
||||||
|
|
||||||
|
/* sound hardware */
|
||||||
|
MCFG_SPEAKER_STANDARD_STEREO("lspeaker","rspeaker")
|
||||||
|
MCFG_SOUND_ADD("gamegear", GAMEGEAR, XTAL_53_693175MHz/15)
|
||||||
|
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||||
|
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||||
|
|
||||||
|
/* cartridge */
|
||||||
|
MCFG_FRAGMENT_ADD( gg_cartslot )
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
|
||||||
|
ROM_START(sms1)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0xff)
|
||||||
|
|
||||||
|
ROM_REGION(0x20000, "user1", 0)
|
||||||
|
ROM_SYSTEM_BIOS( 0, "bios13", "US/European BIOS v1.3 (1986)" )
|
||||||
|
ROMX_LOAD("bios13fx.rom", 0x0000, 0x2000, CRC(0072ED54) SHA1(c315672807d8ddb8d91443729405c766dd95cae7), ROM_BIOS(1))
|
||||||
|
ROM_SYSTEM_BIOS( 1, "hangonsh", "US/European BIOS v2.4 with Hang On and Safari Hunt (1988)" )
|
||||||
|
ROMX_LOAD("hshbios.rom", 0x0000, 0x20000, CRC(91E93385) SHA1(9e179392cd416af14024d8f31c981d9ee9a64517), ROM_BIOS(2))
|
||||||
|
ROM_SYSTEM_BIOS( 2, "hangon", "US/European BIOS v3.4 with Hang On (1988)" )
|
||||||
|
ROMX_LOAD("hangbios.rom", 0x0000, 0x20000, CRC(8EDF7AC6) SHA1(51fd6d7990f62cd9d18c9ecfc62ed7936169107e), ROM_BIOS(3))
|
||||||
|
ROM_SYSTEM_BIOS( 3, "missiled", "US/European BIOS v4.4 with Missile Defense 3D (1988)" )
|
||||||
|
ROMX_LOAD("missiled.rom", 0x0000, 0x20000, CRC(E79BB689) SHA1(aa92ae576ca670b00855e278378d89e9f85e0351), ROM_BIOS(4))
|
||||||
|
ROM_SYSTEM_BIOS( 4, "proto", "US Master System Prototype BIOS" )
|
||||||
|
ROMX_LOAD("m404prot.rom", 0x0000, 0x2000, CRC(1a15dfcc) SHA1(4a06c8e66261611dce0305217c42138b71331701), ROM_BIOS(5))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START(sms)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0xff)
|
||||||
|
|
||||||
|
ROM_REGION(0x20000, "user1", 0)
|
||||||
|
ROM_SYSTEM_BIOS( 0, "alexkidd", "US/European BIOS with Alex Kidd in Miracle World (1990)" )
|
||||||
|
ROMX_LOAD("akbios.rom", 0x0000, 0x20000, CRC(CF4A09EA) SHA1(3af7b66248d34eb26da40c92bf2fa4c73a46a051), ROM_BIOS(1))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START(smssdisp)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0x00)
|
||||||
|
|
||||||
|
ROM_REGION(0x4000, "user1", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0xff)
|
||||||
|
|
||||||
|
ROM_REGION(0x4000, "control", 0)
|
||||||
|
ROM_LOAD("smssdisp.rom", 0x0000, 0x4000, CRC(ee2c29ba) SHA1(fc465122134d95363112eb51b9ab71db3576cefd))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START(sms1pal)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0xff)
|
||||||
|
|
||||||
|
ROM_REGION(0x20000, "user1", 0)
|
||||||
|
ROM_SYSTEM_BIOS( 0, "bios13", "US/European BIOS v1.3 (1986)" )
|
||||||
|
ROMX_LOAD("bios13fx.rom", 0x0000, 0x2000, CRC(0072ED54) SHA1(c315672807d8ddb8d91443729405c766dd95cae7), ROM_BIOS(1))
|
||||||
|
ROM_SYSTEM_BIOS( 1, "hangonsh", "US/European BIOS v2.4 with Hang On and Safari Hunt (1988)" )
|
||||||
|
ROMX_LOAD("hshbios.rom", 0x0000, 0x20000, CRC(91E93385) SHA1(9e179392cd416af14024d8f31c981d9ee9a64517), ROM_BIOS(2))
|
||||||
|
ROM_SYSTEM_BIOS( 2, "hangon", "Sega Master System - US/European BIOS v3.4 with Hang On (1988)" )
|
||||||
|
ROMX_LOAD("hangbios.rom", 0x0000, 0x20000, CRC(8EDF7AC6) SHA1(51fd6d7990f62cd9d18c9ecfc62ed7936169107e), ROM_BIOS(3))
|
||||||
|
ROM_SYSTEM_BIOS( 3, "missiled", "US/European BIOS v4.4 with Missile Defense 3D (1988)" )
|
||||||
|
ROMX_LOAD("missiled.rom", 0x0000, 0x20000, CRC(E79BB689) SHA1(aa92ae576ca670b00855e278378d89e9f85e0351), ROM_BIOS(4))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START(smspal)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0xff)
|
||||||
|
|
||||||
|
ROM_REGION(0x40000, "user1", 0)
|
||||||
|
ROM_SYSTEM_BIOS( 0, "alexkidd", "US/European BIOS with Alex Kidd in Miracle World (1990)" )
|
||||||
|
ROMX_LOAD("akbios.rom", 0x0000, 0x20000, CRC(CF4A09EA) SHA1(3af7b66248d34eb26da40c92bf2fa4c73a46a051), ROM_BIOS(1))
|
||||||
|
ROM_SYSTEM_BIOS( 1, "sonic", "European/Brazilian BIOS with Sonic the Hedgehog (1991)" )
|
||||||
|
ROMX_LOAD("sonbios.rom", 0x0000, 0x40000, CRC(81C3476B) SHA1(6aca0e3dffe461ba1cb11a86cd4caf5b97e1b8df), ROM_BIOS(2))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START(sg1000m3)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0x00)
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START(smsj)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0xff)
|
||||||
|
|
||||||
|
ROM_REGION(0x4000, "user1", 0)
|
||||||
|
ROM_SYSTEM_BIOS( 0, "jbios21", "Japanese BIOS v2.1 (1987)" )
|
||||||
|
ROMX_LOAD("jbios21.rom", 0x0000, 0x2000, CRC(48D44A13) SHA1(a8c1b39a2e41137835eda6a5de6d46dd9fadbaf2), ROM_BIOS(1))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START(sms2kr)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0xff)
|
||||||
|
|
||||||
|
ROM_REGION(0x20000, "user1", 0)
|
||||||
|
ROM_SYSTEM_BIOS( 0, "akbioskr", "Samsung Gam*Boy II with Alex Kidd in Miracle World (1990)" )
|
||||||
|
ROMX_LOAD("akbioskr.rom", 0x000, 0x20000, CRC(9c5bad91) SHA1(2feafd8f1c40fdf1bd5668f8c5c02e5560945b17), ROM_BIOS(1))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
ROM_START(gamegear)
|
||||||
|
ROM_REGION(0x4000, "maincpu", 0)
|
||||||
|
ROM_FILL(0x0000, 0x4000, 0x00)
|
||||||
|
|
||||||
|
ROM_REGION(0x0400, "user1", 0)
|
||||||
|
ROM_SYSTEM_BIOS( 0, "none", "No BIOS" ) /* gamegear */
|
||||||
|
ROM_SYSTEM_BIOS( 1, "majesco", "Majesco BIOS" ) /* gamg */
|
||||||
|
ROMX_LOAD("majbios.rom", 0x0000, 0x0400, CRC(0EBEA9D4) SHA1(914aa165e3d879f060be77870d345b60cfeb4ede), ROM_BIOS(2))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
#define rom_gamegeaj rom_gamegear
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
Game driver(s)
|
||||||
|
|
||||||
|
US
|
||||||
|
- Sega Master System I (sms1)
|
||||||
|
- prototype bios - 1986
|
||||||
|
- without built-in game v1.3 - 1986
|
||||||
|
- built-in Hang On/Safari Hunt v2.4 - 1988
|
||||||
|
- built-in Hang On v3.4 - 1988
|
||||||
|
- built-in Missile Defense 3-D v4.4 - 1988
|
||||||
|
- built-in Hang On/Astro Warrior ????
|
||||||
|
- Sega Master System II (sms/sms2)
|
||||||
|
- built-in Alex Kidd in Miracle World - 1990
|
||||||
|
|
||||||
|
JP
|
||||||
|
- Sega SG-1000 Mark III (smsm3)
|
||||||
|
- no bios
|
||||||
|
- Sega Master System (I) (smsj)
|
||||||
|
- without built-in game v2.1 - 1987
|
||||||
|
|
||||||
|
KR
|
||||||
|
- Sega Master System II (sms2kr)
|
||||||
|
- built-in Alex Kidd in Miracle World (Korean)
|
||||||
|
|
||||||
|
EU
|
||||||
|
- Sega Master System I (sms1pal)
|
||||||
|
- without built-in game v1.3 - 1986
|
||||||
|
- built-in Hang On/Safari Hunt v2.4 - 1988
|
||||||
|
- built-in Hang On v3.4 - 1988
|
||||||
|
- built-in Missile Defense 3-D v4.4 - 1988
|
||||||
|
- built-in Hang On/Astro Warrior ????
|
||||||
|
- Sega Master System II (sms2pal)
|
||||||
|
- built-in Alex Kidd in Miracle World - 1990
|
||||||
|
- built-in Sonic the Hedgehog - 1991
|
||||||
|
|
||||||
|
BR
|
||||||
|
- Sega Master System I - 1987
|
||||||
|
- Sega Master System II???
|
||||||
|
- Sega Master System III - Tec Toy, 1987
|
||||||
|
- Sega Master System Compact - Tec Toy, 1992
|
||||||
|
- Sega Master System Girl - Tec Toy, 1992
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */
|
||||||
|
CONS( 1984, sg1000m3, sms, 0, sg1000m3, smsj, sg1000m3, "Sega", "SG-1000 Mark III", 0 )
|
||||||
|
CONS( 1986, sms1, sms, 0, sms1_ntsc, sms1, sms1, "Sega", "Master System I", 0 )
|
||||||
|
CONS( 1986, sms1pal, sms, 0, sms1_pal, sms1, sms1, "Sega", "Master System I (PAL)" , 0 )
|
||||||
|
CONS( 1986, smssdisp, sms, 0, sms_sdisp, sms, smssdisp, "Sega", "Master System Store Display Unit", GAME_NOT_WORKING )
|
||||||
|
CONS( 1987, smsj, sms, 0, sms_fm, smsj, smsj, "Sega", "Master System (Japan)", 0 )
|
||||||
|
CONS( 1990, sms, 0, 0, sms2_ntsc, sms, sms1, "Sega", "Master System II", 0 )
|
||||||
|
CONS( 1990, smspal, sms, 0, sms2_pal, sms, sms1, "Sega", "Master System II (PAL)", 0 )
|
||||||
|
CONS( 1990, sms2kr, sms, 0, sms2_fm, sms, sms2kr, "Samsung", "Gam*Boy II (Korea)", 0 )
|
||||||
|
|
||||||
|
CONS( 1990, gamegear, 0, sms, gamegear, gg, gamegear, "Sega", "Game Gear (Europe/America)", 0 )
|
||||||
|
CONS( 1990, gamegeaj, gamegear, 0, gamegear, gg, gamegeaj, "Sega", "Game Gear (Japan)", 0 )
|
1221
src/mame/drivers/sg1000.c
Normal file
1221
src/mame/drivers/sg1000.c
Normal file
File diff suppressed because it is too large
Load Diff
352
src/mame/formats/basicdsk.c
Normal file
352
src/mame/formats/basicdsk.c
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
|
||||||
|
formats/basicdsk.c
|
||||||
|
|
||||||
|
Floppy format code for basic disks
|
||||||
|
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "basicdsk.h"
|
||||||
|
|
||||||
|
static floperr_t basicdsk_read_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen);
|
||||||
|
static floperr_t basicdsk_write_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
|
||||||
|
static floperr_t basicdsk_read_indexed_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen);
|
||||||
|
static floperr_t basicdsk_write_indexed_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
|
||||||
|
static floperr_t basicdsk_get_sector_length(floppy_image *floppy, int head, int track, int sector, UINT32 *sector_length);
|
||||||
|
static floperr_t basicdsk_get_indexed_sector_info(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags);
|
||||||
|
static int basicdsk_get_heads_per_disk(floppy_image *floppy);
|
||||||
|
static int basicdsk_get_tracks_per_disk(floppy_image *floppy);
|
||||||
|
static floperr_t basicdsk_format_track(floppy_image *floppy, int head, int track, option_resolution *params);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define BASICDSK_TAG "basicdsktag"
|
||||||
|
|
||||||
|
struct basicdsk_tag
|
||||||
|
{
|
||||||
|
struct basicdsk_geometry geometry;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
static const struct basicdsk_geometry *get_geometry(floppy_image *floppy)
|
||||||
|
{
|
||||||
|
const struct basicdsk_tag *tag;
|
||||||
|
tag = (const basicdsk_tag *)floppy_tag(floppy);
|
||||||
|
return &tag->geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
floperr_t basicdsk_construct(floppy_image *floppy, const struct basicdsk_geometry *geometry)
|
||||||
|
{
|
||||||
|
struct basicdsk_tag *tag;
|
||||||
|
struct FloppyCallbacks *format;
|
||||||
|
|
||||||
|
assert(geometry->heads);
|
||||||
|
assert(geometry->tracks);
|
||||||
|
assert(geometry->sectors);
|
||||||
|
|
||||||
|
tag = (struct basicdsk_tag *) floppy_create_tag(floppy, sizeof(struct basicdsk_tag));
|
||||||
|
if (!tag)
|
||||||
|
return FLOPPY_ERROR_OUTOFMEMORY;
|
||||||
|
tag->geometry = *geometry;
|
||||||
|
|
||||||
|
/* set up format callbacks */
|
||||||
|
format = floppy_callbacks(floppy);
|
||||||
|
format->read_sector = basicdsk_read_sector;
|
||||||
|
format->write_sector = basicdsk_write_sector;
|
||||||
|
format->read_indexed_sector = basicdsk_read_indexed_sector;
|
||||||
|
format->write_indexed_sector = basicdsk_write_indexed_sector;
|
||||||
|
format->get_sector_length = basicdsk_get_sector_length;
|
||||||
|
format->get_heads_per_disk = basicdsk_get_heads_per_disk;
|
||||||
|
format->get_tracks_per_disk = basicdsk_get_tracks_per_disk;
|
||||||
|
format->get_indexed_sector_info = basicdsk_get_indexed_sector_info;
|
||||||
|
format->format_track = basicdsk_format_track;
|
||||||
|
|
||||||
|
return FLOPPY_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static floperr_t get_offset(floppy_image *floppy, int head, int track, int sector, int sector_is_index, UINT64 *offset)
|
||||||
|
{
|
||||||
|
const struct basicdsk_geometry *geom;
|
||||||
|
UINT64 offs;
|
||||||
|
|
||||||
|
geom = get_geometry(floppy);
|
||||||
|
|
||||||
|
/* translate the sector to a raw sector */
|
||||||
|
if (!sector_is_index)
|
||||||
|
{
|
||||||
|
sector -= geom->first_sector_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geom->translate_sector)
|
||||||
|
sector = geom->translate_sector(floppy, sector);
|
||||||
|
|
||||||
|
/* check to see if we are out of range */
|
||||||
|
if ((head < 0) || (head >= geom->heads) || (track < 0) || (track >= geom->tracks)
|
||||||
|
|| (sector < 0) || (sector >= geom->sectors))
|
||||||
|
return FLOPPY_ERROR_SEEKERROR;
|
||||||
|
|
||||||
|
if (geom->translate_offset)
|
||||||
|
offs = geom->translate_offset(floppy, geom, track, head, sector);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offs = 0;
|
||||||
|
offs += track;
|
||||||
|
offs *= geom->heads;
|
||||||
|
offs += head;
|
||||||
|
offs *= geom->sectors;
|
||||||
|
offs += sector;
|
||||||
|
}
|
||||||
|
offs *= geom->sector_length;
|
||||||
|
offs += geom->offset;
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
*offset = offs;
|
||||||
|
return FLOPPY_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int internal_basicdsk_translate_sector_interleave(floppy_image *floppy, int sector)
|
||||||
|
{
|
||||||
|
const struct basicdsk_geometry *geom = get_geometry(floppy);
|
||||||
|
if (sector >= geom->sectors)
|
||||||
|
return sector;
|
||||||
|
return geom->sector_map[sector];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static floperr_t internal_basicdsk_read_sector(floppy_image *floppy, int head, int track, int sector, int sector_is_index, void *buffer, size_t buflen)
|
||||||
|
{
|
||||||
|
UINT64 offset;
|
||||||
|
floperr_t err;
|
||||||
|
|
||||||
|
err = get_offset(floppy, head, track, sector, sector_is_index, &offset);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
floppy_image_read(floppy, buffer, offset, buflen);
|
||||||
|
return FLOPPY_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static floperr_t internal_basicdsk_write_sector(floppy_image *floppy, int head, int track, int sector, int sector_is_index, const void *buffer, size_t buflen, int ddam)
|
||||||
|
{
|
||||||
|
UINT64 offset;
|
||||||
|
floperr_t err;
|
||||||
|
|
||||||
|
err = get_offset(floppy, head, track, sector, sector_is_index, &offset);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
floppy_image_write(floppy, buffer, offset, buflen);
|
||||||
|
return FLOPPY_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static floperr_t basicdsk_read_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen)
|
||||||
|
{
|
||||||
|
return internal_basicdsk_read_sector(floppy, head, track, sector, FALSE, buffer, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static floperr_t basicdsk_write_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
|
||||||
|
{
|
||||||
|
return internal_basicdsk_write_sector(floppy, head, track, sector, FALSE, buffer, buflen, ddam);
|
||||||
|
}
|
||||||
|
|
||||||
|
static floperr_t basicdsk_read_indexed_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen)
|
||||||
|
{
|
||||||
|
return internal_basicdsk_read_sector(floppy, head, track, sector, TRUE, buffer, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static floperr_t basicdsk_write_indexed_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
|
||||||
|
{
|
||||||
|
return internal_basicdsk_write_sector(floppy, head, track, sector, TRUE, buffer, buflen, ddam);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static floperr_t basicdsk_format_track(floppy_image *floppy, int head, int track, option_resolution *params)
|
||||||
|
{
|
||||||
|
floperr_t err = FLOPPY_ERROR_SUCCESS;
|
||||||
|
UINT8 local_buffer[512];
|
||||||
|
void *alloc_buffer = NULL;
|
||||||
|
void *buffer;
|
||||||
|
UINT32 sector_length;
|
||||||
|
int sector;
|
||||||
|
const struct basicdsk_geometry *geometry;
|
||||||
|
|
||||||
|
geometry = get_geometry(floppy);
|
||||||
|
|
||||||
|
sector_length = geometry->sector_length;
|
||||||
|
|
||||||
|
if (sector_length > sizeof(local_buffer))
|
||||||
|
{
|
||||||
|
alloc_buffer = malloc(sector_length);
|
||||||
|
if (!alloc_buffer)
|
||||||
|
{
|
||||||
|
err = FLOPPY_ERROR_OUTOFMEMORY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
buffer = alloc_buffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alloc_buffer = NULL;
|
||||||
|
buffer = local_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buffer, floppy_get_filler(floppy), sector_length);
|
||||||
|
|
||||||
|
for (sector = 0; sector < geometry->sectors; sector++)
|
||||||
|
{
|
||||||
|
err = basicdsk_write_sector(floppy, head, track, sector + geometry->first_sector_id, buffer, sector_length, 0);
|
||||||
|
if (err)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (alloc_buffer)
|
||||||
|
free(alloc_buffer);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int basicdsk_get_heads_per_disk(floppy_image *floppy)
|
||||||
|
{
|
||||||
|
return get_geometry(floppy)->heads;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int basicdsk_get_tracks_per_disk(floppy_image *floppy)
|
||||||
|
{
|
||||||
|
return get_geometry(floppy)->tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static floperr_t basicdsk_get_sector_length(floppy_image *floppy, int head, int track, int sector, UINT32 *sector_length)
|
||||||
|
{
|
||||||
|
floperr_t err;
|
||||||
|
|
||||||
|
err = get_offset(floppy, head, track, sector, FALSE, NULL);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (sector_length)
|
||||||
|
*sector_length = get_geometry(floppy)->sector_length;
|
||||||
|
return FLOPPY_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static floperr_t basicdsk_get_indexed_sector_info(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
|
||||||
|
{
|
||||||
|
const struct basicdsk_geometry *geom = get_geometry(floppy);
|
||||||
|
|
||||||
|
if (geom->translate_sector)
|
||||||
|
sector_index = geom->translate_sector(floppy, sector_index);
|
||||||
|
|
||||||
|
sector_index += geom->first_sector_id;
|
||||||
|
|
||||||
|
if (cylinder)
|
||||||
|
*cylinder = track;
|
||||||
|
if (side)
|
||||||
|
*side = head;
|
||||||
|
if (sector)
|
||||||
|
*sector = sector_index;
|
||||||
|
if (flags) {
|
||||||
|
/* TODO: read DAM or DDAM and determine flags */
|
||||||
|
*flags = 0;
|
||||||
|
if (geom->get_ddam)
|
||||||
|
*flags = geom->get_ddam(floppy, geom, track, head, sector_index);
|
||||||
|
}
|
||||||
|
return basicdsk_get_sector_length(floppy, head, track, sector_index, sector_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Generic Basicdsk Constructors
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
static void basicdsk_default_geometry(const struct FloppyFormat *format, struct basicdsk_geometry *geometry)
|
||||||
|
{
|
||||||
|
optreserr_t err;
|
||||||
|
int sector_length;
|
||||||
|
memset(geometry, 0, sizeof(*geometry));
|
||||||
|
|
||||||
|
err = option_resolution_getdefault(format->param_guidelines, PARAM_HEADS, &geometry->heads);
|
||||||
|
assert(!err);
|
||||||
|
err = option_resolution_getdefault(format->param_guidelines, PARAM_TRACKS, &geometry->tracks);
|
||||||
|
assert(!err);
|
||||||
|
err = option_resolution_getdefault(format->param_guidelines, PARAM_SECTORS, &geometry->sectors);
|
||||||
|
assert(!err);
|
||||||
|
err = option_resolution_getdefault(format->param_guidelines, PARAM_FIRST_SECTOR_ID, &geometry->first_sector_id);
|
||||||
|
assert(!err);
|
||||||
|
err = option_resolution_getdefault(format->param_guidelines, PARAM_INTERLEAVE, &geometry->interleave);
|
||||||
|
if (err!=0) {
|
||||||
|
geometry->interleave = 1;
|
||||||
|
}
|
||||||
|
err = option_resolution_getdefault(format->param_guidelines, PARAM_SECTOR_LENGTH, §or_length);
|
||||||
|
assert(!err);
|
||||||
|
geometry->sector_length = sector_length;
|
||||||
|
|
||||||
|
if (geometry->interleave > 1)
|
||||||
|
{
|
||||||
|
int sector = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < geometry->sectors; i++)
|
||||||
|
{
|
||||||
|
geometry->sector_map[i] = sector;
|
||||||
|
|
||||||
|
sector += geometry->interleave;
|
||||||
|
|
||||||
|
if (sector >= geometry->sectors)
|
||||||
|
sector -= geometry->sectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry->translate_sector = internal_basicdsk_translate_sector_interleave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FLOPPY_CONSTRUCT(basicdsk_construct_default)
|
||||||
|
{
|
||||||
|
struct basicdsk_geometry geometry;
|
||||||
|
basicdsk_default_geometry(format, &geometry);
|
||||||
|
return basicdsk_construct(floppy, &geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FLOPPY_IDENTIFY(basicdsk_identify_default)
|
||||||
|
{
|
||||||
|
UINT64 expected_size;
|
||||||
|
struct basicdsk_geometry geometry;
|
||||||
|
|
||||||
|
basicdsk_default_geometry(format, &geometry);
|
||||||
|
|
||||||
|
expected_size = geometry.sector_length;
|
||||||
|
expected_size *= geometry.heads;
|
||||||
|
expected_size *= geometry.tracks;
|
||||||
|
expected_size *= geometry.sectors;
|
||||||
|
*vote = (floppy_image_size(floppy) == expected_size) ? 100 : 0;
|
||||||
|
return FLOPPY_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
35
src/mame/formats/basicdsk.h
Normal file
35
src/mame/formats/basicdsk.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
|
||||||
|
formats/basicdsk.h
|
||||||
|
|
||||||
|
Floppy format code for basic disks
|
||||||
|
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef BASICDSK_H
|
||||||
|
#define BASICDSK_H
|
||||||
|
|
||||||
|
#include "imagedev/flopimg.h"
|
||||||
|
|
||||||
|
struct basicdsk_geometry
|
||||||
|
{
|
||||||
|
int heads;
|
||||||
|
int tracks;
|
||||||
|
int sectors;
|
||||||
|
int first_sector_id;
|
||||||
|
int interleave;
|
||||||
|
int sector_map[256];
|
||||||
|
UINT32 sector_length;
|
||||||
|
UINT64 offset;
|
||||||
|
|
||||||
|
int (*translate_sector)(floppy_image *floppy, int sector);
|
||||||
|
UINT64 (*translate_offset)(floppy_image *floppy, const struct basicdsk_geometry *geom, int track, int head, int sector);
|
||||||
|
UINT64 (*get_ddam)(floppy_image *floppy, const struct basicdsk_geometry *geom, int track, int head, int sector);
|
||||||
|
};
|
||||||
|
|
||||||
|
floperr_t basicdsk_construct(floppy_image *floppy, const struct basicdsk_geometry *geometry);
|
||||||
|
|
||||||
|
FLOPPY_IDENTIFY(basicdsk_identify_default);
|
||||||
|
FLOPPY_CONSTRUCT(basicdsk_construct_default);
|
||||||
|
|
||||||
|
#endif /* BASICDSK_H */
|
183
src/mame/includes/segasms.h
Normal file
183
src/mame/includes/segasms.h
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* includes/sms.h
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SMS_H_
|
||||||
|
#define SMS_H_
|
||||||
|
|
||||||
|
#define LOG_REG
|
||||||
|
#define LOG_PAGING
|
||||||
|
#define LOG_COLOR
|
||||||
|
|
||||||
|
#define NVRAM_SIZE (0x08000)
|
||||||
|
#define CPU_ADDRESSABLE_SIZE (0x10000)
|
||||||
|
|
||||||
|
#define MAX_CARTRIDGES 16
|
||||||
|
|
||||||
|
class sms_state : public driver_device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
sms_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||||
|
: driver_device(mconfig, type, tag) { }
|
||||||
|
|
||||||
|
// device_ts
|
||||||
|
device_t *m_main_cpu;
|
||||||
|
device_t *m_control_cpu;
|
||||||
|
device_t *m_vdp;
|
||||||
|
device_t *m_ym;
|
||||||
|
device_t *m_main_scr;
|
||||||
|
device_t *m_left_lcd;
|
||||||
|
device_t *m_right_lcd;
|
||||||
|
|
||||||
|
UINT8 m_bios_page_count;
|
||||||
|
UINT8 m_fm_detect;
|
||||||
|
UINT8 m_ctrl_reg;
|
||||||
|
int m_paused;
|
||||||
|
UINT8 m_bios_port;
|
||||||
|
UINT8 *m_BIOS;
|
||||||
|
UINT8 *m_mapper_ram;
|
||||||
|
UINT8 m_mapper[4];
|
||||||
|
// we are going to use 1-6, same as bank numbers. Notice, though, that most mappers
|
||||||
|
// only work on 16K banks and, hence, banks 4-6 are not always directly set
|
||||||
|
// (they often use bank3 + 0x2000 and bank5 + 0x2000)
|
||||||
|
UINT8 *m_banking_bios[7];
|
||||||
|
UINT8 *m_banking_cart[7];
|
||||||
|
UINT8 *m_banking_none[7];
|
||||||
|
UINT8 m_gg_sio[5];
|
||||||
|
UINT8 m_store_control;
|
||||||
|
UINT8 m_input_port0;
|
||||||
|
UINT8 m_input_port1;
|
||||||
|
|
||||||
|
// for gamegear LCD persistence hack
|
||||||
|
bitmap_t *m_tmp_bitmap;
|
||||||
|
bitmap_t *m_prev_bitmap;
|
||||||
|
|
||||||
|
// for 3D glass binocular hack
|
||||||
|
bitmap_t *m_prevleft_bitmap;
|
||||||
|
bitmap_t *m_prevright_bitmap;
|
||||||
|
|
||||||
|
/* Model identifiers */
|
||||||
|
UINT8 m_is_gamegear;
|
||||||
|
UINT8 m_is_region_japan;
|
||||||
|
UINT8 m_has_bios_0400;
|
||||||
|
UINT8 m_has_bios_2000;
|
||||||
|
UINT8 m_has_bios_full;
|
||||||
|
UINT8 m_has_bios;
|
||||||
|
UINT8 m_has_fm;
|
||||||
|
|
||||||
|
/* Data needed for Rapid Fire Unit support */
|
||||||
|
emu_timer *m_rapid_fire_timer;
|
||||||
|
UINT8 m_rapid_fire_state_1;
|
||||||
|
UINT8 m_rapid_fire_state_2;
|
||||||
|
|
||||||
|
/* Data needed for Paddle Control controller */
|
||||||
|
UINT32 m_last_paddle_read_time;
|
||||||
|
UINT8 m_paddle_read_state;
|
||||||
|
|
||||||
|
/* Data needed for Sports Pad controller */
|
||||||
|
UINT32 m_last_sports_pad_time_1;
|
||||||
|
UINT32 m_last_sports_pad_time_2;
|
||||||
|
UINT8 m_sports_pad_state_1;
|
||||||
|
UINT8 m_sports_pad_state_2;
|
||||||
|
UINT8 m_sports_pad_last_data_1;
|
||||||
|
UINT8 m_sports_pad_last_data_2;
|
||||||
|
UINT8 m_sports_pad_1_x;
|
||||||
|
UINT8 m_sports_pad_1_y;
|
||||||
|
UINT8 m_sports_pad_2_x;
|
||||||
|
UINT8 m_sports_pad_2_y;
|
||||||
|
|
||||||
|
/* Data needed for Light Phaser */
|
||||||
|
emu_timer *m_lphaser_1_timer;
|
||||||
|
emu_timer *m_lphaser_2_timer;
|
||||||
|
UINT8 m_lphaser_1_latch;
|
||||||
|
UINT8 m_lphaser_2_latch;
|
||||||
|
int m_lphaser_x_offs; /* Needed to 'calibrate' lphaser; set at cart loading */
|
||||||
|
|
||||||
|
/* Data needed for SegaScope (3D glasses) */
|
||||||
|
UINT8 m_sscope_state;
|
||||||
|
|
||||||
|
/* Data needed for Terebi Oekaki (TV Draw) */
|
||||||
|
UINT8 m_tvdraw_data;
|
||||||
|
|
||||||
|
/* Cartridge slot info */
|
||||||
|
UINT8 m_current_cartridge;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
UINT8 *ROM; /* Pointer to ROM image data */
|
||||||
|
UINT32 size; /* Size of the ROM image */
|
||||||
|
UINT8 features; /* on-cartridge special hardware */
|
||||||
|
UINT8 *cartSRAM; /* on-cartridge SRAM */
|
||||||
|
UINT8 sram_save; /* should be the contents of the on-cartridge SRAM be saved */
|
||||||
|
UINT8 *cartRAM; /* additional on-cartridge RAM (64KB for Ernie Els Golf) */
|
||||||
|
UINT32 ram_size; /* size of the on-cartridge RAM */
|
||||||
|
UINT8 ram_page; /* currently swapped in cartridge RAM */
|
||||||
|
} m_cartridge[MAX_CARTRIDGES];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*----------- defined in machine/sms.c -----------*/
|
||||||
|
|
||||||
|
/* Function prototypes */
|
||||||
|
WRITE8_HANDLER( sms_cartram_w );
|
||||||
|
WRITE8_HANDLER( sms_cartram2_w );
|
||||||
|
WRITE8_HANDLER( sms_fm_detect_w );
|
||||||
|
READ8_HANDLER( sms_fm_detect_r );
|
||||||
|
READ8_HANDLER( sms_input_port_0_r );
|
||||||
|
READ8_HANDLER( sms_input_port_1_r );
|
||||||
|
WRITE8_HANDLER( sms_ym2413_register_port_0_w );
|
||||||
|
WRITE8_HANDLER( sms_ym2413_data_port_0_w );
|
||||||
|
WRITE8_HANDLER( sms_io_control_w );
|
||||||
|
READ8_HANDLER( sms_count_r );
|
||||||
|
WRITE8_HANDLER( sms_sscope_w );
|
||||||
|
READ8_HANDLER( sms_sscope_r );
|
||||||
|
WRITE8_HANDLER( sms_mapper_w );
|
||||||
|
READ8_HANDLER( sms_mapper_r );
|
||||||
|
WRITE8_HANDLER( sms_bios_w );
|
||||||
|
WRITE8_HANDLER( gg_sio_w );
|
||||||
|
READ8_HANDLER( gg_sio_r );
|
||||||
|
READ8_HANDLER( gg_input_port_2_r );
|
||||||
|
|
||||||
|
INPUT_CHANGED( lgun1_changed );
|
||||||
|
INPUT_CHANGED( lgun2_changed );
|
||||||
|
|
||||||
|
void sms_pause_callback( running_machine &machine );
|
||||||
|
void sms_store_int_callback( running_machine &machine, int state );
|
||||||
|
|
||||||
|
DEVICE_START( sms_cart );
|
||||||
|
DEVICE_IMAGE_LOAD( sms_cart );
|
||||||
|
|
||||||
|
MACHINE_START( sms );
|
||||||
|
MACHINE_RESET( sms );
|
||||||
|
|
||||||
|
READ8_HANDLER( sms_store_cart_select_r );
|
||||||
|
WRITE8_HANDLER( sms_store_cart_select_w );
|
||||||
|
READ8_HANDLER( sms_store_select1 );
|
||||||
|
READ8_HANDLER( sms_store_select2 );
|
||||||
|
READ8_HANDLER( sms_store_control_r );
|
||||||
|
WRITE8_HANDLER( sms_store_control_w );
|
||||||
|
|
||||||
|
#define IO_EXPANSION (0x80) /* Expansion slot enable (1= disabled, 0= enabled) */
|
||||||
|
#define IO_CARTRIDGE (0x40) /* Cartridge slot enable (1= disabled, 0= enabled) */
|
||||||
|
#define IO_CARD (0x20) /* Card slot disabled (1= disabled, 0= enabled) */
|
||||||
|
#define IO_WORK_RAM (0x10) /* Work RAM disabled (1= disabled, 0= enabled) */
|
||||||
|
#define IO_BIOS_ROM (0x08) /* BIOS ROM disabled (1= disabled, 0= enabled) */
|
||||||
|
#define IO_CHIP (0x04) /* I/O chip disabled (1= disabled, 0= enabled) */
|
||||||
|
|
||||||
|
|
||||||
|
DRIVER_INIT( sg1000m3 );
|
||||||
|
DRIVER_INIT( sms1 );
|
||||||
|
DRIVER_INIT( smsj );
|
||||||
|
DRIVER_INIT( sms2kr );
|
||||||
|
DRIVER_INIT( smssdisp );
|
||||||
|
DRIVER_INIT( gamegear );
|
||||||
|
DRIVER_INIT( gamegeaj );
|
||||||
|
|
||||||
|
VIDEO_START( sms1 );
|
||||||
|
VIDEO_START( gamegear );
|
||||||
|
SCREEN_UPDATE( sms1 );
|
||||||
|
SCREEN_UPDATE( sms );
|
||||||
|
SCREEN_UPDATE( gamegear );
|
||||||
|
|
||||||
|
#endif /* SMS_H_ */
|
102
src/mame/includes/sg1000.h
Normal file
102
src/mame/includes/sg1000.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#ifndef __SG1000__
|
||||||
|
#define __SG1000__
|
||||||
|
|
||||||
|
#include "machine/ram.h"
|
||||||
|
|
||||||
|
#define SCREEN_TAG "screen"
|
||||||
|
#define Z80_TAG "z80"
|
||||||
|
#define SN76489A_TAG "sn76489a"
|
||||||
|
#define UPD765_TAG "upd765"
|
||||||
|
#define CASSETTE_TAG "cassette"
|
||||||
|
#define UPD8251_TAG "upd8251"
|
||||||
|
#define UPD9255_TAG "upd9255"
|
||||||
|
#define UPD9255_0_TAG "upd9255_0"
|
||||||
|
#define UPD9255_1_TAG "upd9255_1"
|
||||||
|
#define CENTRONICS_TAG "centronics"
|
||||||
|
|
||||||
|
#define IS_CARTRIDGE_TV_DRAW(ptr) \
|
||||||
|
(!strncmp("annakmn", (const char *)&ptr[0x13b3], 7))
|
||||||
|
|
||||||
|
#define IS_CARTRIDGE_THE_CASTLE(ptr) \
|
||||||
|
(!strncmp("ASCII 1986", (const char *)&ptr[0x1cc3], 10))
|
||||||
|
|
||||||
|
#define IS_CARTRIDGE_BASIC_LEVEL_III(ptr) \
|
||||||
|
(!strncmp("SC-3000 BASIC Level 3 ver 1.0", (const char *)&ptr[0x6a20], 29))
|
||||||
|
|
||||||
|
#define IS_CARTRIDGE_MUSIC_EDITOR(ptr) \
|
||||||
|
(!strncmp("PIANO", (const char *)&ptr[0x0841], 5))
|
||||||
|
|
||||||
|
class sg1000_state : public driver_device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
sg1000_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||||
|
: driver_device(mconfig, type, tag),
|
||||||
|
m_maincpu(*this, Z80_TAG),
|
||||||
|
m_ram(*this, RAM_TAG)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
required_device<cpu_device> m_maincpu;
|
||||||
|
required_device<device_t> m_ram;
|
||||||
|
|
||||||
|
virtual void machine_start();
|
||||||
|
|
||||||
|
void install_cartridge(UINT8 *ptr, int size);
|
||||||
|
|
||||||
|
DECLARE_WRITE8_MEMBER( tvdraw_axis_w );
|
||||||
|
DECLARE_READ8_MEMBER( tvdraw_status_r );
|
||||||
|
DECLARE_READ8_MEMBER( tvdraw_data_r );
|
||||||
|
DECLARE_READ8_MEMBER( joysel_r );
|
||||||
|
|
||||||
|
/* keyboard state */
|
||||||
|
UINT8 m_keylatch;
|
||||||
|
|
||||||
|
/* TV Draw state */
|
||||||
|
UINT8 m_tvdraw_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
class sc3000_state : public sg1000_state
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
sc3000_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||||
|
: sg1000_state(mconfig, type, tag),
|
||||||
|
m_cassette(*this, CASSETTE_TAG)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
required_device<device_t> m_cassette;
|
||||||
|
|
||||||
|
virtual void machine_start();
|
||||||
|
|
||||||
|
void install_cartridge(UINT8 *ptr, int size);
|
||||||
|
|
||||||
|
DECLARE_READ8_MEMBER( ppi_pa_r );
|
||||||
|
DECLARE_READ8_MEMBER( ppi_pb_r );
|
||||||
|
DECLARE_WRITE8_MEMBER( ppi_pc_w );
|
||||||
|
};
|
||||||
|
|
||||||
|
class sf7000_state : public sc3000_state
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
sf7000_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||||
|
: sc3000_state(mconfig, type, tag),
|
||||||
|
m_fdc(*this, UPD765_TAG),
|
||||||
|
m_centronics(*this, CENTRONICS_TAG),
|
||||||
|
m_floppy0(*this, FLOPPY_0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
required_device<device_t> m_fdc;
|
||||||
|
required_device<device_t> m_centronics;
|
||||||
|
required_device<device_t> m_floppy0;
|
||||||
|
|
||||||
|
virtual void machine_start();
|
||||||
|
virtual void machine_reset();
|
||||||
|
|
||||||
|
DECLARE_READ8_MEMBER( ppi_pa_r );
|
||||||
|
DECLARE_WRITE8_MEMBER( ppi_pc_w );
|
||||||
|
DECLARE_WRITE_LINE_MEMBER( fdc_intrq_w );
|
||||||
|
|
||||||
|
/* floppy state */
|
||||||
|
int m_fdc_irq;
|
||||||
|
int m_fdc_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
62
src/mame/layout/sms1.lay
Normal file
62
src/mame/layout/sms1.lay
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<mamelayout version="2">
|
||||||
|
<view name="Main Screen Standard (4:3)">
|
||||||
|
<screen index="0">
|
||||||
|
<bounds left="0" top="0" right="4" bottom="3" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view name="SegaScope Left LCD Standard (4:3)">
|
||||||
|
<screen index="1">
|
||||||
|
<bounds left="0" top="0" right="4" bottom="3" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view name="SegaScope Right LCD Standard (4:3)">
|
||||||
|
<screen index="2">
|
||||||
|
<bounds left="0" top="0" right="4" bottom="3" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view name="Main Screen Pixel Aspect (~scr0nativexaspect~:~scr0nativeyaspect~)">
|
||||||
|
<screen index="0">
|
||||||
|
<bounds left="0" top="0" right="~scr0width~" bottom="~scr0height~" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view name="SegaScope Left LCD Aspect (~scr1nativexaspect~:~scr1nativeyaspect~)">
|
||||||
|
<screen index="1">
|
||||||
|
<bounds left="0" top="0" right="~scr1width~" bottom="~scr1height~" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view name="SegaScope Right LCD Pixel Aspect (~scr1nativexaspect~:~scr1nativeyaspect~)">
|
||||||
|
<screen index="2">
|
||||||
|
<bounds left="0" top="0" right="~scr1width~" bottom="~scr1height~" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view name="Main Screen">
|
||||||
|
<screen index="0">
|
||||||
|
<bounds x="0" y="0" width="4" height="3" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view name="SegaScope 3-D Glasses">
|
||||||
|
<screen index="1">
|
||||||
|
<bounds x="0" y="0" width="4" height="3" />
|
||||||
|
</screen>
|
||||||
|
<screen index="2">
|
||||||
|
<bounds x="4.03" y="0" width="4" height="3" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view name="SegaScope 3-D Glasses (Gapless)">
|
||||||
|
<screen index="1">
|
||||||
|
<bounds x="0" y="0" width="4" height="3" />
|
||||||
|
</screen>
|
||||||
|
<screen index="2">
|
||||||
|
<bounds x="4" y="0" width="4" height="3" />
|
||||||
|
</screen>
|
||||||
|
</view>
|
||||||
|
</mamelayout>
|
391
src/mame/machine/ctronics.c
Normal file
391
src/mame/machine/ctronics.c
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
Centronics printer interface
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
#include "ctronics.h"
|
||||||
|
#include "imagedev/printer.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
FUNCTION PROTOTYPES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
static WRITE_LINE_DEVICE_HANDLER( centronics_printer_online );
|
||||||
|
static TIMER_CALLBACK( ack_callback );
|
||||||
|
static TIMER_CALLBACK( busy_callback );
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
typedef struct _centronics_state centronics_state;
|
||||||
|
struct _centronics_state
|
||||||
|
{
|
||||||
|
device_t *printer;
|
||||||
|
|
||||||
|
devcb_resolved_write_line out_ack_func;
|
||||||
|
devcb_resolved_write_line out_busy_func;
|
||||||
|
devcb_resolved_write_line out_not_busy_func;
|
||||||
|
|
||||||
|
int strobe;
|
||||||
|
int busy;
|
||||||
|
int ack;
|
||||||
|
int auto_fd;
|
||||||
|
int pe;
|
||||||
|
int fault;
|
||||||
|
|
||||||
|
UINT8 data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
INLINE FUNCTIONS
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
INLINE centronics_state *get_safe_token(device_t *device)
|
||||||
|
{
|
||||||
|
assert(device != NULL);
|
||||||
|
assert(device->type() == CENTRONICS);
|
||||||
|
|
||||||
|
return (centronics_state *)downcast<legacy_device_base *>(device)->token();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
GLOBAL VARIABLES
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
const centronics_interface standard_centronics =
|
||||||
|
{
|
||||||
|
FALSE,
|
||||||
|
DEVCB_NULL,
|
||||||
|
DEVCB_NULL,
|
||||||
|
DEVCB_NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
PRINTER INTERFACE
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_FRAGMENT( centronics )
|
||||||
|
MCFG_PRINTER_ADD("printer")
|
||||||
|
MCFG_PRINTER_ONLINE(centronics_printer_online)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
DEVICE INTERFACE
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
static DEVICE_START( centronics )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
const centronics_interface *intf = (const centronics_interface *)device->static_config();
|
||||||
|
|
||||||
|
/* validate some basic stuff */
|
||||||
|
assert(device->static_config() != NULL);
|
||||||
|
|
||||||
|
/* set some initial values */
|
||||||
|
centronics->pe = FALSE;
|
||||||
|
centronics->fault = FALSE;
|
||||||
|
centronics->busy = TRUE;
|
||||||
|
centronics->strobe = TRUE;
|
||||||
|
|
||||||
|
/* get printer device */
|
||||||
|
centronics->printer = device->subdevice("printer");
|
||||||
|
|
||||||
|
/* resolve callbacks */
|
||||||
|
centronics->out_ack_func.resolve(intf->out_ack_func, *device);
|
||||||
|
centronics->out_busy_func.resolve(intf->out_busy_func, *device);
|
||||||
|
centronics->out_not_busy_func.resolve(intf->out_not_busy_func, *device);
|
||||||
|
|
||||||
|
/* register for state saving */
|
||||||
|
device->save_item(NAME(centronics->auto_fd));
|
||||||
|
device->save_item(NAME(centronics->strobe));
|
||||||
|
device->save_item(NAME(centronics->busy));
|
||||||
|
device->save_item(NAME(centronics->ack));
|
||||||
|
device->save_item(NAME(centronics->data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_RESET( centronics )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE_GET_INFO( centronics )
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||||
|
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(centronics_state); break;
|
||||||
|
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
|
||||||
|
|
||||||
|
/* --- the following bits of info are returned as pointers --- */
|
||||||
|
case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(centronics); break;
|
||||||
|
|
||||||
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||||
|
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(centronics); break;
|
||||||
|
case DEVINFO_FCT_STOP: /* Nothing */ break;
|
||||||
|
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(centronics); break;
|
||||||
|
|
||||||
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||||
|
case DEVINFO_STR_NAME: strcpy(info->s, "Centronics"); break;
|
||||||
|
case DEVINFO_STR_FAMILY: strcpy(info->s, "Centronics"); break;
|
||||||
|
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
|
||||||
|
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||||
|
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
IMPLEMENTATION
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_printer_online - callback that
|
||||||
|
sets us busy when the printer goes offline
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void centronics_printer_online(device_t *device, int state)
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device->owner());
|
||||||
|
|
||||||
|
/* when going online, set PE and FAULT high and BUSY low */
|
||||||
|
centronics->pe = state;
|
||||||
|
centronics->fault = state;
|
||||||
|
centronics->busy = !state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static TIMER_CALLBACK( ack_callback )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = (centronics_state *)ptr;
|
||||||
|
|
||||||
|
/* signal change */
|
||||||
|
centronics->out_ack_func(param);
|
||||||
|
centronics->ack = param;
|
||||||
|
|
||||||
|
if (param == FALSE)
|
||||||
|
{
|
||||||
|
/* data is now ready, output it */
|
||||||
|
printer_output(centronics->printer, centronics->data);
|
||||||
|
|
||||||
|
/* ready to receive more data, return BUSY to low */
|
||||||
|
machine.scheduler().timer_set(attotime::from_usec(7), FUNC(busy_callback), FALSE, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static TIMER_CALLBACK( busy_callback )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = (centronics_state *)ptr;
|
||||||
|
|
||||||
|
/* signal change */
|
||||||
|
centronics->out_busy_func(param);
|
||||||
|
centronics->out_not_busy_func(!param);
|
||||||
|
centronics->busy = param;
|
||||||
|
|
||||||
|
if (param == TRUE)
|
||||||
|
{
|
||||||
|
/* timer to turn ACK low to receive data */
|
||||||
|
machine.scheduler().timer_set(attotime::from_usec(10), FUNC(ack_callback), FALSE, ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* timer to return ACK to high state */
|
||||||
|
machine.scheduler().timer_set(attotime::from_usec(5), FUNC(ack_callback), TRUE, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_data_w - write print data
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
WRITE8_DEVICE_HANDLER( centronics_data_w )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
centronics->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_data_r - return current data
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ8_DEVICE_HANDLER( centronics_data_r )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
return centronics->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
set_line - helper to set individual bits
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void set_line(device_t *device, int line, int state)
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
centronics->data |= 1 << line;
|
||||||
|
else
|
||||||
|
centronics->data &= ~(1 << line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_dx_w - write line dx print data
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d0_w ) { set_line(device, 0, state); }
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d1_w ) { set_line(device, 1, state); }
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d2_w ) { set_line(device, 2, state); }
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d3_w ) { set_line(device, 3, state); }
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d4_w ) { set_line(device, 4, state); }
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d5_w ) { set_line(device, 5, state); }
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d6_w ) { set_line(device, 6, state); }
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d7_w ) { set_line(device, 7, state); }
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_strobe_w - signal that data is
|
||||||
|
ready
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_strobe_w )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
|
||||||
|
/* look for a high -> low transition */
|
||||||
|
if (centronics->strobe == TRUE && state == FALSE && centronics->busy == FALSE)
|
||||||
|
{
|
||||||
|
/* STROBE has gone low, data is ready */
|
||||||
|
device->machine().scheduler().timer_set(attotime::zero, FUNC(busy_callback), TRUE, centronics);
|
||||||
|
}
|
||||||
|
|
||||||
|
centronics->strobe = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_prime_w - initialize and reset
|
||||||
|
printer (centronics mode)
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_prime_w )
|
||||||
|
{
|
||||||
|
assert(((const centronics_interface *)device->static_config())->is_ibmpc == FALSE);
|
||||||
|
|
||||||
|
/* reset printer if line is low */
|
||||||
|
if (state == FALSE)
|
||||||
|
DEVICE_RESET_CALL( centronics );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_init_w - initialize and reset
|
||||||
|
printer (ibm mode)
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_init_w )
|
||||||
|
{
|
||||||
|
assert(((const centronics_interface *)device->static_config())->is_ibmpc == TRUE);
|
||||||
|
|
||||||
|
/* reset printer if line is low */
|
||||||
|
if (state == FALSE)
|
||||||
|
DEVICE_RESET_CALL( centronics );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_autofeed_w - auto line feed
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_autofeed_w )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
assert(((const centronics_interface *)device->static_config())->is_ibmpc == TRUE);
|
||||||
|
|
||||||
|
centronics->auto_fd = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_ack_r - return the state of the
|
||||||
|
ack line
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_ack_r )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
return centronics->ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_busy_r - return the state of the
|
||||||
|
busy line
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_busy_r )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
return centronics->busy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_pe_r - return the state of the
|
||||||
|
pe line
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_pe_r )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
return centronics->pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_not_busy_r - return the state of the
|
||||||
|
not busy line
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_not_busy_r )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
return !centronics->busy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_vcc_r - return the state of the
|
||||||
|
vcc line
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_vcc_r )
|
||||||
|
{
|
||||||
|
/* always return high */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
centronics_fault_r - return the state of the
|
||||||
|
fault line
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_fault_r )
|
||||||
|
{
|
||||||
|
centronics_state *centronics = get_safe_token(device);
|
||||||
|
return centronics->fault;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_LEGACY_DEVICE(CENTRONICS, centronics);
|
75
src/mame/machine/ctronics.h
Normal file
75
src/mame/machine/ctronics.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
Centronics printer interface
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __CTRONICS_H__
|
||||||
|
#define __CTRONICS_H__
|
||||||
|
|
||||||
|
#include "devcb.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
typedef struct _centronics_interface centronics_interface;
|
||||||
|
struct _centronics_interface
|
||||||
|
{
|
||||||
|
int is_ibmpc;
|
||||||
|
|
||||||
|
devcb_write_line out_ack_func;
|
||||||
|
devcb_write_line out_busy_func;
|
||||||
|
devcb_write_line out_not_busy_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
FUNCTION PROTOTYPES
|
||||||
|
***************************************************************************/
|
||||||
|
WRITE8_DEVICE_HANDLER( centronics_data_w );
|
||||||
|
READ8_DEVICE_HANDLER( centronics_data_r );
|
||||||
|
|
||||||
|
/* access to the individual bits */
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d0_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d1_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d2_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d3_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d4_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d5_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d6_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_d7_w );
|
||||||
|
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_strobe_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_prime_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_init_w );
|
||||||
|
WRITE_LINE_DEVICE_HANDLER( centronics_autofeed_w );
|
||||||
|
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_ack_r );
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_busy_r );
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_pe_r );
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_not_busy_r );
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_vcc_r );
|
||||||
|
READ_LINE_DEVICE_HANDLER( centronics_fault_r );
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
DEVICE CONFIGURATION MACROS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
DECLARE_LEGACY_DEVICE(CENTRONICS, centronics);
|
||||||
|
|
||||||
|
#define MCFG_CENTRONICS_ADD(_tag, _intf) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, CENTRONICS, 0) \
|
||||||
|
MCFG_DEVICE_CONFIG(_intf)
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
DEFAULT INTERFACES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
extern const centronics_interface standard_centronics;
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __CTRONICS_H__ */
|
725
src/mame/machine/dccons.c
Normal file
725
src/mame/machine/dccons.c
Normal file
@ -0,0 +1,725 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
dc.c - Sega Dreamcast hardware
|
||||||
|
|
||||||
|
MESS (DC home console) hardware overrides (GD-ROM drive etc)
|
||||||
|
|
||||||
|
c230048 - 5 is written, want 6
|
||||||
|
c0d9d9e - where bad happens, from routine @ c0da260
|
||||||
|
|
||||||
|
c0d9d8e - R0 on return is the value to put in
|
||||||
|
|
||||||
|
cfffee0 - stack location when bad happens
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
#include "cdrom.h"
|
||||||
|
#include "debugger.h"
|
||||||
|
#include "includes/dc.h"
|
||||||
|
#include "cpu/sh4/sh4.h"
|
||||||
|
#include "sound/aica.h"
|
||||||
|
#include "includes/naomi.h"
|
||||||
|
#include "machine/gdrom.h"
|
||||||
|
#include "imagedev/chd_cd.h"
|
||||||
|
|
||||||
|
#define ATAPI_CYCLES_PER_SECTOR (5000) // TBD for Dreamcast
|
||||||
|
|
||||||
|
#define ATAPI_STAT_BSY 0x80
|
||||||
|
#define ATAPI_STAT_DRDY 0x40
|
||||||
|
#define ATAPI_STAT_DMARDDF 0x20
|
||||||
|
#define ATAPI_STAT_SERVDSC 0x10
|
||||||
|
#define ATAPI_STAT_DRQ 0x08
|
||||||
|
#define ATAPI_STAT_CORR 0x04
|
||||||
|
#define ATAPI_STAT_CHECK 0x01
|
||||||
|
|
||||||
|
#define ATAPI_INTREASON_COMMAND 0x01
|
||||||
|
#define ATAPI_INTREASON_IO 0x02
|
||||||
|
#define ATAPI_INTREASON_RELEASE 0x04
|
||||||
|
|
||||||
|
#define ATAPI_REG_DATA 0
|
||||||
|
#define ATAPI_REG_FEATURES 1
|
||||||
|
#define ATAPI_REG_INTREASON 2
|
||||||
|
#define ATAPI_REG_SAMTAG 3
|
||||||
|
#define ATAPI_REG_COUNTLOW 4
|
||||||
|
#define ATAPI_REG_COUNTHIGH 5
|
||||||
|
#define ATAPI_REG_DRIVESEL 6
|
||||||
|
#define ATAPI_REG_CMDSTATUS 7
|
||||||
|
#define ATAPI_REG_ERROR 16 // read-only ERROR (write is FEATURES)
|
||||||
|
|
||||||
|
#define ATAPI_REG_MAX 24
|
||||||
|
|
||||||
|
#define ATAPI_XFER_PIO 0x00
|
||||||
|
#define ATAPI_XFER_PIO_FLOW 0x08
|
||||||
|
#define ATAPI_XFER_MULTI_DMA 0x20
|
||||||
|
#define ATAPI_XFER_ULTRA_DMA 0x40
|
||||||
|
|
||||||
|
#define ATAPI_DATA_SIZE ( 64 * 1024 )
|
||||||
|
|
||||||
|
static UINT8 *atapi_regs;
|
||||||
|
static emu_timer *atapi_timer;
|
||||||
|
static SCSIInstance *gdrom_device;
|
||||||
|
static UINT8 *atapi_data;
|
||||||
|
static int atapi_data_ptr, atapi_data_len, atapi_xferlen, atapi_xferbase, atapi_cdata_wait, atapi_xfermod;
|
||||||
|
static UINT32 gdrom_alt_status;
|
||||||
|
static UINT8 xfer_mode = ATAPI_XFER_PIO;
|
||||||
|
|
||||||
|
#define MAX_TRANSFER_SIZE ( 63488 )
|
||||||
|
|
||||||
|
extern UINT32 dc_sysctrl_regs[0x200/4];
|
||||||
|
|
||||||
|
extern UINT32 g1bus_regs[0x100/4];
|
||||||
|
|
||||||
|
static void gdrom_raise_irq(running_machine &machine)
|
||||||
|
{
|
||||||
|
dc_sysctrl_regs[SB_ISTEXT] |= IST_EXT_GDROM;
|
||||||
|
dc_update_interrupt_status(machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TIMER_CALLBACK( atapi_xfer_end )
|
||||||
|
{
|
||||||
|
UINT8 sector_buffer[ 4096 ];
|
||||||
|
|
||||||
|
atapi_timer->adjust(attotime::never);
|
||||||
|
|
||||||
|
printf("atapi_xfer_end atapi_xferlen = %d, atapi_xfermod=%d\n", atapi_xfermod, atapi_xferlen );
|
||||||
|
|
||||||
|
mame_printf_debug("ATAPI: xfer_end. xferlen = %d, atapi_xfermod = %d\n", atapi_xferlen, atapi_xfermod);
|
||||||
|
|
||||||
|
while (atapi_xferlen > 0 )
|
||||||
|
{
|
||||||
|
struct sh4_ddt_dma ddtdata;
|
||||||
|
|
||||||
|
// get a sector from the SCSI device
|
||||||
|
SCSIReadData( gdrom_device, sector_buffer, 2048 );
|
||||||
|
|
||||||
|
atapi_xferlen -= 2048;
|
||||||
|
|
||||||
|
// perform the DMA
|
||||||
|
ddtdata.destination = atapi_xferbase; // destination address
|
||||||
|
ddtdata.length = 2048/4;
|
||||||
|
ddtdata.size = 4;
|
||||||
|
ddtdata.buffer = sector_buffer;
|
||||||
|
ddtdata.direction=1; // 0 source to buffer, 1 buffer to destination
|
||||||
|
ddtdata.channel= -1; // not used
|
||||||
|
ddtdata.mode= -1; // copy from/to buffer
|
||||||
|
printf("ATAPI: DMA one sector to %x, %x remaining\n", atapi_xferbase, atapi_xferlen);
|
||||||
|
sh4_dma_ddt(machine.device("maincpu"), &ddtdata);
|
||||||
|
|
||||||
|
atapi_xferbase += 2048;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atapi_xfermod > MAX_TRANSFER_SIZE)
|
||||||
|
{
|
||||||
|
atapi_xferlen = MAX_TRANSFER_SIZE;
|
||||||
|
atapi_xfermod = atapi_xfermod - MAX_TRANSFER_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
atapi_xferlen = atapi_xfermod;
|
||||||
|
atapi_xfermod = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atapi_xferlen > 0)
|
||||||
|
{
|
||||||
|
printf("ATAPI: starting next piece of multi-part transfer\n");
|
||||||
|
atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff;
|
||||||
|
|
||||||
|
atapi_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime((ATAPI_CYCLES_PER_SECTOR * (atapi_xferlen/2048))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ATAPI: Transfer completed, dropping DRQ\n");
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY;
|
||||||
|
gdrom_alt_status = ATAPI_STAT_DRDY;
|
||||||
|
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO | ATAPI_INTREASON_COMMAND;
|
||||||
|
|
||||||
|
g1bus_regs[SB_GDST]=0;
|
||||||
|
dc_sysctrl_regs[SB_ISTNRM] |= IST_DMA_GDROM;
|
||||||
|
dc_update_interrupt_status(machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
gdrom_raise_irq(machine);
|
||||||
|
|
||||||
|
printf( "atapi_xfer_end: %d %d\n", atapi_xferlen, atapi_xfermod );
|
||||||
|
}
|
||||||
|
|
||||||
|
static READ32_HANDLER( atapi_r )
|
||||||
|
{
|
||||||
|
running_machine &machine = space->machine();
|
||||||
|
int reg, data;
|
||||||
|
|
||||||
|
if (mem_mask == 0x0000ffff) // word-wide command read
|
||||||
|
{
|
||||||
|
// mame_printf_debug("ATAPI: packet read = %04x\n", atapi_data[atapi_data_ptr]);
|
||||||
|
|
||||||
|
// assert IRQ and drop DRQ
|
||||||
|
if (atapi_data_ptr == 0 && atapi_data_len == 0)
|
||||||
|
{
|
||||||
|
// get the data from the device
|
||||||
|
if( atapi_xferlen > 0 )
|
||||||
|
{
|
||||||
|
SCSIReadData( gdrom_device, atapi_data, atapi_xferlen );
|
||||||
|
atapi_data_len = atapi_xferlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atapi_xfermod > MAX_TRANSFER_SIZE)
|
||||||
|
{
|
||||||
|
atapi_xferlen = MAX_TRANSFER_SIZE;
|
||||||
|
atapi_xfermod = atapi_xfermod - MAX_TRANSFER_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
atapi_xferlen = atapi_xfermod;
|
||||||
|
atapi_xfermod = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf( "atapi_r: atapi_xferlen=%d\n", atapi_xferlen );
|
||||||
|
if( atapi_xferlen != 0 )
|
||||||
|
{
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC;
|
||||||
|
gdrom_alt_status = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC;
|
||||||
|
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//mame_printf_debug("ATAPI: dropping DRQ\n");
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
|
||||||
|
gdrom_alt_status = 0;
|
||||||
|
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff;
|
||||||
|
|
||||||
|
gdrom_raise_irq(machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( atapi_data_ptr < atapi_data_len )
|
||||||
|
{
|
||||||
|
data = atapi_data[atapi_data_ptr++];
|
||||||
|
data |= ( atapi_data[atapi_data_ptr++] << 8 );
|
||||||
|
if( atapi_data_ptr >= atapi_data_len )
|
||||||
|
{
|
||||||
|
// printf( "atapi_r: read all bytes\n" );
|
||||||
|
atapi_data_ptr = 0;
|
||||||
|
atapi_data_len = 0;
|
||||||
|
|
||||||
|
if( atapi_xferlen == 0 )
|
||||||
|
{
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
|
||||||
|
gdrom_alt_status = 0;
|
||||||
|
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
|
||||||
|
gdrom_raise_irq(machine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reg = offset;
|
||||||
|
|
||||||
|
// get read-only side of read-only/write-only registers from elsewhere
|
||||||
|
if (reg == ATAPI_REG_FEATURES)
|
||||||
|
{
|
||||||
|
reg = ATAPI_REG_ERROR;
|
||||||
|
}
|
||||||
|
data = atapi_regs[reg];
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
switch( reg )
|
||||||
|
{
|
||||||
|
case ATAPI_REG_DATA:
|
||||||
|
printf( "atapi_r: data=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_ERROR:
|
||||||
|
printf( "atapi_r: error=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_INTREASON:
|
||||||
|
printf( "atapi_r: intreason=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_SAMTAG:
|
||||||
|
printf( "atapi_r: samtag=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_COUNTLOW:
|
||||||
|
printf( "atapi_r: countlow=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_COUNTHIGH:
|
||||||
|
printf( "atapi_r: counthigh=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_DRIVESEL:
|
||||||
|
printf( "atapi_r: drivesel=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_CMDSTATUS:
|
||||||
|
printf( "atapi_r: cmdstatus=%02x\n", data );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mame_printf_debug("ATAPI: read reg %d = %x (PC=%x)\n", reg, data, cpu_get_pc(&space->device()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf( "atapi_r( %08x, %08x ) %08x\n", offset, mem_mask, data );
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WRITE32_HANDLER( atapi_w )
|
||||||
|
{
|
||||||
|
running_machine &machine = space->machine();
|
||||||
|
int reg;
|
||||||
|
|
||||||
|
// printf( "atapi_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
|
||||||
|
|
||||||
|
if (mem_mask == 0x0000ffff) // word-wide command write
|
||||||
|
{
|
||||||
|
// printf("atapi_w: data=%04x\n", data );
|
||||||
|
|
||||||
|
// printf("ATAPI: packet write %04x\n", data);
|
||||||
|
atapi_data[atapi_data_ptr++] = data & 0xff;
|
||||||
|
atapi_data[atapi_data_ptr++] = data >> 8;
|
||||||
|
|
||||||
|
if (atapi_cdata_wait)
|
||||||
|
{
|
||||||
|
// printf("ATAPI: waiting, ptr %d wait %d\n", atapi_data_ptr, atapi_cdata_wait);
|
||||||
|
if (atapi_data_ptr == atapi_cdata_wait)
|
||||||
|
{
|
||||||
|
// send it to the device
|
||||||
|
SCSIWriteData( gdrom_device, atapi_data, atapi_cdata_wait );
|
||||||
|
|
||||||
|
// assert IRQ
|
||||||
|
gdrom_raise_irq(machine);
|
||||||
|
|
||||||
|
// not sure here, but clear DRQ at least?
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( atapi_data_ptr == 12 )
|
||||||
|
{
|
||||||
|
int phase;
|
||||||
|
|
||||||
|
// printf("atapi_w: command %02x\n", atapi_data[0]&0xff );
|
||||||
|
|
||||||
|
// reset data pointer for reading SCSI results
|
||||||
|
atapi_data_ptr = 0;
|
||||||
|
atapi_data_len = 0;
|
||||||
|
|
||||||
|
// send it to the SCSI device
|
||||||
|
SCSISetCommand( gdrom_device, atapi_data, 12 );
|
||||||
|
SCSIExecCommand( gdrom_device, &atapi_xferlen );
|
||||||
|
SCSIGetPhase( gdrom_device, &phase );
|
||||||
|
|
||||||
|
if (atapi_xferlen != -1)
|
||||||
|
{
|
||||||
|
printf("ATAPI: SCSI command %02x returned %d bytes from the device\n", atapi_data[0]&0xff, atapi_xferlen);
|
||||||
|
|
||||||
|
// store the returned command length in the ATAPI regs, splitting into
|
||||||
|
// multiple transfers if necessary
|
||||||
|
atapi_xfermod = 0;
|
||||||
|
if (atapi_xferlen > MAX_TRANSFER_SIZE)
|
||||||
|
{
|
||||||
|
atapi_xfermod = atapi_xferlen - MAX_TRANSFER_SIZE;
|
||||||
|
atapi_xferlen = MAX_TRANSFER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff;
|
||||||
|
|
||||||
|
gdrom_alt_status = 0; // (I guess?)
|
||||||
|
|
||||||
|
if (atapi_xferlen == 0)
|
||||||
|
{
|
||||||
|
// if no data to return, set the registers properly
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY;
|
||||||
|
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO|ATAPI_INTREASON_COMMAND;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// indicate data ready: set DRQ and DMA ready, and IO in INTREASON
|
||||||
|
if (atapi_regs[ATAPI_REG_FEATURES] & 0x01) // DMA feature
|
||||||
|
{
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_BSY | ATAPI_STAT_DRDY | ATAPI_STAT_SERVDSC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC | ATAPI_STAT_DRQ;
|
||||||
|
}
|
||||||
|
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( phase )
|
||||||
|
{
|
||||||
|
case SCSI_PHASE_DATAOUT:
|
||||||
|
atapi_cdata_wait = atapi_xferlen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform special ATAPI processing of certain commands
|
||||||
|
switch (atapi_data[0]&0xff)
|
||||||
|
{
|
||||||
|
case 0x00: // BUS RESET / TEST UNIT READY
|
||||||
|
case 0xbb: // SET CDROM SPEED
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x45: // PLAY
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_BSY;
|
||||||
|
atapi_timer->adjust( downcast<cpu_device *>(&space->device())->cycles_to_attotime(ATAPI_CYCLES_PER_SECTOR ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert IRQ
|
||||||
|
gdrom_raise_irq(machine);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ATAPI: SCSI device returned error!\n");
|
||||||
|
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_CHECK;
|
||||||
|
atapi_regs[ATAPI_REG_ERROR] = 0x50; // sense key = ILLEGAL REQUEST
|
||||||
|
atapi_regs[ATAPI_REG_COUNTLOW] = 0;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTHIGH] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reg = offset;
|
||||||
|
#if 0
|
||||||
|
switch( reg )
|
||||||
|
{
|
||||||
|
case ATAPI_REG_DATA:
|
||||||
|
printf( "atapi_w: data=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_FEATURES:
|
||||||
|
printf( "atapi_w: features=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_INTREASON:
|
||||||
|
printf( "atapi_w: intreason=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_SAMTAG:
|
||||||
|
printf( "atapi_w: samtag=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_COUNTLOW:
|
||||||
|
printf( "atapi_w: countlow=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_COUNTHIGH:
|
||||||
|
printf( "atapi_w: counthigh=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_DRIVESEL:
|
||||||
|
printf( "atapi_w: drivesel=%02x\n", data );
|
||||||
|
break;
|
||||||
|
case ATAPI_REG_CMDSTATUS:
|
||||||
|
printf( "atapi_w: cmdstatus=%02x\n", data );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
atapi_regs[reg] = data;
|
||||||
|
// mame_printf_debug("ATAPI: reg %d = %x (offset %x mask %x PC=%x)\n", reg, data, offset, mem_mask, cpu_get_pc(&space->device()));
|
||||||
|
|
||||||
|
if (reg == ATAPI_REG_CMDSTATUS)
|
||||||
|
{
|
||||||
|
printf("ATAPI command %x issued! (PC=%x)\n", data, cpu_get_pc(&space->device()));
|
||||||
|
|
||||||
|
switch (data)
|
||||||
|
{
|
||||||
|
case 0xa0: // PACKET
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ;
|
||||||
|
gdrom_alt_status = ATAPI_STAT_DRQ;
|
||||||
|
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_COMMAND;
|
||||||
|
|
||||||
|
atapi_data_ptr = 0;
|
||||||
|
atapi_data_len = 0;
|
||||||
|
|
||||||
|
/* we have no data */
|
||||||
|
atapi_xferlen = 0;
|
||||||
|
atapi_xfermod = 0;
|
||||||
|
|
||||||
|
atapi_cdata_wait = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xa1: // IDENTIFY PACKET DEVICE
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ;
|
||||||
|
gdrom_alt_status = ATAPI_STAT_DRQ;
|
||||||
|
|
||||||
|
atapi_data_ptr = 0;
|
||||||
|
atapi_data_len = 512;
|
||||||
|
|
||||||
|
/* we have no data */
|
||||||
|
atapi_xferlen = 0;
|
||||||
|
atapi_xfermod = 0;
|
||||||
|
|
||||||
|
memset( atapi_data, 0, atapi_data_len );
|
||||||
|
|
||||||
|
atapi_data[ 0 ^ 1 ] = 0x86; // ATAPI device, cmd set 6 compliant, DRQ within 3 ms of PACKET command
|
||||||
|
atapi_data[ 1 ^ 1 ] = 0x00;
|
||||||
|
|
||||||
|
memset( &atapi_data[ 46 ], ' ', 8 );
|
||||||
|
atapi_data[ 46 ^ 1 ] = 'S';
|
||||||
|
atapi_data[ 47 ^ 1 ] = 'E';
|
||||||
|
|
||||||
|
memset( &atapi_data[ 54 ], ' ', 40 );
|
||||||
|
atapi_data[ 54 ^ 1 ] = 'C';
|
||||||
|
atapi_data[ 55 ^ 1 ] = 'D';
|
||||||
|
atapi_data[ 56 ^ 1 ] = '-';
|
||||||
|
atapi_data[ 57 ^ 1 ] = 'R';
|
||||||
|
atapi_data[ 58 ^ 1 ] = 'O';
|
||||||
|
atapi_data[ 59 ^ 1 ] = 'M';
|
||||||
|
atapi_data[ 60 ^ 1 ] = ' ';
|
||||||
|
atapi_data[ 61 ^ 1 ] = 'D';
|
||||||
|
atapi_data[ 62 ^ 1 ] = 'R';
|
||||||
|
atapi_data[ 63 ^ 1 ] = 'I';
|
||||||
|
atapi_data[ 64 ^ 1 ] = 'V';
|
||||||
|
atapi_data[ 65 ^ 1 ] = 'E';
|
||||||
|
atapi_data[ 66 ^ 1 ] = ' ';
|
||||||
|
atapi_data[ 67 ^ 1 ] = ' ';
|
||||||
|
atapi_data[ 68 ^ 1 ] = ' ';
|
||||||
|
atapi_data[ 69 ^ 1 ] = ' ';
|
||||||
|
atapi_data[ 70 ^ 1 ] = '6';
|
||||||
|
atapi_data[ 71 ^ 1 ] = '.';
|
||||||
|
atapi_data[ 72 ^ 1 ] = '4';
|
||||||
|
atapi_data[ 73 ^ 1 ] = '2';
|
||||||
|
|
||||||
|
atapi_data[ 98 ^ 1 ] = 0x04; // IORDY may be disabled
|
||||||
|
atapi_data[ 99 ^ 1 ] = 0x00;
|
||||||
|
|
||||||
|
atapi_regs[ATAPI_REG_COUNTLOW] = 0;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTHIGH] = 2;
|
||||||
|
|
||||||
|
gdrom_raise_irq(space->machine());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xef: // SET FEATURES
|
||||||
|
// set xfer mode?
|
||||||
|
if (atapi_regs[ATAPI_REG_FEATURES] == 0x03)
|
||||||
|
{
|
||||||
|
printf("Set transfer mode to %x\n", atapi_regs[ATAPI_REG_COUNTLOW] & 0xf8);
|
||||||
|
xfer_mode = atapi_regs[ATAPI_REG_COUNTLOW] & 0xf8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ATAPI: Unknown set features %x\n", atapi_regs[ATAPI_REG_FEATURES]);
|
||||||
|
}
|
||||||
|
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
|
||||||
|
gdrom_alt_status = 0; // is this correct?
|
||||||
|
|
||||||
|
atapi_data_ptr = 0;
|
||||||
|
atapi_data_len = 0;
|
||||||
|
|
||||||
|
gdrom_raise_irq(space->machine());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mame_printf_debug("ATAPI: Unknown IDE command %x\n", data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dreamcast_atapi_exit(running_machine& machine)
|
||||||
|
{
|
||||||
|
if (gdrom_device != NULL)
|
||||||
|
{
|
||||||
|
SCSIDeleteInstance( gdrom_device );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dreamcast_atapi_init(running_machine &machine)
|
||||||
|
{
|
||||||
|
atapi_regs = auto_alloc_array(machine, UINT8, ATAPI_REG_MAX );
|
||||||
|
memset(atapi_regs, 0, sizeof(atapi_regs));
|
||||||
|
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
|
||||||
|
atapi_regs[ATAPI_REG_ERROR] = 1;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTLOW] = 0x14;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTHIGH] = 0xeb;
|
||||||
|
|
||||||
|
atapi_data_ptr = 0;
|
||||||
|
atapi_data_len = 0;
|
||||||
|
atapi_cdata_wait = 0;
|
||||||
|
|
||||||
|
atapi_timer = machine.scheduler().timer_alloc(FUNC(atapi_xfer_end));
|
||||||
|
atapi_timer->adjust(attotime::never);
|
||||||
|
|
||||||
|
gdrom_device = NULL;
|
||||||
|
|
||||||
|
machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(dreamcast_atapi_exit),&machine));
|
||||||
|
|
||||||
|
atapi_data = auto_alloc_array(machine, UINT8, ATAPI_DATA_SIZE );
|
||||||
|
|
||||||
|
state_save_register_global_pointer(machine, atapi_regs, ATAPI_REG_MAX );
|
||||||
|
state_save_register_global_pointer(machine, atapi_data, ATAPI_DATA_SIZE / 2 );
|
||||||
|
state_save_register_global(machine, atapi_data_ptr );
|
||||||
|
state_save_register_global(machine, atapi_data_len );
|
||||||
|
state_save_register_global(machine, atapi_xferlen );
|
||||||
|
state_save_register_global(machine, atapi_xferbase );
|
||||||
|
state_save_register_global(machine, atapi_cdata_wait );
|
||||||
|
state_save_register_global(machine, atapi_xfermod );
|
||||||
|
}
|
||||||
|
|
||||||
|
void dreamcast_atapi_reset(running_machine &machine)
|
||||||
|
{
|
||||||
|
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
|
||||||
|
atapi_regs[ATAPI_REG_ERROR] = 1;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTLOW] = 0x14;
|
||||||
|
atapi_regs[ATAPI_REG_COUNTHIGH] = 0xeb;
|
||||||
|
|
||||||
|
atapi_data_ptr = 0;
|
||||||
|
atapi_data_len = 0;
|
||||||
|
atapi_cdata_wait = 0;
|
||||||
|
|
||||||
|
atapi_xferlen = 0;
|
||||||
|
atapi_xfermod = 0;
|
||||||
|
|
||||||
|
if ( cd_get_cdrom_file(machine.device( "cdrom" )) != NULL )
|
||||||
|
{
|
||||||
|
SCSIAllocInstance( machine, &SCSIClassGDROM, &gdrom_device, "cdrom" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gdrom_device = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
GDROM regsters:
|
||||||
|
|
||||||
|
5f7018: alternate status/device control
|
||||||
|
5f7080: data
|
||||||
|
5f7084: error/features
|
||||||
|
5f7088: interrupt reason/sector count
|
||||||
|
5f708c: sector number
|
||||||
|
5f7090: byte control low
|
||||||
|
5f7094: byte control high
|
||||||
|
5f7098: drive select
|
||||||
|
5f709c: status/command
|
||||||
|
|
||||||
|
c002910 - ATAPI packet writes
|
||||||
|
c002796 - aux status read after that
|
||||||
|
c000776 - DMA triggered to c008000
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
READ64_HANDLER( dc_mess_gdrom_r )
|
||||||
|
{
|
||||||
|
UINT32 off;
|
||||||
|
|
||||||
|
if ((int)~mem_mask & 1)
|
||||||
|
{
|
||||||
|
off=(offset << 1) | 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
off=offset << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("gdrom_r: @ %x (off %x), mask %llx (PC %x)\n", offset, off, mem_mask, cpu_get_pc(&space->device()));
|
||||||
|
|
||||||
|
if (offset == 3)
|
||||||
|
{
|
||||||
|
return gdrom_alt_status;
|
||||||
|
}
|
||||||
|
else if (off >= 0x20)
|
||||||
|
{
|
||||||
|
return atapi_r(space, off-0x20, 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE64_HANDLER( dc_mess_gdrom_w )
|
||||||
|
{
|
||||||
|
UINT32 dat,off;
|
||||||
|
|
||||||
|
if ((int)~mem_mask & 1)
|
||||||
|
{
|
||||||
|
dat=(UINT32)(data >> 32);
|
||||||
|
off=(offset << 1) | 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dat=(UINT32)data;
|
||||||
|
off=offset << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("GDROM: [%08x=%x]write %llx to %x, mask %llx (PC %x)\n", 0x5f7000+off*4, dat, data, offset, mem_mask, cpu_get_pc(&space->device()));
|
||||||
|
|
||||||
|
if (off >= 0x20)
|
||||||
|
{
|
||||||
|
atapi_w(space, off-0x20, dat, (UINT32)mem_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// register decode helpers
|
||||||
|
|
||||||
|
// this accepts only 32-bit accesses
|
||||||
|
INLINE int decode_reg32_64(running_machine &machine, UINT32 offset, UINT64 mem_mask, UINT64 *shift)
|
||||||
|
{
|
||||||
|
int reg = offset * 2;
|
||||||
|
|
||||||
|
*shift = 0;
|
||||||
|
|
||||||
|
// non 32-bit accesses have not yet been seen here, we need to know when they are
|
||||||
|
if ((mem_mask != U64(0xffffffff00000000)) && (mem_mask != U64(0x00000000ffffffff)))
|
||||||
|
{
|
||||||
|
mame_printf_verbose("%s:Wrong mask!\n", machine.describe_context());
|
||||||
|
// debugger_break(machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem_mask == U64(0xffffffff00000000))
|
||||||
|
{
|
||||||
|
reg++;
|
||||||
|
*shift = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
READ64_HANDLER( dc_mess_g1_ctrl_r )
|
||||||
|
{
|
||||||
|
int reg;
|
||||||
|
UINT64 shift;
|
||||||
|
|
||||||
|
reg = decode_reg32_64(space->machine(), offset, mem_mask, &shift);
|
||||||
|
mame_printf_verbose("G1CTRL: Unmapped read %08x\n", 0x5f7400+reg*4);
|
||||||
|
return (UINT64)g1bus_regs[reg] << shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE64_HANDLER( dc_mess_g1_ctrl_w )
|
||||||
|
{
|
||||||
|
int reg;
|
||||||
|
UINT64 shift;
|
||||||
|
UINT32 old,dat;
|
||||||
|
|
||||||
|
reg = decode_reg32_64(space->machine(), offset, mem_mask, &shift);
|
||||||
|
dat = (UINT32)(data >> shift);
|
||||||
|
old = g1bus_regs[reg];
|
||||||
|
|
||||||
|
g1bus_regs[reg] = dat; // 5f7400+reg*4=dat
|
||||||
|
mame_printf_verbose("G1CTRL: [%08x=%x] write %" I64FMT "x to %x, mask %" I64FMT "x\n", 0x5f7400+reg*4, dat, data, offset, mem_mask);
|
||||||
|
switch (reg)
|
||||||
|
{
|
||||||
|
case SB_GDST:
|
||||||
|
if (dat & 1 && g1bus_regs[SB_GDEN] == 1) // 0 -> 1
|
||||||
|
{
|
||||||
|
if (g1bus_regs[SB_GDDIR] == 0)
|
||||||
|
{
|
||||||
|
printf("G1CTRL: unsupported transfer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
atapi_xferbase = g1bus_regs[SB_GDSTAR];
|
||||||
|
atapi_timer->adjust(space->machine().device<cpu_device>("maincpu")->cycles_to_attotime((ATAPI_CYCLES_PER_SECTOR * (atapi_xferlen/2048))));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
874
src/mame/machine/gdrom.c
Normal file
874
src/mame/machine/gdrom.c
Normal file
@ -0,0 +1,874 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
gdrom.c - Implementation of the Sega GD-ROM device
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
#include "machine/scsidev.h"
|
||||||
|
#include "cdrom.h"
|
||||||
|
#include "sound/cdda.h"
|
||||||
|
#include "imagedev/chd_cd.h"
|
||||||
|
#include "gdrom.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UINT32 lba;
|
||||||
|
UINT32 blocks;
|
||||||
|
UINT32 last_lba;
|
||||||
|
UINT32 bytes_per_sector;
|
||||||
|
UINT32 num_subblocks;
|
||||||
|
UINT32 cur_subblock;
|
||||||
|
UINT32 play_err_flag;
|
||||||
|
UINT32 read_type; // for command 0x30 only
|
||||||
|
UINT32 data_select; // for command 0x30 only
|
||||||
|
cdrom_file *cdrom;
|
||||||
|
bool is_file;
|
||||||
|
} SCSIGd;
|
||||||
|
|
||||||
|
static const UINT8 GDROM_Cmd11_Reply[32] =
|
||||||
|
{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x19, 0x00, 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2E, 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36
|
||||||
|
};
|
||||||
|
|
||||||
|
static void phys_frame_to_msf(int phys_frame, int *m, int *s, int *f)
|
||||||
|
{
|
||||||
|
*m = phys_frame / (60*75);
|
||||||
|
phys_frame -= (*m * 60 * 75);
|
||||||
|
*s = phys_frame / 75;
|
||||||
|
*f = phys_frame % 75;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// scsicd_exec_command
|
||||||
|
//
|
||||||
|
// Execute a SCSI command.
|
||||||
|
|
||||||
|
static int scsicd_exec_command( SCSIInstance *scsiInstance, UINT8 *statusCode )
|
||||||
|
{
|
||||||
|
UINT8 *command;
|
||||||
|
int commandLength;
|
||||||
|
SCSIGd *our_this = (SCSIGd *)SCSIThis( &SCSIClassGDROM, scsiInstance );
|
||||||
|
|
||||||
|
cdrom_file *cdrom = our_this->cdrom;
|
||||||
|
device_t *cdda;
|
||||||
|
int trk;
|
||||||
|
|
||||||
|
SCSIGetCommand( scsiInstance, &command, &commandLength );
|
||||||
|
|
||||||
|
switch ( command[0] )
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
case 0x03: // REQUEST SENSE
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return SCSILengthFromUINT8( &command[ 4 ] );
|
||||||
|
|
||||||
|
case 0x11: // REQ_MODE
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
printf("REQ_MODE %02x %02x %02x %02x %02x %02x\n",
|
||||||
|
command[0], command[1],
|
||||||
|
command[2], command[3],
|
||||||
|
command[4], command[5]);
|
||||||
|
// if (SCSILengthFromUINT8( &command[ 4 ] ) < 32) return -1;
|
||||||
|
return 32; //SCSILengthFromUINT8( &command[ 4 ] );
|
||||||
|
|
||||||
|
case 0x12: // INQUIRY
|
||||||
|
logerror("GDROM: REQUEST SENSE\n");
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return SCSILengthFromUINT8( &command[ 4 ] );
|
||||||
|
|
||||||
|
case 0x15: // MODE SELECT(6)
|
||||||
|
logerror("GDROM: MODE SELECT(6) length %x control %x\n", command[4], command[5]);
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAOUT );
|
||||||
|
return SCSILengthFromUINT8( &command[ 4 ] );
|
||||||
|
|
||||||
|
case 0x1a: // MODE SENSE(6)
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return SCSILengthFromUINT8( &command[ 4 ] );
|
||||||
|
|
||||||
|
case 0x1b: // START STOP UNIT
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
{
|
||||||
|
cdda_stop_audio(cdda);
|
||||||
|
}
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 0x1e: // PREVENT ALLOW MEDIUM REMOVAL
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 0x25: // READ CAPACITY
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case 0x28: // READ(10)
|
||||||
|
|
||||||
|
our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
|
||||||
|
our_this->blocks = SCSILengthFromUINT16( &command[7] );
|
||||||
|
|
||||||
|
logerror("GDROM: READ(10) at LBA %x for %d blocks (%d bytes)\n", our_this->lba, our_this->blocks, our_this->blocks * our_this->bytes_per_sector);
|
||||||
|
|
||||||
|
if (our_this->num_subblocks > 1)
|
||||||
|
{
|
||||||
|
our_this->cur_subblock = our_this->lba % our_this->num_subblocks;
|
||||||
|
our_this->lba /= our_this->num_subblocks;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
our_this->cur_subblock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
{
|
||||||
|
cdda_stop_audio(cdda);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return our_this->blocks * our_this->bytes_per_sector;
|
||||||
|
|
||||||
|
case 0x30: // CD_READ
|
||||||
|
if (command[1] & 1)
|
||||||
|
{
|
||||||
|
fatalerror("GDROM: MSF mode used for CD_READ, unsupported");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
our_this->lba = (command[2]<<16 | command[3]<<8 | command[4]) - 150;
|
||||||
|
our_this->blocks = command[8]<<16 | command[9]<<8 | command[10];
|
||||||
|
|
||||||
|
our_this->read_type = (command[1] >> 1) & 7;
|
||||||
|
our_this->data_select = (command[1]>>4) & 0xf;
|
||||||
|
|
||||||
|
if (our_this->read_type != 2) // mode 1
|
||||||
|
{
|
||||||
|
fatalerror("GDROM: Unhandled read_type %d", our_this->read_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (our_this->data_select != 2) // just sector data
|
||||||
|
{
|
||||||
|
fatalerror("GDROM: Unhandled data_select %d", our_this->data_select);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("GDROM: CD_READ at LBA %x for %d blocks (%d bytes, read type %d, data select %d)\n", our_this->lba, our_this->blocks, our_this->blocks * our_this->bytes_per_sector, our_this->read_type, our_this->data_select);
|
||||||
|
|
||||||
|
if (our_this->num_subblocks > 1)
|
||||||
|
{
|
||||||
|
our_this->cur_subblock = our_this->lba % our_this->num_subblocks;
|
||||||
|
our_this->lba /= our_this->num_subblocks;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
our_this->cur_subblock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
{
|
||||||
|
cdda_stop_audio(cdda);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return our_this->blocks * our_this->bytes_per_sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x42: // READ SUB-CHANNEL
|
||||||
|
// logerror("GDROM: READ SUB-CHANNEL type %d\n", command[3]);
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return SCSILengthFromUINT16( &command[ 7 ] );
|
||||||
|
|
||||||
|
case 0x43: // READ TOC
|
||||||
|
{
|
||||||
|
int start_trk = command[6];
|
||||||
|
int end_trk = cdrom_get_last_track(cdrom);
|
||||||
|
int length;
|
||||||
|
int allocation_length = SCSILengthFromUINT16( &command[ 7 ] );
|
||||||
|
|
||||||
|
if( start_trk == 0 )
|
||||||
|
{
|
||||||
|
start_trk = 1;
|
||||||
|
}
|
||||||
|
if( start_trk == 0xaa )
|
||||||
|
{
|
||||||
|
end_trk = start_trk;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = 4 + ( 8 * ( ( end_trk - start_trk ) + 1 ) );
|
||||||
|
if( length > allocation_length )
|
||||||
|
{
|
||||||
|
length = allocation_length;
|
||||||
|
}
|
||||||
|
else if( length < 4 )
|
||||||
|
{
|
||||||
|
length = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
{
|
||||||
|
cdda_stop_audio(cdda);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
case 0x45: // PLAY AUDIO(10)
|
||||||
|
our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
|
||||||
|
our_this->blocks = SCSILengthFromUINT16( &command[7] );
|
||||||
|
|
||||||
|
// special cases: lba of 0 means MSF of 00:02:00
|
||||||
|
if (our_this->lba == 0)
|
||||||
|
{
|
||||||
|
our_this->lba = 150;
|
||||||
|
}
|
||||||
|
else if (our_this->lba == 0xffffffff)
|
||||||
|
{
|
||||||
|
logerror("GDROM: play audio from current not implemented!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
logerror("GDROM: PLAY AUDIO(10) at LBA %x for %x blocks\n", our_this->lba, our_this->blocks);
|
||||||
|
|
||||||
|
trk = cdrom_get_track(cdrom, our_this->lba);
|
||||||
|
|
||||||
|
if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO)
|
||||||
|
{
|
||||||
|
our_this->play_err_flag = 0;
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
cdda_start_audio(cdda, our_this->lba, our_this->blocks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logerror("GDROM: track is NOT audio!\n");
|
||||||
|
our_this->play_err_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 0x48: // PLAY AUDIO TRACK/INDEX
|
||||||
|
// be careful: tracks here are zero-based, but the SCSI command
|
||||||
|
// uses the real CD track number which is 1-based!
|
||||||
|
our_this->lba = cdrom_get_track_start(cdrom, command[4]-1);
|
||||||
|
our_this->blocks = cdrom_get_track_start(cdrom, command[7]-1) - our_this->lba;
|
||||||
|
if (command[4] > command[7])
|
||||||
|
{
|
||||||
|
our_this->blocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command[4] == command[7])
|
||||||
|
{
|
||||||
|
our_this->blocks = cdrom_get_track_start(cdrom, command[4]) - our_this->lba;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (our_this->blocks && cdrom)
|
||||||
|
{
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
cdda_start_audio(cdda, our_this->lba, our_this->blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
logerror("GDROM: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], our_this->blocks);
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 0x4b: // PAUSE/RESUME
|
||||||
|
if (cdrom)
|
||||||
|
{
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
cdda_pause_audio(cdda, (command[8] & 0x01) ^ 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
logerror("GDROM: PAUSE/RESUME: %s\n", command[8]&1 ? "RESUME" : "PAUSE");
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 0x55: // MODE SELECT(10)
|
||||||
|
logerror("GDROM: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]);
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAOUT );
|
||||||
|
return SCSILengthFromUINT16( &command[ 7 ] );
|
||||||
|
|
||||||
|
case 0x5a: // MODE SENSE(10)
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return SCSILengthFromUINT16( &command[ 7 ] );
|
||||||
|
|
||||||
|
case 0xa5: // PLAY AUDIO(12)
|
||||||
|
our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
|
||||||
|
our_this->blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9];
|
||||||
|
|
||||||
|
// special cases: lba of 0 means MSF of 00:02:00
|
||||||
|
if (our_this->lba == 0)
|
||||||
|
{
|
||||||
|
our_this->lba = 150;
|
||||||
|
}
|
||||||
|
else if (our_this->lba == 0xffffffff)
|
||||||
|
{
|
||||||
|
logerror("GDROM: play audio from current not implemented!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
logerror("GDROM: PLAY AUDIO(12) at LBA %x for %x blocks\n", our_this->lba, our_this->blocks);
|
||||||
|
|
||||||
|
trk = cdrom_get_track(cdrom, our_this->lba);
|
||||||
|
|
||||||
|
if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO)
|
||||||
|
{
|
||||||
|
our_this->play_err_flag = 0;
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
cdda_start_audio(cdda, our_this->lba, our_this->blocks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logerror("GDROM: track is NOT audio!\n");
|
||||||
|
our_this->play_err_flag = 1;
|
||||||
|
}
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 0xa8: // READ(12)
|
||||||
|
our_this->lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
|
||||||
|
our_this->blocks = command[7]<<16 | command[8]<<8 | command[9];
|
||||||
|
|
||||||
|
logerror("GDROM: READ(12) at LBA %x for %x blocks (%x bytes)\n", our_this->lba, our_this->blocks, our_this->blocks * our_this->bytes_per_sector);
|
||||||
|
|
||||||
|
if (our_this->num_subblocks > 1)
|
||||||
|
{
|
||||||
|
our_this->cur_subblock = our_this->lba % our_this->num_subblocks;
|
||||||
|
our_this->lba /= our_this->num_subblocks;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
our_this->cur_subblock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL)
|
||||||
|
{
|
||||||
|
cdda_stop_audio(cdda);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_DATAIN );
|
||||||
|
return our_this->blocks * our_this->bytes_per_sector;
|
||||||
|
|
||||||
|
case 0xbb: // SET CD SPEED
|
||||||
|
logerror("GDROM: SET CD SPEED to %d kbytes/sec.\n", command[2]<<8 | command[3]);
|
||||||
|
SCSISetPhase( scsiInstance, SCSI_PHASE_STATUS );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SCSIBase( &SCSIClassGDROM, SCSIOP_EXEC_COMMAND, scsiInstance, 0, NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scsicd_read_data
|
||||||
|
//
|
||||||
|
// Read data from the device resulting from the execution of a command
|
||||||
|
|
||||||
|
static void scsicd_read_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
|
||||||
|
{
|
||||||
|
UINT8 *command;
|
||||||
|
int commandLength;
|
||||||
|
SCSIGd *our_this = (SCSIGd *)SCSIThis( &SCSIClassGDROM, scsiInstance );
|
||||||
|
|
||||||
|
int i;
|
||||||
|
UINT32 last_phys_frame;
|
||||||
|
cdrom_file *cdrom = our_this->cdrom;
|
||||||
|
UINT32 temp;
|
||||||
|
UINT8 tmp_buffer[2048];
|
||||||
|
device_t *cdda;
|
||||||
|
|
||||||
|
SCSIGetCommand( scsiInstance, &command, &commandLength );
|
||||||
|
|
||||||
|
switch ( command[0] )
|
||||||
|
{
|
||||||
|
case 0x03: // REQUEST SENSE
|
||||||
|
logerror("GDROM: Reading REQUEST SENSE data\n");
|
||||||
|
|
||||||
|
memset( data, 0, dataLength );
|
||||||
|
|
||||||
|
data[0] = 0x71; // deferred error
|
||||||
|
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
if (cdda != NULL && cdda_audio_active(cdda))
|
||||||
|
{
|
||||||
|
data[12] = 0x00;
|
||||||
|
data[13] = 0x11; // AUDIO PLAY OPERATION IN PROGRESS
|
||||||
|
}
|
||||||
|
else if (our_this->play_err_flag)
|
||||||
|
{
|
||||||
|
our_this->play_err_flag = 0;
|
||||||
|
data[12] = 0x64; // ILLEGAL MODE FOR THIS TRACK
|
||||||
|
data[13] = 0x00;
|
||||||
|
}
|
||||||
|
// (else 00/00 means no error to report)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x11: // REQ_MODE
|
||||||
|
printf("REQ_MODE: dataLength %d\n", dataLength);
|
||||||
|
memcpy(data, &GDROM_Cmd11_Reply[0], (dataLength >= 32) ? 32 : dataLength);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x12: // INQUIRY
|
||||||
|
memset( data, 0, dataLength );
|
||||||
|
data[0] = 0x05; // device is present, device is CD/DVD (MMC-3)
|
||||||
|
data[1] = 0x80; // media is removable
|
||||||
|
data[2] = 0x05; // device complies with SPC-3 standard
|
||||||
|
data[3] = 0x02; // response data format = SPC-3 standard
|
||||||
|
// some Konami games freak out if this isn't "Sony", so we'll lie
|
||||||
|
// this is the actual drive on my Nagano '98 board
|
||||||
|
strcpy((char *)&data[8], "Sony");
|
||||||
|
strcpy((char *)&data[16], "CDU-76S");
|
||||||
|
strcpy((char *)&data[32], "1.0");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x25: // READ CAPACITY
|
||||||
|
logerror("GDROM: READ CAPACITY\n");
|
||||||
|
|
||||||
|
temp = cdrom_get_track_start(cdrom, 0xaa);
|
||||||
|
temp--; // return the last used block on the disc
|
||||||
|
|
||||||
|
data[0] = (temp>>24) & 0xff;
|
||||||
|
data[1] = (temp>>16) & 0xff;
|
||||||
|
data[2] = (temp>>8) & 0xff;
|
||||||
|
data[3] = (temp & 0xff);
|
||||||
|
data[4] = 0;
|
||||||
|
data[5] = 0;
|
||||||
|
data[6] = (our_this->bytes_per_sector>>8)&0xff;
|
||||||
|
data[7] = (our_this->bytes_per_sector & 0xff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x28: // READ(10)
|
||||||
|
case 0xa8: // READ(12)
|
||||||
|
logerror("GDROM: read %x dataLength, \n", dataLength);
|
||||||
|
if ((our_this->cdrom) && (our_this->blocks))
|
||||||
|
{
|
||||||
|
while (dataLength > 0)
|
||||||
|
{
|
||||||
|
if (!cdrom_read_data(our_this->cdrom, our_this->lba, tmp_buffer, CD_TRACK_MODE1))
|
||||||
|
{
|
||||||
|
logerror("GDROM: CD read error!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
logerror("True LBA: %d, buffer half: %d\n", our_this->lba, our_this->cur_subblock * our_this->bytes_per_sector);
|
||||||
|
|
||||||
|
memcpy(data, &tmp_buffer[our_this->cur_subblock * our_this->bytes_per_sector], our_this->bytes_per_sector);
|
||||||
|
|
||||||
|
our_this->cur_subblock++;
|
||||||
|
if (our_this->cur_subblock >= our_this->num_subblocks)
|
||||||
|
{
|
||||||
|
our_this->cur_subblock = 0;
|
||||||
|
|
||||||
|
our_this->lba++;
|
||||||
|
our_this->blocks--;
|
||||||
|
}
|
||||||
|
|
||||||
|
our_this->last_lba = our_this->lba;
|
||||||
|
dataLength -= our_this->bytes_per_sector;
|
||||||
|
data += our_this->bytes_per_sector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x30: // CD_READ
|
||||||
|
logerror("GDROM: read %x dataLength, \n", dataLength);
|
||||||
|
if ((our_this->cdrom) && (our_this->blocks))
|
||||||
|
{
|
||||||
|
while (dataLength > 0)
|
||||||
|
{
|
||||||
|
if (!cdrom_read_data(our_this->cdrom, our_this->lba, tmp_buffer, CD_TRACK_MODE1))
|
||||||
|
{
|
||||||
|
logerror("GDROM: CD read error!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
logerror("True LBA: %d, buffer half: %d\n", our_this->lba, our_this->cur_subblock * our_this->bytes_per_sector);
|
||||||
|
|
||||||
|
memcpy(data, &tmp_buffer[our_this->cur_subblock * our_this->bytes_per_sector], our_this->bytes_per_sector);
|
||||||
|
|
||||||
|
our_this->cur_subblock++;
|
||||||
|
if (our_this->cur_subblock >= our_this->num_subblocks)
|
||||||
|
{
|
||||||
|
our_this->cur_subblock = 0;
|
||||||
|
|
||||||
|
our_this->lba++;
|
||||||
|
our_this->blocks--;
|
||||||
|
}
|
||||||
|
|
||||||
|
our_this->last_lba = our_this->lba;
|
||||||
|
dataLength -= our_this->bytes_per_sector;
|
||||||
|
data += our_this->bytes_per_sector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x42: // READ SUB-CHANNEL
|
||||||
|
switch (command[3])
|
||||||
|
{
|
||||||
|
case 1: // return current position
|
||||||
|
{
|
||||||
|
int audio_active;
|
||||||
|
int msf;
|
||||||
|
|
||||||
|
if (!cdrom)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logerror("GDROM: READ SUB-CHANNEL Time = %x, SUBQ = %x\n", command[1], command[2]);
|
||||||
|
|
||||||
|
msf = command[1] & 0x2;
|
||||||
|
|
||||||
|
cdda = cdda_from_cdrom(scsiInstance->machine(), cdrom);
|
||||||
|
audio_active = cdda != NULL && cdda_audio_active(cdda);
|
||||||
|
if (audio_active)
|
||||||
|
{
|
||||||
|
if (cdda_audio_paused(cdda))
|
||||||
|
{
|
||||||
|
data[1] = 0x12; // audio is paused
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data[1] = 0x11; // audio in progress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cdda != NULL && cdda_audio_ended(cdda))
|
||||||
|
{
|
||||||
|
data[1] = 0x13; // ended successfully
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// data[1] = 0x14; // stopped due to error
|
||||||
|
data[1] = 0x15; // No current audio status to return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if audio is playing, get the latest LBA from the CDROM layer
|
||||||
|
if (audio_active)
|
||||||
|
{
|
||||||
|
our_this->last_lba = cdda_get_audio_lba(cdda);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
our_this->last_lba = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[2] = 0;
|
||||||
|
data[3] = 12; // data length
|
||||||
|
data[4] = 0x01; // sub-channel format code
|
||||||
|
data[5] = 0x10 | (audio_active ? 0 : 4);
|
||||||
|
data[6] = cdrom_get_track(cdrom, our_this->last_lba) + 1; // track
|
||||||
|
data[7] = 0; // index
|
||||||
|
|
||||||
|
last_phys_frame = our_this->last_lba;
|
||||||
|
|
||||||
|
if (msf)
|
||||||
|
{
|
||||||
|
int m,s,f;
|
||||||
|
phys_frame_to_msf(last_phys_frame, &m, &s, &f);
|
||||||
|
data[8] = 0;
|
||||||
|
data[9] = m;
|
||||||
|
data[10] = s;
|
||||||
|
data[11] = f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data[8] = last_phys_frame>>24;
|
||||||
|
data[9] = (last_phys_frame>>16)&0xff;
|
||||||
|
data[10] = (last_phys_frame>>8)&0xff;
|
||||||
|
data[11] = last_phys_frame&0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_phys_frame -= cdrom_get_track_start(cdrom, data[6] - 1);
|
||||||
|
|
||||||
|
if (msf)
|
||||||
|
{
|
||||||
|
int m,s,f;
|
||||||
|
phys_frame_to_msf(last_phys_frame, &m, &s, &f);
|
||||||
|
data[12] = 0;
|
||||||
|
data[13] = m;
|
||||||
|
data[14] = s;
|
||||||
|
data[15] = f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data[12] = last_phys_frame>>24;
|
||||||
|
data[13] = (last_phys_frame>>16)&0xff;
|
||||||
|
data[14] = (last_phys_frame>>8)&0xff;
|
||||||
|
data[15] = last_phys_frame&0xff;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
logerror("GDROM: Unknown subchannel type %d requested\n", command[3]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x43: // READ TOC
|
||||||
|
/*
|
||||||
|
Track numbers are problematic here: 0 = lead-in, 0xaa = lead-out.
|
||||||
|
That makes sense in terms of how real-world CDs are referred to, but
|
||||||
|
our internal routines for tracks use "0" as track 1. That probably
|
||||||
|
should be fixed...
|
||||||
|
*/
|
||||||
|
logerror("GDROM: READ TOC, format = %d time=%d\n", command[2]&0xf,(command[1]>>1)&1);
|
||||||
|
switch (command[2] & 0x0f)
|
||||||
|
{
|
||||||
|
case 0: // normal
|
||||||
|
{
|
||||||
|
int start_trk;
|
||||||
|
int end_trk;
|
||||||
|
int len;
|
||||||
|
int in_len;
|
||||||
|
int dptr;
|
||||||
|
UINT32 tstart;
|
||||||
|
|
||||||
|
start_trk = command[6];
|
||||||
|
if( start_trk == 0 )
|
||||||
|
{
|
||||||
|
start_trk = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_trk = cdrom_get_last_track(cdrom);
|
||||||
|
len = (end_trk * 8) + 2;
|
||||||
|
|
||||||
|
// the returned TOC DATA LENGTH must be the full amount,
|
||||||
|
// regardless of how much we're able to pass back due to in_len
|
||||||
|
dptr = 0;
|
||||||
|
data[dptr++] = (len>>8) & 0xff;
|
||||||
|
data[dptr++] = (len & 0xff);
|
||||||
|
data[dptr++] = 1;
|
||||||
|
data[dptr++] = end_trk;
|
||||||
|
|
||||||
|
if( start_trk == 0xaa )
|
||||||
|
{
|
||||||
|
end_trk = 0xaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_len = command[7]<<8 | command[8];
|
||||||
|
|
||||||
|
for (i = start_trk; i <= end_trk; i++)
|
||||||
|
{
|
||||||
|
int cdrom_track = i;
|
||||||
|
if( cdrom_track != 0xaa )
|
||||||
|
{
|
||||||
|
cdrom_track--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dptr >= in_len )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[dptr++] = 0;
|
||||||
|
data[dptr++] = cdrom_get_adr_control(cdrom, cdrom_track);
|
||||||
|
data[dptr++] = i;
|
||||||
|
data[dptr++] = 0;
|
||||||
|
|
||||||
|
tstart = cdrom_get_track_start(cdrom, cdrom_track);
|
||||||
|
if ((command[1]&2)>>1)
|
||||||
|
tstart = lba_to_msf(tstart);
|
||||||
|
data[dptr++] = (tstart>>24) & 0xff;
|
||||||
|
data[dptr++] = (tstart>>16) & 0xff;
|
||||||
|
data[dptr++] = (tstart>>8) & 0xff;
|
||||||
|
data[dptr++] = (tstart & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logerror("GDROM: Unhandled READ TOC format %d\n", command[2]&0xf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1a: // MODE SENSE(6)
|
||||||
|
case 0x5a: // MODE SENSE(10)
|
||||||
|
logerror("GDROM: MODE SENSE page code = %x, PC = %x\n", command[2] & 0x3f, (command[2]&0xc0)>>6);
|
||||||
|
|
||||||
|
switch (command[2] & 0x3f)
|
||||||
|
{
|
||||||
|
case 0xe: // CD Audio control page
|
||||||
|
data[0] = 0x8e; // page E, parameter is savable
|
||||||
|
data[1] = 0x0e; // page length
|
||||||
|
data[2] = 0x04; // IMMED = 1, SOTC = 0
|
||||||
|
data[3] = data[4] = data[5] = data[6] = data[7] = 0; // reserved
|
||||||
|
|
||||||
|
// connect each audio channel to 1 output port
|
||||||
|
data[8] = 1;
|
||||||
|
data[10] = 2;
|
||||||
|
data[12] = 4;
|
||||||
|
data[14] = 8;
|
||||||
|
|
||||||
|
// indicate max volume
|
||||||
|
data[9] = data[11] = data[13] = data[15] = 0xff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logerror("GDROM: MODE SENSE unknown page %x\n", command[2] & 0x3f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SCSIBase( &SCSIClassGDROM, SCSIOP_READ_DATA, scsiInstance, dataLength, data );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scsicd_write_data
|
||||||
|
//
|
||||||
|
// Write data to the CD-ROM device as part of the execution of a command
|
||||||
|
|
||||||
|
static void scsicd_write_data( SCSIInstance *scsiInstance, UINT8 *data, int dataLength )
|
||||||
|
{
|
||||||
|
UINT8 *command;
|
||||||
|
int commandLength;
|
||||||
|
SCSIGd *our_this = (SCSIGd *)SCSIThis( &SCSIClassGDROM, scsiInstance );
|
||||||
|
SCSIGetCommand( scsiInstance, &command, &commandLength );
|
||||||
|
|
||||||
|
switch (command[ 0 ])
|
||||||
|
{
|
||||||
|
case 0x15: // MODE SELECT(6)
|
||||||
|
case 0x55: // MODE SELECT(10)
|
||||||
|
logerror("GDROM: MODE SELECT page %x\n", data[0] & 0x3f);
|
||||||
|
|
||||||
|
switch (data[0] & 0x3f)
|
||||||
|
{
|
||||||
|
case 0x0: // vendor-specific
|
||||||
|
// check for SGI extension to force 512-byte blocks
|
||||||
|
if ((data[3] == 8) && (data[10] == 2))
|
||||||
|
{
|
||||||
|
logerror("GDROM: Experimental SGI 512-byte block extension enabled\n");
|
||||||
|
|
||||||
|
our_this->bytes_per_sector = 512;
|
||||||
|
our_this->num_subblocks = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logerror("GDROM: Unknown vendor-specific page!\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xe: // audio page
|
||||||
|
logerror("Ch 0 route: %x vol: %x\n", data[8], data[9]);
|
||||||
|
logerror("Ch 1 route: %x vol: %x\n", data[10], data[11]);
|
||||||
|
logerror("Ch 2 route: %x vol: %x\n", data[12], data[13]);
|
||||||
|
logerror("Ch 3 route: %x vol: %x\n", data[14], data[15]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SCSIBase( &SCSIClassGDROM, SCSIOP_WRITE_DATA, scsiInstance, dataLength, data );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scsicd_alloc_instance( SCSIInstance *scsiInstance, const char *diskregion )
|
||||||
|
{
|
||||||
|
running_machine &machine = scsiInstance->machine();
|
||||||
|
SCSIGd *our_this = (SCSIGd *)SCSIThis( &SCSIClassGDROM, scsiInstance );
|
||||||
|
|
||||||
|
our_this->lba = 0;
|
||||||
|
our_this->blocks = 0;
|
||||||
|
our_this->last_lba = 0;
|
||||||
|
our_this->bytes_per_sector = 2048;
|
||||||
|
our_this->num_subblocks = 1;
|
||||||
|
our_this->cur_subblock = 0;
|
||||||
|
our_this->play_err_flag = 0;
|
||||||
|
|
||||||
|
state_save_register_item( machine, "scsicd", diskregion, 0, our_this->lba );
|
||||||
|
state_save_register_item( machine, "scsicd", diskregion, 0, our_this->blocks );
|
||||||
|
state_save_register_item( machine, "scsicd", diskregion, 0, our_this->last_lba );
|
||||||
|
state_save_register_item( machine, "scsicd", diskregion, 0, our_this->bytes_per_sector );
|
||||||
|
state_save_register_item( machine, "scsicd", diskregion, 0, our_this->num_subblocks );
|
||||||
|
state_save_register_item( machine, "scsicd", diskregion, 0, our_this->cur_subblock );
|
||||||
|
state_save_register_item( machine, "scsicd", diskregion, 0, our_this->play_err_flag );
|
||||||
|
|
||||||
|
if (machine.device( diskregion )) {
|
||||||
|
our_this->is_file = TRUE;
|
||||||
|
our_this->cdrom = cd_get_cdrom_file( machine.device( diskregion ) );
|
||||||
|
} else {
|
||||||
|
our_this->is_file = FALSE;
|
||||||
|
our_this->cdrom = cdrom_open(get_disk_handle( machine, diskregion ));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!our_this->cdrom)
|
||||||
|
{
|
||||||
|
logerror("GDROM: no CD found!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scsicd_delete_instance( SCSIInstance *scsiInstance )
|
||||||
|
{
|
||||||
|
SCSIGd *our_this = (SCSIGd *)SCSIThis( &SCSIClassGDROM, scsiInstance );
|
||||||
|
if (!our_this->is_file) {
|
||||||
|
if( our_this->cdrom )
|
||||||
|
{
|
||||||
|
cdrom_close( our_this->cdrom );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scsicd_get_device( SCSIInstance *scsiInstance, cdrom_file **cdrom )
|
||||||
|
{
|
||||||
|
SCSIGd *our_this = (SCSIGd *)SCSIThis( &SCSIClassGDROM, scsiInstance );
|
||||||
|
*cdrom = our_this->cdrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scsicd_set_device( SCSIInstance *scsiInstance, cdrom_file *cdrom )
|
||||||
|
{
|
||||||
|
SCSIGd *our_this = (SCSIGd *)SCSIThis( &SCSIClassGDROM, scsiInstance );
|
||||||
|
our_this->cdrom = cdrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scsigd_dispatch(int operation, void *file, INT64 intparm, void *ptrparm)
|
||||||
|
{
|
||||||
|
SCSIAllocInstanceParams *params;
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case SCSIOP_EXEC_COMMAND:
|
||||||
|
return scsicd_exec_command( (SCSIInstance *)file, (UINT8 *)ptrparm );
|
||||||
|
|
||||||
|
case SCSIOP_READ_DATA:
|
||||||
|
scsicd_read_data( (SCSIInstance *)file, (UINT8 *)ptrparm, intparm );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case SCSIOP_WRITE_DATA:
|
||||||
|
scsicd_write_data( (SCSIInstance *)file, (UINT8 *)ptrparm, intparm );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case SCSIOP_ALLOC_INSTANCE:
|
||||||
|
params = (SCSIAllocInstanceParams *)ptrparm;
|
||||||
|
SCSIBase( &SCSIClassGDROM, operation, (SCSIInstance *)file, intparm, (UINT8 *)ptrparm );
|
||||||
|
scsicd_alloc_instance( params->instance, params->diskregion );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case SCSIOP_DELETE_INSTANCE:
|
||||||
|
scsicd_delete_instance( (SCSIInstance *)file );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SCSIOP_GET_DEVICE:
|
||||||
|
scsicd_get_device( (SCSIInstance *)file, (cdrom_file **)ptrparm );
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case SCSIOP_SET_DEVICE:
|
||||||
|
scsicd_set_device( (SCSIInstance *)file, (cdrom_file *)ptrparm );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCSIBase( &SCSIClassGDROM, operation, (SCSIInstance *)file, intparm, (UINT8 *)ptrparm );
|
||||||
|
}
|
||||||
|
|
||||||
|
const SCSIClass SCSIClassGDROM =
|
||||||
|
{
|
||||||
|
&SCSIClassDevice,
|
||||||
|
scsigd_dispatch,
|
||||||
|
sizeof( SCSIGd )
|
||||||
|
};
|
17
src/mame/machine/gdrom.h
Normal file
17
src/mame/machine/gdrom.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
gdrom.h
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _GDROM_H_
|
||||||
|
#define _GDROM_H_
|
||||||
|
|
||||||
|
#include "machine/scsi.h"
|
||||||
|
|
||||||
|
// Sega GD-ROM handler
|
||||||
|
extern const SCSIClass SCSIClassGDROM;
|
||||||
|
#define SCSI_DEVICE_GDROM &SCSIClassGDROM
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
2053
src/mame/machine/segasms.c
Normal file
2053
src/mame/machine/segasms.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@ DRIVERS = $(MAMEOBJ)/drivers
|
|||||||
LAYOUT = $(MAMEOBJ)/layout
|
LAYOUT = $(MAMEOBJ)/layout
|
||||||
MACHINE = $(MAMEOBJ)/machine
|
MACHINE = $(MAMEOBJ)/machine
|
||||||
VIDEO = $(MAMEOBJ)/video
|
VIDEO = $(MAMEOBJ)/video
|
||||||
|
FORMATS = $(MAMEOBJ)/formats
|
||||||
|
|
||||||
OBJDIRS += \
|
OBJDIRS += \
|
||||||
$(AUDIO) \
|
$(AUDIO) \
|
||||||
@ -25,6 +26,7 @@ OBJDIRS += \
|
|||||||
$(LAYOUT) \
|
$(LAYOUT) \
|
||||||
$(MACHINE) \
|
$(MACHINE) \
|
||||||
$(VIDEO) \
|
$(VIDEO) \
|
||||||
|
$(FORMATS) \
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -335,6 +337,7 @@ DRVLIBS += \
|
|||||||
$(MAMEOBJ)/misc.a \
|
$(MAMEOBJ)/misc.a \
|
||||||
$(MAMEOBJ)/pinball.a \
|
$(MAMEOBJ)/pinball.a \
|
||||||
$(MAMEOBJ)/shared.a \
|
$(MAMEOBJ)/shared.a \
|
||||||
|
$(MAMEOBJ)/formats.a \
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -345,6 +348,7 @@ DRVLIBS += \
|
|||||||
|
|
||||||
$(MAMEOBJ)/shared.a: \
|
$(MAMEOBJ)/shared.a: \
|
||||||
$(MACHINE)/nmk112.o \
|
$(MACHINE)/nmk112.o \
|
||||||
|
$(MACHINE)/ctronics.o \
|
||||||
$(MACHINE)/pckeybrd.o \
|
$(MACHINE)/pckeybrd.o \
|
||||||
$(MACHINE)/pcshare.o \
|
$(MACHINE)/pcshare.o \
|
||||||
$(MACHINE)/segacrpt.o \
|
$(MACHINE)/segacrpt.o \
|
||||||
@ -352,7 +356,12 @@ $(MAMEOBJ)/shared.a: \
|
|||||||
$(MACHINE)/ticket.o \
|
$(MACHINE)/ticket.o \
|
||||||
$(VIDEO)/avgdvg.o \
|
$(VIDEO)/avgdvg.o \
|
||||||
|
|
||||||
|
#-------------------------------------------------
|
||||||
|
# file formats, mostly used for MESS software
|
||||||
|
#-------------------------------------------------
|
||||||
|
|
||||||
|
$(MAMEOBJ)/formats.a: \
|
||||||
|
$(FORMATS)/basicdsk.o \
|
||||||
|
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
# manufacturer-specific groupings for drivers
|
# manufacturer-specific groupings for drivers
|
||||||
@ -1219,6 +1228,13 @@ $(MAMEOBJ)/sega.a: \
|
|||||||
$(VIDEO)/segaic16.o \
|
$(VIDEO)/segaic16.o \
|
||||||
$(VIDEO)/sega16sp.o \
|
$(VIDEO)/sega16sp.o \
|
||||||
$(VIDEO)/segaic24.o \
|
$(VIDEO)/segaic24.o \
|
||||||
|
$(VIDEO)/smsvdp.o \
|
||||||
|
$(MACHINE)/segasms.o \
|
||||||
|
$(DRIVERS)/segasms.o \
|
||||||
|
$(DRIVERS)/sg1000.o \
|
||||||
|
$(DRIVERS)/dc.o \
|
||||||
|
$(MACHINE)/dccons.o \
|
||||||
|
$(MACHINE)/gdrom.o \
|
||||||
|
|
||||||
$(MAMEOBJ)/seibu.a: \
|
$(MAMEOBJ)/seibu.a: \
|
||||||
$(DRIVERS)/bloodbro.o $(VIDEO)/bloodbro.o \
|
$(DRIVERS)/bloodbro.o $(VIDEO)/bloodbro.o \
|
||||||
@ -1976,6 +1992,8 @@ $(DRIVERS)/segaorun.o: $(LAYOUT)/outrun.lh
|
|||||||
|
|
||||||
$(DRIVERS)/segas32.o: $(LAYOUT)/radr.lh
|
$(DRIVERS)/segas32.o: $(LAYOUT)/radr.lh
|
||||||
|
|
||||||
|
$(DRIVERS)/segasms.o: $(LAYOUT)/sms1.lh
|
||||||
|
|
||||||
$(DRIVERS)/segaybd.o: $(LAYOUT)/pdrift.lh
|
$(DRIVERS)/segaybd.o: $(LAYOUT)/pdrift.lh
|
||||||
|
|
||||||
$(DRIVERS)/snookr10.o: $(LAYOUT)/snookr10.lh
|
$(DRIVERS)/snookr10.o: $(LAYOUT)/snookr10.lh
|
||||||
|
1530
src/mame/video/smsvdp.c
Normal file
1530
src/mame/video/smsvdp.c
Normal file
File diff suppressed because it is too large
Load Diff
86
src/mame/video/smsvdp.h
Normal file
86
src/mame/video/smsvdp.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
|
||||||
|
smsvdp.h
|
||||||
|
|
||||||
|
Implementation of Sega VDP chip used in Master System and Game Gear
|
||||||
|
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __SMSVDP_H__
|
||||||
|
#define __SMSVDP_H__
|
||||||
|
|
||||||
|
#include "devcb.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
CONSTANTS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#define MODEL_315_5124 0x0001
|
||||||
|
#define MODEL_315_5246 0x0002
|
||||||
|
#define MODEL_315_5378 0x0004
|
||||||
|
|
||||||
|
#define SMS_X_PIXELS 342 /* 342 pixels */
|
||||||
|
#define NTSC_Y_PIXELS 262 /* 262 lines */
|
||||||
|
#define PAL_Y_PIXELS 313 /* 313 lines */
|
||||||
|
#define LBORDER_START (1 + 2 + 14 + 8)
|
||||||
|
#define LBORDER_X_PIXELS (0x0d) /* 13 pixels */
|
||||||
|
#define RBORDER_X_PIXELS (0x0f) /* 15 pixels */
|
||||||
|
#define TBORDER_START (3 + 13)
|
||||||
|
#define NTSC_192_TBORDER_Y_PIXELS (0x1b) /* 27 lines */
|
||||||
|
#define NTSC_192_BBORDER_Y_PIXELS (0x18) /* 24 lines */
|
||||||
|
#define NTSC_224_TBORDER_Y_PIXELS (0x0b) /* 11 lines */
|
||||||
|
#define NTSC_224_BBORDER_Y_PIXELS (0x08) /* 8 lines */
|
||||||
|
#define PAL_192_TBORDER_Y_PIXELS (0x36) /* 54 lines */
|
||||||
|
#define PAL_192_BBORDER_Y_PIXELS (0x30) /* 48 lines */
|
||||||
|
#define PAL_224_TBORDER_Y_PIXELS (0x26) /* 38 lines */
|
||||||
|
#define PAL_224_BBORDER_Y_PIXELS (0x20) /* 32 lines */
|
||||||
|
#define PAL_240_TBORDER_Y_PIXELS (0x1e) /* 30 lines */
|
||||||
|
#define PAL_240_BBORDER_Y_PIXELS (0x18) /* 24 lines */
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
typedef void (*smsvdp_int_cb)( running_machine &machine, int state );
|
||||||
|
typedef void (*smsvdp_pause_cb)( running_machine &machine );
|
||||||
|
|
||||||
|
typedef struct _smsvdp_interface smsvdp_interface;
|
||||||
|
struct _smsvdp_interface
|
||||||
|
{
|
||||||
|
UINT32 model; /* Select model/features for the emulation */
|
||||||
|
smsvdp_int_cb int_callback; /* Interrupt callback function */
|
||||||
|
smsvdp_pause_cb pause_callback; /* Pause callback function */
|
||||||
|
};
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
DEVICE CONFIGURATION MACROS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
DECLARE_LEGACY_DEVICE(SMSVDP, smsvdp);
|
||||||
|
|
||||||
|
#define MCFG_SMSVDP_ADD(_tag, _interface) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, SMSVDP, 0) \
|
||||||
|
MCFG_DEVICE_CONFIG(_interface)
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
DEVICE I/O FUNCTIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/* prototypes */
|
||||||
|
|
||||||
|
UINT32 sms_vdp_update( device_t *device, bitmap_t *bitmap, const rectangle *cliprect );
|
||||||
|
READ8_DEVICE_HANDLER( sms_vdp_vcount_r );
|
||||||
|
READ8_DEVICE_HANDLER( sms_vdp_hcount_latch_r );
|
||||||
|
WRITE8_DEVICE_HANDLER( sms_vdp_hcount_latch_w );
|
||||||
|
READ8_DEVICE_HANDLER( sms_vdp_data_r );
|
||||||
|
WRITE8_DEVICE_HANDLER( sms_vdp_data_w );
|
||||||
|
READ8_DEVICE_HANDLER( sms_vdp_ctrl_r );
|
||||||
|
WRITE8_DEVICE_HANDLER( sms_vdp_ctrl_w );
|
||||||
|
void sms_vdp_set_ggsmsmode( device_t *device, int mode );
|
||||||
|
int sms_vdp_check_brightness( device_t *device, int x, int y );
|
||||||
|
|
||||||
|
#endif /* __SMSVDP_H__ */
|
Loading…
Reference in New Issue
Block a user