Specs:
|
ChibiAkumas Tutorials
Screen layers...Where's my Tilemap!
Most Console systems will have 2
types of graphics layer... a 'Tile Map' which is a grid of
predefined 'tiles'... these are usually 8x8 in size... on a 16 bit
system, usually multiple layers of tilemaps exist to define
paralax... On top of this we would add sprites to make our player character and other such things... But the NeoGeo HAS NO TILEMAP! |
![]() |
So how does the NeoGeo work with no
Tilemap? Well... sprites on the NeoGeo are 16 pixels wide, and can be up to 512 pixels tall - but they can be combined!... and because the NeoGeo is capable of a whopping 380 tiles, we can combine 20 of them together to 'simulate' a tilemap!... this is how background graphics are drawn on the Neogeo! On top of this are our 'normal' sprites - enemies, player characters and such... There is one final layer, the 'Fix Layer'... this is made up of 16 color 8x8 tiles, in a simple grid... it's designed to do onscreen text and the like... but I used it in GrimeZ80 to do all the game graphics... so if your needs are simple, and you want 8x8 block graphics, it can be used for the job... but don't worry, we'll learn about sprites later! |
![]() |
The Neogeo screen has a resolution of 320x224, and each tile is
8x8 - giving an effective screen size of 40x28... The actual tilemap is 40x32... the top and bottom two lines are not show (Shown in red on the chart to the right) However, because of the CRT layout - it is likely that the left and rightmost 1 column will not be visible (Shown in orange to the right)... this gives a visible screen of 38x28 The Fix Layer is positioned in VRAM at &7000 (each position contains 1 word / 2 bytes)- each Tile is defined by 16 bits in the following format:
Where P is the Palette number, and T is the Tile number The fixmap appears at $7000 in Vram... tile data for the Fixmap are in ROM Tiles in memory are ordered in COLUMNS... so in memory (X,Y) co-ordinate (0,1) comes after (0,0) ($7000)... and (1,0) comes 32 words ($7020) after (0,0) For example - to set tile (0,2) to tile 256 in palette 1 (note this is in the "May be offscreen" area, but should appear on an emulator) Move.W #$7002,d1 ;Address - Tile 2 Move.W #$1100,d0 ;PTTT - Palette and tile Move.w d1,$3C0000 ;set address in vdp Move.w d0,$3C0002 ;set tile data in vdp |
![]() |
||||||||||||||||||||||||||||||||||
Fix Layer tiles are in an odd format! Each tile is 8x8 at 4bpp ... so 32 bytes per tile... The two nibbles of each byte represent 2 pixels , but they are BACKWARDS... so the 1st (High) nibble is the 2nd pixel color, and the 2nd nibble (Low) is the 1st pixel color The bytes are stored in Columns, then rows... and the columns are out of order too! .. Visible pixels ABCDEFGH are stored in Ram in order FEHGBADC The 8 bytes of each column are in normal top->bottom format... so at least that:s something! |
![]() |
||||||||||||||||||||||||||||||||||
My AkuSprite editor (used in these tutorials) has support to export images in the correct "Fix" format for the NeoGeo | ![]() |
Each address contains a WORD... Write a word to $3C0000 to select VRAM Address Write a word to $3C0002 to Send data to VRAM |
|
MAME NeoGeo Rom XMLs
To run a custom game on MAME, we need to create a hash file -
usually called 'neogeo.xml' This defines how the various binary files that make up a game are attached to the system... multiple files can be combined for a single purpose - the 'Offset'
|
![]() |
|||||||||||||||
There are various parameters for 'rom'
files that must correct for MAME to be happy, otherwise you will get
the error "One or more ROMs/CHDs for this machine are incorrect. The
machine may not run correctly"... To fix this you must ensure the following parameters are correct:
|
||||||||||||||||
If you want to calculate the hashes, you can do so with my 'MakeNeoGeoHash'
program - you need to provide it a template (shown to the right) -
it will calculate the size,crc and sha1 of each rom, and write out a
new xml which mame will be happy with! MakeNeoGeoHash is included in my 68000 development tools package, with scripts to use it automatically with my tutorials samples |
![]() |
Memory Map
Function | Port | Details |
$000000 | Vector Table | |
$000100 | Cart Header and User Vectors | |
$000400 | 1st bank of Rom | |
$100000 | Ram (64k) | |
BIOS_SYSTEM_MODE | $10FD80 | (byte) VBL for $00=system,$80=game |
BIOS_SYSRET_STATUS | $10FD81 | (byte) Stores function code for SYSTEM_RETURN |
BIOS_MVS_FLAG | $10FD82 | (byte) 0=Home/AES,1=MVS |
BIOS_COUNTRY_CODE | $10FD83 | (byte) 0=Japan,1=USA,2=Europe/Export (xxx:Korea?) |
BIOS_GAME_DIP | $10FD84 | $10FD84-$10FD93 (all bytes) |
BIOS_GAMEDIP_TIME1 | $10FD84 | (word) timed option 1 (minutes and seconds in BCD) |
BIOS_GAMEDIP_TIME2 | $10FD86 | (word) timed option 2 (minutes and seconds in BCD) |
BIOS_GAMEDIP_COUNT1 | $10FD88 | (byte) counter option 1 (1-99; value set here is default) |
BIOS_GAMEDIP_COUNT2 | $10FD89 | (byte) counter option 2 (WITHOUT, INFINITE, 1-99 TIMES) |
BIOS_GAMEDIP_01 | $10FD8A | (byte) Game soft dip 01 |
BIOS_GAMEDIP_02 | $10FD8B | (byte) Game soft dip 02 |
BIOS_GAMEDIP_03 | $10FD8C | (byte) Game soft dip 03 |
BIOS_GAMEDIP_04 | $10FD8D | (byte) Game soft dip 04 |
BIOS_GAMEDIP_05 | $10FD8E | (byte) Game soft dip 05 |
BIOS_GAMEDIP_06 | $10FD8F | (byte) Game soft dip 06 |
BIOS_GAMEDIP_07 | $10FD90 | (byte) Game soft dip 07 |
BIOS_GAMEDIP_08 | $10FD91 | (byte) Game soft dip 08 |
BIOS_GAMEDIP_09 | $10FD92 | (byte) Game soft dip 09 |
BIOS_GAMEDIP_10 | $10FD93 | (byte) Game soft dip 10 |
BIOS_P1STATUS | $10FD94 | (byte) Controller 1 status |
BIOS_P1PREVIOUS | $10FD95 | (byte) Inputs from last frame |
BIOS_P1CURRENT | $10FD96 | (byte) Inputs from current frame |
BIOS_P1CHANGE | $10FD97 | (byte) Active-edge input |
BIOS_P1REPEAT | $10FD98 | (byte) Auto-repeat flag |
BIOS_P1TIMER | $10FD99 | (byte) Input repeat timer |
BIOS_P2STATUS | $10FD9A | (byte) Controller 2 status |
BIOS_P2PREVIOUS | $10FD9B | (byte) Inputs from last frame |
BIOS_P2CURRENT | $10FD9C | (byte) Inputs from current frame |
BIOS_P2CHANGE | $10FD9D | (byte) Active-edge input |
BIOS_P2REPEAT | $10FD9E | (byte) Auto-repeat flag |
BIOS_P2TIMER | $10FD9F | (byte) Input repeat timer |
BIOS_P3STATUS | $10FDA0 | (byte) Controller 3 status |
BIOS_P3PREVIOUS | $10FDA1 | (byte) Inputs from last frame |
BIOS_P3CURRENT | $10FDA2 | (byte) Inputs from current frame |
BIOS_P3CHANGE | $10FDA3 | (byte) Active-edge input |
BIOS_P3REPEAT | $10FDA4 | (byte) Auto-repeat flag |
BIOS_P3TIMER | $10FDA5 | (byte) Input repeat timer |
BIOS_P4STATUS | $10FDA6 | (byte) Controller 4 status |
BIOS_P4PREVIOUS | $10FDA7 | (byte) Inputs from last frame |
BIOS_P4CURRENT | $10FDA8 | (byte) Inputs from current frame |
BIOS_P4CHANGE | $10FDA9 | (byte) Active-edge input |
BIOS_P4REPEAT | $10FDAA | (byte) Auto-repeat flag |
BIOS_P4TIMER | $10FDAB | (byte) Input repeat timer |
BIOS_STATCURNT | $10FDAC | (byte) Start and Select from current frame (Select bits = 0 on MVS) |
BIOS_STATCHANGE | $10FDAD | (byte) Start and Select active-edge input (Select bits = 0 on MVS) |
BIOS_USER_REQUEST | $10FDAE | (byte) Command for USER ($122) |
BIOS_USER_MODE | $10FDAF | (byte) Current game status (0:init/boot, 1:title/demo, 2:game) |
BIOS_CREDIT1_DEC | $10FDB0 | (byte) Credit decrement Player 1 (BCD) |
BIOS_CREDIT2_DEC | $10FDB1 | (byte) Credit decrement Player 2 (BCD) |
BIOS_CREDIT3_DEC | $10FDB2 | (byte) Credit decrement Player 3 (BCD) |
BIOS_CREDIT4_DEC | $10FDB3 | (byte) Credit decrement Player 4 (BCD) |
BIOS_START_FLAG | $10FDB4 | (byte) Player(s) starting the game on PLAYER_START call |
BIOS_PLAYER1_MODE | $10FDB6 | (byte) Player 1 Status (a.k.a. "BIOS_PLAYER_MOD1") |
BIOS_PLAYER2_MODE | $10FDB7 | (byte) Player 2 Status |
BIOS_PLAYER3_MODE | $10FDB8 | (byte) Player 3 Status |
BIOS_PLAYER4_MODE | $10FDB9 | (byte) Player 4 Status |
;??? | $10FDBA | (long) |
BIOS_MESS_POINT | $10FDBE | (long) pointer to MESS_OUT buffer |
BIOS_MESS_BUSY | $10FDC2 | (word) 0=run MESS_OUT, 1=skip MESS_OUT |
BIOS_CARD_COMMAND | $10FDC4 | (byte) Command to execute |
BIOS_CARD_MODE | $10FDC5 | (byte) "command error job mode" |
BIOS_CARD_ANSWER | $10FDC6 | (byte) answer code for command; set by BIOS |
;BIOS_?????????? | $10FDC7 | (byte) ? |
BIOS_CARD_START | $10FDC8 | (long) Pointer to start of card data |
BIOS_CARD_SIZE | $10FDCC | (word) Size of data |
BIOS_CARD_FCB | $10FDCE | (word) Game NGH number |
BIOS_CARD_SUB | $10FDD0 | (byte/word) Game sub number (0-15) |
BIOS_DATE_TIME | $10FDD2 | DATE_TIME struct |
BIOS_YEAR | $10FDD2 | (byte) Current Year (starts at ??) |
BIOS_MONTH | $10FDD3 | (byte) Current Month |
BIOS_DAY | $10FDD4 | (byte) Current Day |
BIOS_WEEKDAY | $10FDD5 | (byte) Current Weekday (0:Sunday, 1:Monday, ... 6:Saturday) |
BIOS_HOUR | $10FDD6 | (byte) Current Hour (24 hour format) |
BIOS_MINUTE | $10FDD7 | (byte) Current Minute |
BIOS_SECOND | $10FDD8 | (byte) Current Second |
;BIOS_?????????? | $10FDD9 | (byte) ? |
BIOS_SELECT_TIMER | $10FDDA | (word) (a.k.a. "compulsion timer") |
BIOS_START_TEST | $10FDDC | (word) ?? (might be used differently on CD systems) |
BIOS_COIN_LEVER | $10FDDE | (word) ?? |
BIOS_WORK1 | $10FE00 | |
BIOS_CREDIT1 | $10FE00 | (byte) |
BIOS_CREDIT2 | $10FE01 | (byte) |
BIOS_CREDIT3 | $10FE02 | (byte) |
BIOS_CREDIT4 | $10FE03 | (byte) |
BIOS_SWITCH_STORE | $10FE04 | (long) |
BIOS_UNDER_CREDIT1 | $10FE08 | (byte) |
BIOS_UNDER_CREDIT2 | $10FE09 | (byte) |
BIOS_UNDER_CREDIT3 | $10FE0A | (byte) |
BIOS_UNDER_CREDIT4 | $10FE0B | (byte) |
BIOS_UNDER_CREDIT5 | $10FE0C | (byte) |
BIOS_UNDER_CREDIT6 | $10FE0D | (byte) |
BIOS_UNDER_CREDIT7 | $10FE0E | (byte) |
BIOS_UNDER_CREDIT8 | $10FE0F | (byte) |
BIOS_COIN1_NOR_CRED | $10FE10 | (word) |
BIOS_COIN2_NOR_CRED | $10FE12 | (word) |
BIOS_COIN1_CONT_CRED | $10FE14 | (word) |
BIOS_COIN2_CONT_CRED | $10FE16 | (word) |
BIOS_SELECT_FREE | $10FE18 | (byte) |
;??? | $10FE19 | (byte) |
BIOS_NON_LIMIT | $10FE1A | (byte/word?) |
BIOS_DEMO_SOUND | $10FE1C | (byte) |
BIOS_INIT_MARK | $10FE1E | (word) |
BIOS_SR_STORE | $10FE20 | (word) |
BIOS_VERSION_BASE | $10FE22 | (long) |
BIOS_GD_STORE | $10FE26 | (byte) 32 bytes |
BIOS_WORK2 | $10FE80 | |
BIOS_DEVMODE | $10FE80 | (byte) nonzero value = enabled |
BIOS_FRAMECOUNT | $10FE88 | (long) (a.k.a. "SYS_INT1_TIMER") |
BIOS_SYS_STOPPER | $10FE8C | (byte) "system stopper", actually BIOS VBlank flag |
BIOS_Z80_BANK | $10FE8D | (byte) |
BIOS_SYSTEM_MODE2 | $10FE8E | (word) |
BIOS_CARD_TIMER | $10FE90 | (word) |
BIOS_CARD_START2 | $10FE92 | (long) |
BIOS_CARD_SIZE2 | $10FE96 | (word) |
BIOS_CARD_FCB2 | $10FE98 | (word) |
BIOS_CARD_SUB2 | $10FE9A | (word) |
BIOS_DIR_BUFFER | $10FE9C | (byte) 20 bytes |
BIOS_DIR_NUMBER | $10FEB0 | (word) 5 words |
BIOS_FIX_STORE_FLAG | $10FEBA | (byte) |
BIOS_LED_OFF | $10FEBB | (byte) |
BIOS_IN_TEST | $10FEBC | (byte) |
BIOS_INST_MODE | $10FEBD | (byte) |
BIOS_START_BUSY | $10FEBE | (byte) |
BIOS_BACKUP_MODE | $10FEBF | (byte) (a.k.a. "BIOS_BRAM_USED") |
BIOS_INST_RAD | $10FEC0 | (long) |
BIOS_INST_RCO | $10FEC4 | (byte) |
BIOS_TITLE_MODE | $10FEC5 | (byte) When set to 1, stops BIOS from calling command 3 twice after Game Over if credits are in the system. -paraphrasing Razoola, NeoGeo Development Wiki |
BIOS_MESS_STACK | $10FEC6 | (long) 5 longs; first is the pointer to the data. |
BIOS_STATCURNT_RAW | $10FEDC | (byte) raw version of BIOS_STATCURNT (includes Select on MVS) (a.k.a. "INPUT_SS") |
BIOS_STATCHANGE_RAW | $10FEDD | (byte) raw version of BIOS_STATCHANGE (includes Select on MVS) |
BIOS_INPUT_TT1 | $10FEDE | (byte) |
BIOS_INPUT_TT2 | $10FEDF | (byte) |
BIOS_KYOUSEI_MODE | $10FEE0 | (byte) a.k.a. "KYOUSEI_MODE" (Game start compulsion?) |
BIOS_SYS_STOP | $10FEE1 | (byte) (a.k.a. "BIOS_FRAME_SKIP","SYS_STOP") |
BIOS_CS_REMAIN | $10FEE2 | (byte) (a.k.a. "CS_REMAIN") |
BIOS_INT_OFF | $10FEE3 | (byte) (a.k.a. "BIOS_INT1_SKIP", "INT_OFF") |
BIOS_INT1_TIMER2 | $10FEE4 | (word?) (a.k.a. "BIOS_INT1_FRAME_COUNTER", "INT1_TIMER2") |
BIOS_P5STATUS | $10FEE8 | (byte) Input 5 status |
BIOS_P5PREVIOUS | $10FEE9 | (byte) Inputs from last frame |
BIOS_P5CURRENT | $10FEEA | (byte) Inputs from current frame |
BIOS_P5CHANGE | $10FEEB | (byte) Active-edge input |
BIOS_P5REPEAT | $10FEEC | (byte) Auto-repeat flag |
BIOS_P5TIMER | $10FEED | (byte) Input repeat timer |
BIOS_P6STATUS | $10FEEE | (byte) Input 6 status |
BIOS_P6PREVIOUS | $10FEEF | (byte) Inputs from last frame |
BIOS_P6CURRENT | $10FEF0 | (byte) Inputs from current frame |
BIOS_P6CHANGE | $10FEF1 | (byte) Active-edge input |
BIOS_P6REPEAT | $10FEF2 | (byte) Auto-repeat flag |
BIOS_P6TIMER | $10FEF3 | (byte) Input repeat timer |
BIOS_MESS_BUFFER | $10FF00 | 100 byte buffer |
BIOS_4P_REQUESTED | $10FEF8 | (bios) local copy of hard dip 2 (0=off; 2=on) |
BIOS_4P_MODE | $10FEFA | (bios) Main 4P flag (0=regular; $FF=4P ok) |
BIOS_4P_PLUGGED | $10FEFB | (bios) Is NEO-FTC1B board present? (0=not found; $FF=plugged in) |
BIOS_CD_UPZONE | $10FEDA | (byte) zone (0=PRG/TXT, 1=FIX, 2=SPR, 3=Z80, 4=PCM, 5=PAT, 6=???, 7=OBJ, 8=A**) |
BIOS_CD_UPBANK | $10FEDB | (byte) bank |
BIOS_CD_UPDEST | $10FEF4 | (long) destination address |
BIOS_CD_UPSRC | $10FEF8 | (long) source address |
BIOS_CD_UPSIZE | $10FEFC | (long) size |
$110000 | Ram Mirror | |
$200000 | 2nd bank of Rom | |
REG_P1CNT | $300000 | Player 1 Controls (DCBArldu)/Trackball data [active low] |
REG_DIPSW | $300001 | Read Hardware DIPs [active low], Kick watchdog (a.k.a. "WATCH_DOG") |
REG_SOUND | $320000 | (Byte) Send command to Z80 (Z80 port &00), Read Z80 reply (Z80 port &0C) |
REG_STATUS_A | $320001 | uPD4990 bits, Coin switches [switches active low] |
REG_P2CNT | $340000 | Player 2 Controls (DCBArldu) [active low] |
REG_STATUS_B | $380000 | Aux inputs (Start/Select, Memory Card...) [active low] |
REG_POUTPUT | $380001 | Joypad port outputs |
CARD_BANK | $380011 | Memory Card bank select |
REG_SLOT | $380021 | Slot Number (MVS)/REG_POUTPUT mirror (home) |
REG_LEDLATCHES | $380031 | LED Latches (latched on 1->0/falling edge transition) |
REG_LEDDATA | $380041 | LED Output Data |
REG_RTCCTRL | $380051 | Strobe/Clock/DIN for uPD4990 |
REG_COIN1COUNT_HI | $380061 | Chute 1 coin counter -> High |
REG_COIN2COUNT_HI | $380063 | Chute 2 coin counter -> High |
REG_COIN1LOCK_HI | $380065 | Chute 1 coin lockout -> High |
REG_COIN2LOCK_HI | $380067 | Chute 2 coin lockout -> High |
REG_RTCWRITE | $3800D1 | Write to RTC |
REG_COIN1COUNT_LO | $3800E1 | Chute 1 coin counter -> Low |
REG_COIN2COUNT_LO | $3800E3 | Chute 2 coin counter -> Low |
REG_COIN1LOCK_LO | $3800E5 | Chute 1 coin lockout -> Low |
REG_COIN2LOCK_LO | $3800E7 | Chute 2 coin lockout -> Low |
SYS_NOSHADOW | $3A0001 | Normal output (a.k.a. "SHADOW_OFF","REG_NOSHADOW") |
SYS_BIOSVEC | $3A0003 | Use BIOS vectors (a.k.a. "SYSTEM_ROM","REG_SWPBIOS") |
CARD_ENABLE_1 | $3A0005 | Enable card writes (w/CARD_ENABLE_2). (a.k.a. "REG_CRDUNLOCK1","IC_WRITE_EI1") |
CARD_DISABLE_1 | $3A0007 | Disable card writes (w/CARD_DISABLE_2). (a.k.a. "REG_CRDLOCK1","IC_WRITE_DI1") |
CARD_SELECT | $3A0009 | Enable card register select |
SYS_BIOSFIX | $3A000B | Use BIOS Fix tiles |
SYS_MVSBRAM_LOCK | $3A000D | Write-protect MVS-only Backup RAM |
PALETTE_BANK1 | $3A000F | (byte) Palette bank 1 register |
SYS_SHADOW | $3A0011 | Darkened output (a.k.a. "SHADOW_ON","REG_SHADOW") |
SYS_CARTVEC | $3A0013 | Use Cart vectors (a.k.a. "USER_ROM","REG_SWPROM") |
CARD_DISABLE_2 | $3A0015 | Disable card writes (w/CARD_DISABLE_1). (a.k.a. "REG_CRDLOCK2","IC_WRITE_DI2") |
CARD_ENABLE_2 | $3A0017 | Enable card writes (w/CARD_ENABLE_1). (a.k.a. "REG_CRDUNLOCK2","IC_WRITE_EI2") |
CARD_NORMAL | $3A0019 | Disable card register select |
SYS_CARTFIX | $3A001B | Use Cart Fix tiles |
SYS_MVSBRAM_UNLOCK | $3A001D | Unprotect MVS-only Backup-RAM |
PALETTE_BANK0 | $3A001F | (byte) Palette bank 0 register |
LSPC_ADDR | $3C0000 | VRAM Address |
LSPC_DATA | $3C0002 | VRAM Data |
LSPC_INCR | $3C0004 | VRAM
Increment (1=on 0=off) |
LSPC_MODE | $3C0006 | LSPC Mode |
LSPC_TIMER_HI | $3C0008 | Timer MSB |
LSPC_TIMER_LO | $3C000A | Timer LSB |
LSPC_IRQ_ACK | $3C000C | Interrupt acknowlege |
LSPC_TIMER_STOP | $3C000E | Stop timer for 32 lines in PAL mode? (LSPC2 only, apparently) |
PALETTES | $400000 | $400000-$401FFF (2 bytes per color - 16 colors - 256 palettes) |
PALETTE_REFERENCE | $400000 | Reference Color (must be $8000) |
PALETTE_BACKDROP | $401FFE | Backdrop Color |
MEMCARD_DATA | $800000 | Memory Card Data (a.k.a. "IC_MEMORY") |
BIOSROM | $C00000 | BIOS ROM begins at $C00000 |
SYSTEM_RESET | $C00402 | |
SYSTEM_INT1 | $C00438 | System VBlank |
SYSTEM_INT2 | $C0043E | System Int2 (Cart systems only) |
SYSTEM_RETURN | $C00444 | Returns from the game to the BIOS |
SYSTEM_IO | $C0044A | Reads player inputs (and cabinet if MVS) |
CREDIT_CHECK | $C00450 | Check a player's number of credits |
CREDIT_DOWN | $C00456 | Deduct credits |
READ_CALENDAR | $C0045C | Read values from uPD4990 chip (MVS-only) |
SETUP_CALENDAR | $C00462 | Sets up uPD4990 chip (MVS-only) |
SYS_CARD | $C00468 | Memory Card commands |
SYS_CARD_ERROR | $C0046E | Handle card errors and display message |
SYSTEM_HOW_TO_PLAY | $C00474 | display old-style how to play. uncomment if you want to use it. |
CALC_CHECKSUM | $C0047A | calc a checksum and loop forever |
FIX_CLEAR | $C004C2 | Clear Fix layer |
LSP_1st | $C004C8 | Clear SCB2-4, first SCB1 tilemap |
MESS_OUT | $C004CE | Fix layer message output |
CONTROLLER_SETUP | $C004D4 | Initializes controllers |
BIOSF_HBLANK | $C004DA | HBlank handler (replaces SYSTEM_INT2) |
BIOSF_UPLOAD | $C00546 | Upload data to DRAM |
$C0054C ? (CDZ) | ||
BIOSF_LOADFILE | $C00552 | Load file from CD, with animation |
$C00558 ? (CDZ) | ||
BIOSF_CDPLAYER | $C0055E | Reset to CD Player |
BIOSF_LOADFILEX | $C00564 | Load file from CD, no animation |
BIOSF_CDDACMD | $C0056A | Issue CDDA command |
BIOSF_VIDEOEN | $C00570 | Enable/Disable video layers |
UPLOAD | $E00000 | CD Upload Zone ($E00000-$EFFFFF) |
$F00000 | Registers |
F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
D | R0 | G0 | B0 | R4 | R3 | R2 | R1 | G4 | G3 | G2 | G1 | B4 | B3 | B2 | B1 |
The FM chip uses 2 pairs of ports, $04 and $06 select the address of the
register we want to change, $05 and $07 write the new data, but after each
write, we need to check if the FM chip is busy,
To check if the FM chip is busy, read in from port $04, and check bit 7 -
it will return 0 when not busy.
Address | Function | Port $04 / $05 |
Port $06 / $07 |
Bits | Details |
$21 | LSI Test Data | ALL | TTTTTTTT | T=Test | |
$22 | LFO Frequency Control | ALL | ----EFFF | E=enable F=Frequency | |
$24 | Timer A H | ALL | HHHHHHHH | Timer A top 8 bits | |
$25 | Timer A L | ALL | ------LL | Timer A bottom 2 bits | |
$26 | Timer B | ALL | TTTTTTTT | T=Timer B | |
$27 | Timer Control, 2ch mode | ALL | MMRREELL | M=Multi Mode, R=Reset timers, E=enable, L=Load | |
$28 | Individual Operator Key On/Off | ALL | - | OOOO-GCC | O=operator / G=Channel group / C=Channel (0=chn 1) |
$31 | Multiplier & Detune | Ch1 Op1 | Ch3 Op1 | -DDDMMMM | D=Detune / M=Multiplier |
$32 | Multiplier & Detune | Ch2 Op1 | Ch4 Op1 | -DDDMMMM | D=Detune / M=Multiplier |
$35 | Multiplier & Detune | Ch1 Op2 | Ch3 Op2 | -DDDMMMM | D=Detune / M=Multiplier |
$36 | Multiplier & Detune | Ch2 Op2 | Ch4 Op2 | -DDDMMMM | D=Detune / M=Multiplier |
$39 | Multiplier & Detune | Ch1 Op3 | Ch3 Op3 | -DDDMMMM | D=Detune / M=Multiplier |
$3A | Multiplier & Detune | Ch2 Op3 | Ch4 Op3 | -DDDMMMM | D=Detune / M=Multiplier |
$3D | Multiplier & Detune | Ch1 Op4 | Ch3 Op4 | -DDDMMMM | D=Detune / M=Multiplier |
$3E | Multiplier & Detune | Ch2 Op4 | Ch4 Op4 | -DDDMMMM | D=Detune / M=Multiplier |
$41 | Total Level | Ch1 Op1 | Ch3 Op1 | -TTTTTTT | T=Total Level (0=max) |
$42 | Total Level | Ch2 Op1 | Ch4 Op1 | -TTTTTTT | T=Total Level (0=max) |
$45 | Total Level | Ch1 Op2 | Ch3 Op2 | -TTTTTTT | T=Total Level (0=max) |
$46 | Total Level | Ch2 Op2 | Ch4 Op2 | -TTTTTTT | T=Total Level (0=max) |
$49 | Total Level | Ch1 Op3 | Ch3 Op3 | -TTTTTTT | T=Total Level (0=max) |
$4A | Total Level | Ch2 Op3 | Ch4 Op3 | -TTTTTTT | T=Total Level (0=max) |
$4D | Total Level | Ch1 Op4 | Ch3 Op4 | -TTTTTTT | T=Total Level (0=max) |
$4E | Total Level | Ch2 Op4 | Ch4 Op4 | -TTTTTTT | T=Total Level (0=max) |
$51 | Key Scaling & Attack Rate | Ch1 Op1 | Ch3 Op1 | KK-RRRRR | K=Keyscaling / R=attackrate |
$52 | Key Scaling & Attack Rate | Ch2 Op1 | Ch4 Op1 | KK-RRRRR | K=Keyscaling / R=attackrate |
$55 | Key Scaling & Attack Rate | Ch1 Op2 | Ch3 Op2 | KK-RRRRR | K=Keyscaling / R=attackrate |
$56 | Key Scaling & Attack Rate | Ch2 Op2 | Ch4 Op2 | KK-RRRRR | K=Keyscaling / R=attackrate |
$59 | Key Scaling & Attack Rate | Ch1 Op3 | Ch3 Op3 | KK-RRRRR | K=Keyscaling / R=attackrate |
$5A | Key Scaling & Attack Rate | Ch2 Op3 | Ch4 Op3 | KK-RRRRR | K=Keyscaling / R=attackrate |
$5D | Key Scaling & Attack Rate | Ch1 Op4 | Ch3 Op4 | KK-RRRRR | K=Keyscaling / R=attackrate |
$5E | Key Scaling & Attack Rate | Ch2 Op4 | Ch4 Op4 | KK-RRRRR | K=Keyscaling / R=attackrate |
$61 | Decay Rate & AM Enable | Ch1 Op1 | Ch3 Op1 | A--DDDDD | A=Amplitude Mod Enable / D= Decay rate |
$62 | Decay Rate & AM Enable | Ch2 Op1 | Ch4 Op1 | A--DDDDD | A=Amplitude Mod Enable / D= Decay rate |
$65 | Decay Rate & AM Enable | Ch1 Op2 | Ch3 Op2 | A--DDDDD | A=Amplitude Mod Enable / D= Decay rate |
$66 | Decay Rate & AM Enable | Ch2 Op2 | Ch4 Op2 | A--DDDDD | A=Amplitude Mod Enable / D= Decay rate |
$69 | Decay Rate & AM Enable | Ch1 Op3 | Ch3 Op3 | A--DDDDD | A=Amplitude Mod Enable / D= Decay rate |
$6A | Decay Rate & AM Enable | Ch2 Op3 | Ch4 Op3 | A--DDDDD | A=Amplitude Mod Enable / D= Decay rate |
$6D | Decay Rate & AM Enable | Ch1 Op4 | Ch3 Op4 | A--DDDDD | A=Amplitude Mod Enable / D= Decay rate |
$6E | Decay Rate & AM Enable | Ch2 Op4 | Ch4 Op4 | A--DDDDD | A=Amplitude Mod Enable / D= Decay rate |
$71 | Sustain Rate | Ch1 Op1 | Ch3 Op1 | ---SSSSS | S=Sustain Rate |
$72 | Sustain Rate | Ch2 Op1 | Ch4 Op1 | ---SSSSS | S=Sustain Rate |
$75 | Sustain Rate | Ch1 Op2 | Ch3 Op2 | ---SSSSS | S=Sustain Rate |
$76 | Sustain Rate | Ch2 Op2 | Ch4 Op2 | ---SSSSS | S=Sustain Rate |
$79 | Sustain Rate | Ch1 Op3 | Ch3 Op3 | ---SSSSS | S=Sustain Rate |
$7A | Sustain Rate | Ch2 Op3 | Ch4 Op3 | ---SSSSS | S=Sustain Rate |
$7D | Sustain Rate | Ch1 Op4 | Ch3 Op4 | ---SSSSS | S=Sustain Rate |
$7E | Sustain Rate | Ch2 Op4 | Ch4 Op4 | ---SSSSS | S=Sustain Rate |
$81 | Release Rate & Sustain Level | Ch1 Op1 | Ch3 Op1 | SSSSRRRR | S=Sustain Level / Release Rate |
$82 | Release Rate & Sustain Level | Ch2 Op1 | Ch4 Op1 | SSSSRRRR | S=Sustain Level / Release Rate |
$85 | Release Rate & Sustain Level | Ch1 Op2 | Ch3 Op2 | SSSSRRRR | S=Sustain Level / Release Rate |
$86 | Release Rate & Sustain Level | Ch2 Op2 | Ch4 Op2 | SSSSRRRR | S=Sustain Level / Release Rate |
$89 | Release Rate & Sustain Level | Ch1 Op3 | Ch3 Op3 | SSSSRRRR | S=Sustain Level / Release Rate |
$8A | Release Rate & Sustain Level | Ch2 Op3 | Ch4 Op3 | SSSSRRRR | S=Sustain Level / Release Rate |
$8D | Release Rate & Sustain Level | Ch1 Op4 | Ch3 Op4 | SSSSRRRR | S=Sustain Level / Release Rate |
$8E | Release Rate & Sustain Level | Ch2 Op4 | Ch4 Op4 | SSSSRRRR | S=Sustain Level / Release Rate |
$91 | SSG-Envelope Generator | Ch1 Op1 | Ch3 Op1 | ----EEEE | E=Envelope Gen |
$92 | SSG-Envelope Generator | Ch2 Op1 | Ch4 Op1 | ----EEEE | E=Envelope Gen |
$95 | SSG-Envelope Generator | Ch1 Op2 | Ch3 Op2 | ----EEEE | E=Envelope Gen |
$96 | SSG-Envelope Generator | Ch2 Op2 | Ch4 Op2 | ----EEEE | E=Envelope Gen |
$99 | SSG-Envelope Generator | Ch1 Op3 | Ch3 Op3 | ----EEEE | E=Envelope Gen |
$9A | SSG-Envelope Generator | Ch2 Op3 | Ch4 Op3 | ----EEEE | E=Envelope Gen |
$9D | SSG-Envelope Generator | Ch1 Op4 | Ch3 Op4 | ----EEEE | E=Envelope Gen |
$9E | SSG-Envelope Generator | Ch2 Op4 | Ch4 Op4 | ----EEEE | E=Envelope Gen |
$A1 | Frequency low (Write Second) | Ch1 | Ch3 | PPPPPPPP | P=Frequency Position L |
$A2 | Frequency low (Write Second) | Ch2 | Ch4 | PPPPPPPP | P=Frequency Position L |
$A5 | Frequency high & Octave (Write first) | Ch1 | Ch3 | --OOOPPP | O=Octive / P=Position H |
$A6 | Frequency high & Octave (Write first) | Ch2 | Ch4 | --OOOPPP | O=Octive / P=Position H |
$A9 | Frequency low during Multi-Mode | Ch1 | Ch3 | PPPPPPPP | P=Frequency Position L |
$AA | Frequency low during Multi-Mode | Ch2 | Ch4 | PPPPPPPP | P=Frequency Position L |
$AD | Frequency high & Octave during Multi-Mode | Ch1 | Ch3 | --OOOPPP | O=Octive / P=Position H |
$AE | Frequency high & Octave during Multi-Mode | Ch2 | Ch4 | --OOOPPP | O=Octive / P=Position H |
$B1 | Algorithm & Feedback | Ch1 | Ch3 | --FFFAAA | F=Feedback / A=Algorithm |
$B2 | Algorithm & Feedback | Ch2 | Ch4 | --FFFAAA | F=Feedback / A=Algorithm |
$B5 | FMS & AMS & Stereo | Ch1 | Ch3 | LRAA-FFF | Left / Right (1=on) / A=Amplitude Mod Sensitivity / F=Frequency Mod Sensitivity |
$B6 | FMS & AMS & Stereo | Ch2 | Ch4 | LRAA-FFF | Left / Right (1=on) / A=Amplitude Mod Sensitivity / F=Frequency Mod Sensitivity |
The NeoGeo sound
chip is backwards compatible with the AY... and cannot be accessed
by the 68000, so we have to get the Z80 CPU to do the sound
work... The Z80 has its own program code contained in a ROM and separate memory - and we have to pass data betrween the Z80 and 68000 with a single byte RW port! Writes to Z80 port &0C can be read from 68000 port $320000 , and writes to 68000 port $32000 can be read from port &00 |
![]() |
Sound Ports
Communication between the Z80 and 68000 work with the following ports
Z80 |
68000 |
|
Read |
Port &00 |
Address $320000 |
Write |
Port &0C |
Address $320000 |
FM Algorithm (&B1/B2)
The algorithm number is one of 8 - each one defines how the different
operations build up to build a sound:
FM Sound over time
The sound created is affected over time by the various registers, we can
see a simple representation below:
Command | Meaning |
$00 | nop/do nothing |
$01 | Slot switch (needed by bios) |
$02 | Play eyecatch music (needed by bios) |
$03 | Soft Reset (needed by bios) |
$04 | Disable All (Music & Sounds) |
$05 | Disable Music |
$06 | Disable Sounds |
$07 | Enable All (Music & Sounds) |
$08 | Enable Music |
$09 | Enable Sounds |
$0A | Silence SSG channels |
$0B | Silence FM channels |
$0C | Stop all ADPCM-A samples |
$0D | Stop current ADPCM-B sample |
$0E | Tempo Change (1 argument; new tempo) |
$0F | unused |
$10 | Fade Out (1 argument; fade speed) |
$11 | Stop Fade In/Out |
$12 | Fade In (1 argument; fade speed) |
$13-$1F | Unused |
$20-FF | Free for user use |
The YM1610 is backwards compatible with the AY-3-8910 - we covered using
this chip in the Z80
Tutorials here!
On the NeoGeo Sprites are 16 pixels
wide, and are made up of tiles 16 pixels tall... they are 16 colors
(4 bitplanes) so each tile is 128 bytes... The NeoGeo is capable of
up to 380 sprites total. A sprite can be made up of up to 32 tiles to make the sprite taller... there is also a 'Chain' bit - this will connect a sprite to the previous sprite (Sharing its position) to make a sprite wider! Hardware sprite Tiles are not in the same format as the FIX layer - they are 16x16 pixels in size and use bitplanes, but the layout is odd, and they are split onto two rom files (C1/C2 or C3/C4 etc) The sprite is split into 2x 8 pixel wide 'columns' the rightmost one is stored first - each pair of bitplanes 0 & 1 are stored together in ROM C1 - and 2 & 3 are stores in ROM C2 - all 16 lines of the right half are stored first - then the 16 lines of the left side are stored - making a total of 128 bytes (64 in each file) |
![]() |
Address of | Bit | ||||||||||||||||||||
Function | Sprite 1 | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Purpose | Sample | ||
TileAddr 1,2..32 | $0040,$0042�$007E | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N=Tile Number L | $2000 | ||
TilePal 1,2..32 | $0041,$0043...$007F | P | P | P | P | P | P | P | P | N | N | N | N | A | A | V | H | P=Pallete, N=tile Number H, A=Animate (4/8) V=Vflip H=Hflip | $0100 | ||
Shrink | $8001 | - | - | - | - | H | H | H | H | V | V | V | V | V | V | V | V | H=H shrink (F=off), V=V shrink (FF=off) | $0FFF | ||
Ypos | $8201 | Y | Y | Y | Y | Y | Y | Y | Y | Y | C | T | T | T | T | T | T | Y=Y pos (from bottom, so 288+208-Y) C=Chain another sprite on right, T=Tile count vertically | $E002 | ||
Xpos | $8401 | X | X | X | X | X | X | X | X | X | - | - | - | - | - | - | - | X=X pos (from left) | $0800 |
Valid Tile Counts (T) are 1-12 , 32 and 33 (13-31 are invalid)
A special Tile Height of 33 makes the sprite the Full height of screen -
use for building a 'tilemap'
Note: Tile number $2000 would be loaded at ROM address 0x100000 in the XML
First we write the Address of the Sprite Attribute we want to change to $3C0000, then we write the new word value for the address to $3C0002
If you want to AutoInc the VRAM destination after each write, write 1 to $3C0004 or 0 to turn it off.
Sprite
Num |
TileAddr (1st) | TilePal (1st) | TileAddr (32nd) | TilePal (32nd) | Shrink | Ypos | Xpos |
0 | $0000 | $0001 | $003E | $003F | $8000 | $8200 | $8400 |
1 | $0040 | $0041 | $007E | $007F | $8001 | $8201 | $8401 |
2 | $0080 | $0081 | $00BE | $00BF | $8002 | $8202 | $8402 |
3 | $00C0 | $00C1 | $00FE | $00FF | $8003 | $8203 | $8403 |
� |
� | � | � | � | � | � | � |
379 | $5EC0 | $5EC1 | $5EC0 | $5EC1 | $817B | $837B | $857B |
To the right is the source of a
working example for showing a 32x32 sprite! (made up of 2 chained
sprites of 2 tiles each)![]() In MAME We need to load our sprites into the $10000 area for this to work - a working XML is shown below: <dataarea name="sprites" size="0x400000"> <rom loadflag="load16_byte" name="202-c1.c1" offset="0x000000" size="0x100000" crc="479543cf" sha1="772690c872632320133a799aa41f6e68a8d07a4c" /> <rom loadflag="load16_byte" name="202-c2.c2" offset="0x000001" size="0x100000" crc="1f6431d5" sha1="7c90d6ec9df9e6223a066c338b7a7886071370cf" /> <rom loadflag="load16_byte" name="Sprites.c1" offset="0x100000" size="0x100000" crc="479543cf" sha1="772690c872632320133a799aa41f6e68a8d07a4c" /> <rom loadflag="load16_byte" name="Sprites.c2" offset="0x100001" size="0x100000" crc="1f6431d5" sha1="7c90d6ec9df9e6223a066c338b7a7886071370cf" /> </dataarea> Note... Mame will sulk (immediately close) unless the file size of all these sprites are exactly 1MB each (1,048,576 bytes) |
;$3C0000=Select
VRAM Address ;$3C0002=Send data to VRAM move.w #$0040,$3C0000 ;Show Tile 0 from bank $100000 move.w #$2000,$3C0002 ;NNNNNNNN Tile - my tiles start at $2000 move.w #$0041,$3C0000 ;Use Palette 1 move.w #$0100,$3C0002 ;PPPPPPPP NNNNAAVH Palette Tile, Autoanimate Flip move.w #$0040+2,$3C0000 ;Show Tile 1 from bank $100000 move.w #$2001,$3C0002 ;NNNNNNNN Tile move.w #$0041+2,$3C0000 ;Use Palette 1 move.w #$0100,$3C0002 ;PPPPPPPP NNNNAAVH Palette Tile, Autoanimate Flip move.w #$8000+1,$3C0000 ;Full size move.w #$0FFF,$3C0002 ;----HHHH VVVVVVVV - Shrink move.w #$8200+1,$3C0000 ;Top of screen - 2 tiles tall move.w #$F402,$3C0002 ;YYYYYYYY YCSSSSSS Ypos - Chain Sprite Size move.w #$8400+1,$3C0000 ;Left of screen move.w #$0800,$3C0002 ;XXXXXXXX X------- Xpos ;Sprite 2 move.w #$0080,$3C0000 ;Show Tile 2 from bank $100000 move.w #$2002,$3C0002 ;NNNNNNNN Tile - my tiles start at $2000 move.w #$0081,$3C0000 ;Use Palette 1 move.w #$0100,$3C0002 ;PPPPPPPP NNNNAAVH Palette Tile, Autoanimate Flip move.w #$0080+2,$3C0000 ;Show Tile 3 from bank $100000 move.w #$2003,$3C0002 ;NNNNNNNN Tile move.w #$0081+2,$3C0000 ;Use Palette 1 move.w #$0100,$3C0002 ;PPPPPPPP NNNNAAVH Palette Tile, Autoanimate Flip move.w #$8000+2,$3C0000 ;Full size move.w #$0FFF,$3C0002 ;----HHHH VVVVVVVV - Shrink move.w #$8200+2,$3C0000 ;Chain Sprite - Ypos ignored move.w #$0040,$3C0002 ;YYYYYYYY YCSSSSSS Ypos - Chain Sprite Size move.w #$8400+2,$3C0000 ;Xpos ignored due to Chain move.w #$0000,$3C0002 ;XXXXXXXX X------- Xpos |
![]() |
If you're shrinking sprites, and it's causing
'glitches' in the transparent areas of the sprite (black animated
dots) try setting the other tiles of the sprite to a transparent
pattern (even if they shouldn't be used) - It seems to fix the
issue! |