====== Add a MESS Skeleton Driver ====== This article will teach you how to create a skeleton driver for MESS, the first step for your own driver. For a very basic driver, we need to add one file (the actual driver) and modify two files, so that MESS knows about your driver. ===== Creating the driver ===== As an example, we'll create a driver for the hypothetical system "MX-1290" from Epson. Create a new file in ''mess/drivers'' and name it ''mx1290.c''. Open this file and add the line #include "emu.h" Every driver includes this file. Then, add a line corresponding to the CPU needed #include "cpu/z80/z80.h" Now we basically need to add various macros to describe our system and functions that get called by the MAME/MESS core. First, we add a driver state using the C++ class class mx1290_state : public driver_device { public: mx1290_state(running_machine &machine, const driver_device_config_base &config) : driver_device(machine, config) { } }; In here you will put all devices and local variables (if any). Now, we add some functions: DRIVER_INIT_MEMBER( mx1290_state, mx1290) { } This function is called once at the beginning of the emulation. We don't need to put code in here now. Next, we'll add two functions for the video hardware: VIDEO_START_MEMBER( mx1290_state, mx1290 ) { } UINT32 mx1290_state::screen_update_mx1290(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { return 0; } Those get called at the start and when the graphics need updating. READ8_MEMBER( mx1290_state::mx1290_port1_r ) { logerror("Read from port1 @%x\n", activecpu_get_pc()); return 0xff; } WRITE8_MEMBER( mx1290_state::mx1290_port1_w ) { logerror("Write to port1 @%x: %02x\n", activecpu_get_pc(), data); } We will reference these two functions later in our address maps, which describe the memory layout of the system. static ADDRESS_MAP_START( mx1290_mem, AS_PROGRAM, 8, mx1290_state ) AM_RANGE( 0x0000, 0x0fff ) AM_ROM AM_REGION("maincpu", 0) AM_RANGE( 0x1000, 0x1fff ) AM_RAM ADDRESS_MAP_END static ADDRESS_MAP_START( mx1290_io, AS_IO, 8, mx1290_state ) ADDRESS_MAP_GLOBAL_MASK(0xff) AM_RANGE( 0x00, 0x0f ) AM_READWRITE( mx1290_port1_r, mx1290_port1_w ) ADDRESS_MAP_END We have defined two ranges now in program memory now: A ROM region, where the firmware or BIOS is located, and a RAM region. We also added a map for the I/O ports, when the system writes or reads from the address ''%%0x00%%'' to ''%%0x0f%%'' our ''READ8_MEMBER'' ''mx1290_port1_r'' and the ''WRITE8_MEMBER'' ''mx1290_port1_w'' are called. The read member expects data from us, and the write member will give us data. We also need to define some input ports, i. e. Buttons etc. that the system has. This is done using a macro: static INPUT_PORTS_START( mx1290 ) INPUT_PORTS_END Another macro finally describes the whole system: static MACHINE_DRIVER_START( mx1290, mx1290_state ) /* basic machine hardware */ MCFG_CPU_ADD_TAG("maincpu", Z80, MAIN_CLOCK / 4) MCFG_CPU_PROGRAM_MAP(mx1290_mem) MCFG_CPU_IO_MAP(mx1290_io) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(50) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) MCFG_SCREEN_SIZE(640, 480) MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) MCFG_SCREEN_UPDATE_DRIVER(mx1290_state, screen_update_mx1290) MCFG_PALETTE_ADD_BLACK_AND_WHITE("palette") MCFG_VIDEO_START_OVERRIDE(mx1290_state, mx1290) MACHINE_DRIVER_END This macro tells MESS what CPU our system uses and references our memory maps and video update functions. Note that we use a placeholder for the frequency our system runs at, this allows us to accurately describe how the clock is derived. For this to work, you need to ''#define MAIN_CLOCK 4000000'' somewhere in an include file or at the top of the driver file. In our example, the real CPU clock would then be 1 MHz. Finally, we can add some ROM loading macros. ROM_START( mx1290 ) ROM_REGION( 0x1000, "maincpu", 0 ) ROM_LOAD( "mx_v11.u22", 0x0000, 0x1000, CRC(6d84119d) SHA1(de60ead727b9317154742efd8e1206e9f9bb695b) ) ROM_END This macro creates a memory region with the size ''0x1000'' in ''maincpu'' (that we referenced in our memory map) and loads one ROM with the filename ''mx_v11.u22'' into this region at offset ''0x0000'', length ''0x1000'', CRC32 of ''6d84119d'' and SHA1 of ''de60ead727b9317154742efd8e1206e9f9bb695b''. We are almost finished now, we only need some glue macro to combine everything above now. This is doing using either the ''COMP'' or ''CONS'' macros, which are used for computers and consoles respectively. Lets say this is a computer system, so we can add: /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ COMP( 1986, mx1290, 0, 0, mx1290, mx1290, mx1290_state, mx1290, "Epson", "MX-1290", MACHINE_IS_SKELETON ) //Name// is the system name and used later when we add the actual driver to MESS. //Machine// is the ''MACHINE_DRIVER'' macro and //Input// are our input definitions. The full driver now looks like this: /* Epson MX-1290 driver by Anonymous */ #include "emu.h" #include "cpu/z80/z80.h" #define MAIN_CLOCK 4000000 /* 4 MHz */ class mx1290_state : public driver_device { public: mx1290_state(running_machine &machine, const driver_device_config_base &config) : driver_device(machine, config) { } DECLARE_DRIVER_INIT(mx1290); DECLARE_VIDEO_START(mx1290); DECLARE_READ8_MEMBER(mx1290_port1_r); DECLARE_WRITE8_MEMBER(mx1290_port1_w); UINT32 screen_update_mx1290(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); }; /* Driver initialization */ DRIVER_INIT_MEMBER( mx1290_state, mx1290) { } /* Video hardware */ VIDEO_START_MEMBER( mx1290_state, mx1290 ) { } UINT32 mx1290_state::screen_update_mx1290(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { return 0; } /* Port 1 code */ READ8_MEMBER( mx1290_state::mx1290_port1_r ) { logerror("Read from port1 @%x\n", activecpu_get_pc()); return 0xff; } WRITE8_MEMBER( mx1290_state::mx1290_port1_w ) { logerror("Write to port1 @%x: %02x\n", activecpu_get_pc(), data); } /* Address maps */ static ADDRESS_MAP_START( mx1290_mem, AS_PROGRAM, 8, mx1290_state ) AM_RANGE( 0x0000, 0x0fff ) AM_ROM AM_REGION("maincpu", 0) AM_RANGE( 0x1000, 0x1fff ) AM_RAM ADDRESS_MAP_END static ADDRESS_MAP_START(mx1290_io, AS_IO, 8, mx1290_state ) ADDRESS_MAP_GLOBAL_MASK( 0xff ) AM_RANGE( 0x00, 0x0f ) AM_READWRITE( mx1290_port1_r, mx1290_port1_w ) ADDRESS_MAP_END /* Input ports */ static INPUT_PORTS_START( mx1290 ) INPUT_PORTS_END /* Machine driver */ static MACHINE_DRIVER_START( mx1290, mx1290_state ) /* basic machine hardware */ MCFG_CPU_ADD_TAG("maincpu", Z80, MAIN_CLOCK / 4) MCFG_CPU_PROGRAM_MAP(mx1290_mem) MCFG_CPU_IO_MAP(mx1290_io) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(50) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) MCFG_SCREEN_SIZE(640, 480) MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) MCFG_SCREEN_UPDATE_DRIVER(mx1290_state, screen_update_mx1290) MCFG_PALETTE_ADD_BLACK_AND_WHITE("palette") MCFG_VIDEO_START_OVERRIDE(mx1290_state, mx1290) MACHINE_DRIVER_END /* ROM definition */ ROM_START( mx1290 ) ROM_REGION( 0x1000, "maincpu", 0 ) ROM_LOAD( "mx_v11.u22", 0x0000, 0x1000, CRC(6d84119d) SHA1(de60ead727b9317154742efd8e1206e9f9bb695b) ) ROM_END /* Driver */ /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ COMP( 1986, mx1290, 0, 0, mx1290, mx1290, mx1290_state, mx1290, "Epson", "MX-1290", MACHINE_IS_SKELETON ) ===== Adding the driver ===== Adding the driver to MESS involves editing two files, ''src/mame/mess.lst'' and ''scripts/target/mame/mess.lua''. ==== scripts/target/mame/mess.lua ==== Open the file and scroll to the section "manufacturer-specific groupings for drivers". Look for the manufacturer of your emulated system. If you can't find it, add a new section. Lets add our system from Epson, our driver is called ''mx1290.c''. Scroll down to the last manufacturer and add the following lines: createMESSProjects(_target, _subtarget, "epson") files { MAME_DIR .. "src/mess/drivers/mx1290.c", } If the manufacturer already exists, just add the second line only. ==== src/mame/mess.lst ==== Open the file and scroll to an appropriate section (consoles are listed first, computers after that, grouped by manufacturer again). Add the following line: mx1290 Note that this is the system name that you specified with the ''COMP'' or ''CONS'' macros and independent of the name of your source file. ===== Testing your new driver ===== Make a clean build and compile MESS with ''mingw32-make SUBTARGET=mess''. We enabled symbols, as it helps greatly with debugging in gdb. To run your new driver, type ''mess mx1290''. ===== Further development ===== Note that usually the ''VIDEO_START'' and ''VIDEO_UPDATE'' functions will be moved into their own file in ''mess/video/mx1290.c'' and the READ/WRITE handlers are normally found in ''mess/machine/mx1290.c''. The function prototypes for those will then be in a file called ''mess/includes/mx1290.h'' which is included into the main driver file.