====== HowTo: Adding a MESS skeleton driver ====== This HowTo 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 "driver.h" Every driver includes this file. 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 some functions: static DRIVER_INIT(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: static VIDEO_START( mx1290 ) { } static VIDEO_UPDATE( mx1290 ) { return 0; } Those get called at the start and when the graphics need updating. static READ8_HANDLER( mx1290_port1_r ) { logerror("Read from port1 @%x\n", activecpu_get_pc()); return 0xff; } static WRITE8_HANDLER( 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, ADDRESS_SPACE_PROGRAM, 8) AM_RANGE( 0x0000, 0x0fff ) AM_ROM AM_REGION(REGION_CPU1, 0) AM_RANGE( 0x1000, 0x1fff ) AM_RAM ADDRESS_MAP_END static ADDRESS_MAP_START(mx1290_mem, ADDRESS_SPACE_IO, 8) ADDRESS_MAP_FLAGS( AMEF_ABITS(8) ) 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_HANDLER'' ''mx1290_port1_r'' and the ''WRITE8_HANDLER'' ''mx1290_port1_w'' are called. The read handler expects data from us, and the write handler 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: INPUT_PORTS_START( mx1290 ) INPUT_PORTS_END Another macro finally describes the whole system: static MACHINE_DRIVER_START( mx1290 ) /* basic machine hardware */ MDRV_CPU_ADD_TAG("main", Z80, MAIN_CLOCK / 4) MDRV_CPU_PROGRAM_MAP(mx1290_mem, 0) MDRV_CPU_IO_MAP(mx1290_io, 0) /* video hardware */ MDRV_SCREEN_ADD("main", RASTER) MDRV_SCREEN_REFRESH_RATE(60) MDRV_SCREEN_VBLANK_TIME(DEFAULT_60HZ_VBLANK_DURATION) MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER) MDRV_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) MDRV_SCREEN_SIZE(640, 480) MDRV_SCREEN_VISIBLE_AREA(0, 639, 0, 479) MDRV_PALETTE_LENGTH(4) MDRV_VIDEO_START(mx1290) MDRV_VIDEO_UPDATE(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, REGION_CPU1, 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 ''REGION_CPU1'' (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 INIT CONFIG COMPANY FULLNAME FLAGS */ COMP( 1986, mx1290, 0, 0, mx1290, mx1290, NULL, NULL, "Epson", "MX-1290", GAME_NO_SOUND | GAME_NOT_WORKING) //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 "driver.h" #define MAIN_CLOCK 4000000 /* 4 MHz */ /* Driver initialization */ static DRIVER_INIT(mx1290) { } /* Video hardware */ static VIDEO_START( mx1290 ) { } static VIDEO_UPDATE( mx1290 ) { return 0; } /* Port 1 code */ static READ8_HANDLER( mx1290_port1_r ) { logerror("Read from port1 @%x\n", activecpu_get_pc()); return 0xff; } static WRITE8_HANDLER( mx1290_port1_w ) { logerror("Write to port1 @%x: %02x\n", activecpu_get_pc(), data); } /* Address maps */ static ADDRESS_MAP_START(mx1290_mem, ADDRESS_SPACE_PROGRAM, 8) AM_RANGE( 0x0000, 0x0fff ) AM_ROM AM_REGION(REGION_CPU1, 0) AM_RANGE( 0x1000, 0x1fff ) AM_RAM ADDRESS_MAP_END static ADDRESS_MAP_START(mx1290_mem, ADDRESS_SPACE_IO, 8) ADDRESS_MAP_FLAGS( AMEF_ABITS(8) ) AM_RANGE( 0x00, 0x0f ) AM_READWRITE( mx1290_port1_r, mx1290_port1_w ) ADDRESS_MAP_END /* Input ports */ INPUT_PORTS_START( mx1290 ) INPUT_PORTS_END /* Machine driver */ static MACHINE_DRIVER_START( mx1290 ) /* basic machine hardware */ MDRV_CPU_ADD_TAG("main", Z80, MAIN_CLOCK / 4) MDRV_CPU_PROGRAM_MAP(mx1290_mem, 0) MDRV_CPU_IO_MAP(mx1290_io, 0) /* video hardware */ MDRV_SCREEN_ADD("main", RASTER) MDRV_SCREEN_REFRESH_RATE(60) MDRV_SCREEN_VBLANK_TIME(DEFAULT_60HZ_VBLANK_DURATION) MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER) MDRV_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) MDRV_SCREEN_SIZE(640, 480) MDRV_SCREEN_VISIBLE_AREA(0, 639, 0, 479) MDRV_PALETTE_LENGTH(4) MDRV_VIDEO_START(mx1290) MDRV_VIDEO_UPDATE(mx1290) MACHINE_DRIVER_END /* ROM definition */ ROM_START( mx1290 ) ROM_REGION( 0x1000, REGION_CPU1, 0 ) ROM_LOAD( "mx_v11.u22", 0x0000, 0x1000, CRC(6d84119d) SHA1(de60ead727b9317154742efd8e1206e9f9bb695b) ) ROM_END /* Driver */ /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT CONFIG COMPANY FULLNAME FLAGS */ COMP( 1986, mx1290, 0, 0, mx1290, mx1290, NULL, NULL, "Epson", "MX-1290", GAME_NO_SOUND | GAME_NOT_WORKING) ===== Adding the driver ===== Adding the driver to MESS involves editing two files, ''mess/mess.mak'' and ''mess/messdriv.c''. ==== mess.mak ==== 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: $(MESSOBJ)/epson.a: \ $(MESS_DRIVERS)/mx1290.o If the manufacturer already exists, just add the second line only. ==== messdriv.c ==== Open the file and scroll to an appropriate section (consoles are listed first, computers after that, grouped by manufacturer again). Add the following line: DRIVER(mx1290) Note that this is the system name that you specifid with the ''COMP'' or ''CONS'' macros and independent of the name of your source file. ===== Testing your new driver ===== Make a clean build (''make -f makefile.mes DEBUG=1 clean'') and compile MESS with ''make -f makefile.mes DEBUG=1''. We enabled the debugger, because you can't really develop a driver without it. To run your new driver, type ''messd 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.