Files
Hiscores_MiSTer/docs/hiscore.md
2021-10-05 18:17:40 +01:00

10 KiB

Hiscores_MiSTer

hiscore.v

hiscore.v is a generic module for MiSTer arcade cores which enables high score save/load based on the MAME hiscore plugin data format (hiscore.dat).

Created by Alan Steremberg (alanswx)

Further development by Jim Gregory (JimmyStones)

Bug fixes by Andrew Certain (tacertain)

Features

  • Reads hiscore.dat entries from MRA (defaults to ioctl index = 3)
  • Loads and saves high score data in <MRA name>.nvm dump (defaults to ioctl index = 4)
  • Configurable delay before high score load to game RAM
  • Configurable hold time during hiscore RAM read/write
  • Configurable single or double byte entry lengths
  • Configurable pause padding around game RAM access
  • Pause signal to halt CPU for during multiplex with cores already using dual-port RAM
  • Scores are extracted every time OSD is opened into temporary buffer, if changed then they are copied to saveable data and auto-save is triggered (optional)

History

0001 - 2021-03-06

  • First marked release

0002 - 2021-03-06

  • Added HS_DUMPFORMAT localparam to identify dump version (for future use).
  • Add HS_CONFIGINDEX and HS_DUMPINDEX parameters to configure ioctl_indexes

0003 - 2021-03-10

  • Added WRITE_REPEATCOUNT and WRITE_REPEATDELAY to handle tricky write situations

0004 - 2021-03-15

  • Fix ram_access assignment

0005 - 2021-03-18

  • Add configurable score table width, clean up some stupid mistakes

0006 - 2021-03-27

  • Move 'tweakable' parameters into MRA data header

0007 - 2021-04-17

  • Convert state machine to use constants
  • Add new 'pause padding' states

0008 - 2021-05-12

  • Feed back core-level pause to halt startup timer

0009 - 2021-07-31

  • Split hiscore extraction from upload (updates hiscore buffer on OSD open)

0010 - 2021-08-03

  • Add hiscore extraction buffer and change detection (ready for autosave!)

0011 - 2021-08-07

  • Optional auto-save on OSD open

0012 - 2021-08-17

  • Add variable length change detection mask

0013 - 2021-09-01

  • Output configured signal for autosave option menu masking

0014 - 2021-09-09

  • Fix turning on autosave w/o core reload (tacertain)

Implementation instructions

  • Add hiscore.v to rtl/ folder and files.qip
  • Add the following code to the main core .sv file.
// HISCORE SYSTEM
// --------------

wire [15:0]hs_address;
wire [7:0]hs_data_out;
wire [7:0]hs_data_in;
wire hs_write_enable;
wire hs_access_read;
wire hs_access_write;
wire hs_pause;
wire hs_configured;

hiscore #(
	.HS_ADDRESSWIDTH(16),
	.CFG_ADDRESSWIDTH(4)
) hi (
	.*
	.clk(clk_sys),
	.paused(pause_cpu),
	.reset(reset),
	.autosave(status[28]),
	.ram_address(hs_address),
	.data_from_ram(hs_data_out),
	.data_to_ram(hs_data_in),
	.data_from_hps(ioctl_dout),
	.data_to_hps(ioctl_din),
	.ram_write(hs_write_enable),
	.ram_intent_read(hs_access_read),
	.ram_intent_write(hs_access_write),
	.pause_cpu(hs_pause),
	.configured(hs_configured)
);

The module parameters in the example above are the bare minimum config required to customise behaviour for a core. See Module parameters for further details.

Core specific implementation

NOTE: It is advisable to implement a working pause system beforehand so the pause_cpu signal can be used to pause the core while reading/writing to game RAM to avoid instability/corruption.

Add code to link the high score signals into the relevant RAM instances.

In simple cases (see Phoenix core for an example) this will only involve converting a working RAM instance from single to dual port.

If hiscores are located in multiple RAM areas then some multiplexing will be needed to merge/split based on hs_address.

If RAM is already dual-ported then the hs_access_read/hs_access_write signals should be used to pause CPU and switch inputs to one of the ports during highscore access (see Sega System 1 for a particularly complex example!)

Module parameters

Parameters should be configured to allow the high score system to cope with all games supported by the core. Maximum dump size, maximum number of entries and largest individual entry length need to be collated for all MRAs before selecting values.

Parameter Description
HS_ADDRESSWIDTH Set to the widest memory address used by the core. The upper size of hs_address should should be set to the same -1.
HS_SCOREWIDTH Set to allow the size of the largest .nvm dump for this core (default is 8, allowing 256 bytes)
HS_CONFIGINDEX Optional override of ioctl_index used for config download (default is 3)
HS_DUMPINDEX Optional override of ioctl_index used for nvram dump download (default is 4)
CFG_ADDRESSWIDTH Set to allow for the maximum number of hiscore.dat entry lines used by the core (e.g. 4 = 16 max)
CFG_LENGTHWIDTH Set to 1 for single byte length, 2 for double

Module ports

Port Direction Description
clk in System clock. Should match the HPS IO clock input
reset in Active-high reset signal from core
paused in Active-high signal from core confirming CPU is paused
autosave in Active-high flag to enable autosave
ioctl_upload in From HPS module
ioctl_upload_req in From HPS module
ioctl_download in From HPS module
ioctl_wr in From HPS module
ioctl_addr in From HPS module
ioctl_index in From HPS module
ram_address out System RAM address for highscore read/write
data_to_ram out Data to send to system RAM (restore scores)
data_from_ram out Data from system RAM (extract scores)
data_to_hps out Data to send to HPS (save scores)
data_from_hps out Data from HPS (load scores)
ram_write out Active-high signal to write to system RAM
ram_intent_read out Active-high signal used to enable RAM read access
ram_intent_write out Active-high signal used to enable RAM write access
pause_cpu out Active-high signal used to pause CPU
configured out Active-high signal used to mask autosave menu item if game has no hiscore configuration

MRA data

To enable the high score module add the following sections to the MRA.

MRA sections

<rom index="3" md5="none">
	<part>
		00 00 FF FF 00 FF 00 02 00 02 00 01 00 FF 02 00
		00 00 90 5F 01 30 30 00 
		00 00 90 7F 01 30 30 00 
		00 00 90 9F 01 30 30 00 
		00 00 90 BF 01 30 30 00 
		00 00 90 DE 03 53 24 00 
		00 00 90 FE 03 2D 24 00 
		00 00 91 1F 01 00 00 00 
		00 00 91 3F 01 00 00 00 
		00 00 80 E2 04 00 00 00 
		00 00 81 00 96 00 FF 00 
	</part>
</rom>
<nvram index="4" size="166"/>

The <rom index="3"> section contains a header section with runtime tweakable parameters, and the entries from the MAME hiscore.dat file.

Header data
Size (bytes) Parameter Description
4 START_WAIT Number of cycles before beginning check process (usually 0)
2 CHECK_WAIT Number of cycles to wait between start/end checks (usually 256)
2 CHECK_HOLD Number of cycles to wait during start/end checks to allow addresses/multiplexers to settle (usually 2)
2 WRITE_HOLD Number of cycles to wait during write to game RAM to allow addresses/multiplexers to settle (usually 2)
2 WRITE_REPEATCOUNT Number of times to write score to game RAM - used to brute force cores that don't behave (usually 1)
2 WRITE_REPEATWAIT Number of cycles delay between subsequent write attempts
1 ACCESS_PAUSEPAD Number of cycles to pause CPU before and after RAM access attempts (usually 0)
1 CHANGEMASK Number of bytes to read after header into change detection mask
Entry data

If CFG_LENGTHWIDTH=1 then the following structure is used:

  • 4 bytes Address of ram entry (in core memory map)
  • 1 byte Length of ram entry in bytes
  • 1 byte Start value to check for at start of address range before proceeding
  • 1 byte End value to check for at end of address range before proceeding
  • 1 byte (padding)

Below is the original hiscore.dat entry for the example above (Bomb Jack)

@:maincpu,program,905f,1,30,30
@:maincpu,program,907f,1,30,30
@:maincpu,program,909f,1,30,30
@:maincpu,program,90bf,1,30,30
@:maincpu,program,90de,3,53,24
@:maincpu,program,90fe,3,2d,24
@:maincpu,program,911f,1,00,00
@:maincpu,program,913f,1,00,00
@:maincpu,program,80e2,4,00,00
@:maincpu,program,8100,96,00,ff

If CFG_LENGTHWIDTH=2 then the following structure is used:

  • 4 bytes Address of ram entry (in core memory map)
  • 2 byte Length of ram entry in bytes
  • 1 byte Start value to check for at start of address range before proceeding
  • 1 byte End value to check for at end of address range before proceeding

The size attribute in <nvram index="4" size="?"> should be the decimal total of all lengths in the entry table.

Notes

Change detection

Change detection is employed to limit unnecessary autosave events. An optional change detection mask can be provided to stop autosave being triggered by constantly changing data in the hiscore RAM areas. The final byte of the header specifies the amount of bytes to read into the mask. Only multiples of 8 are supported.

Example:

CHANGEMASK = 8 with the following 8 bytes: F0 FF FF FF FF FF FF FF

This would result in a mask with the first 4 bits as zero - this would mean any change in the first 4 bytes of the hiscore data dump are ignored.

Multiplexing

To help support cores which require multiplexing due to scores being split across multiple RAM banks, or where RAM is already dual-ported, the followinG signals can be used:

  • ram_intent_read - High when hiscore module wants to read from game RAM
  • ram_intent_write - High when hiscore module wants to write to game RAM (ram_write needs to also be high to actually write to game RAM)

Calculating delays

Delays should be calculated based on the clock passed to the hiscore module - e.g. for a 48MHz clock, a 10 second delay should be 48 * 1000 * 1000 * 10 = 31'h1C9C3800;

License

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.