68000 Assembly Programming for the NeoGeo

The SNK NeoGeo always had "mythical" status during my childhood... everyone knew what one was, but it was so out of the price-range of what we could hope to get it was never really on our radar.

The NeoGeo was a simple concept, using the exact same hardware as an arcade, with just some technical tweaks to make it more suited for home users... (and unfortunately the same cost!)... the Neo Geo gave the wealthy the ability to have all the power of high-end arcade hardware at home..

Now that the NeoGeo is easily emulatable, we can all run - and develop for - this hardware at home!
Specs:

Neo GEO AES
Cpu 12mhz 68000
Ram 64k
Cart ROM 2MB
Graphics ROM 16MB  sprites + 128K Fix Tiles (Font)
Vram 64K + 4K
Resolution 320x224 (288x208 visible) - 4096 colors onscreen
Sprites 380 sprites of size 16x16-16x512 - (96 per line - 380 onscreen)
Bitmap planes NONE!
Colors 16 per 16x16 sprite - 256 x 16 color palettes from 65536
Sprites 380 sprites onscreen 16 color  (16x16 px 32 per line) (max 96 per line)
Can be chained to make larger sprites
Suport X and Y scaling (Down only)
Sound chip 6mhz Z80 compatible (84C00AM-6) sound CPU
YM2610 + ADPCM
Power Supply 5V  3A 9V 1.5A (depending on model)  Center pin NEGATIVE

ChibiAkumas Tutorials

Lesson P3 - using the FIX layer to draw bitmaps on the NeoGeo
Lesson P9 - Joystick Reading on the NeoGeo
Lesson P15 - Palette Definitions on the NeoGeo

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 Fix Layer

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:

F E D C B A 7 8   7 6 5 4 3 2 1 0
P P P P T T T T
T T T T T T T T

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

Vram Map
Each address contains a WORD...

Write a word to $3C0000 to select VRAM Address
Write a word to $3C0002 to Send data to VRAM
Start End Words Zone Description
 $0000   $6FFF  28672 Lower SpriteData 1 Tile/Palette
$7000 $74FF 4096
Fix map
$7500 $7FFF

Extension
$8000 $81FF 512 Upper SpriteData 2 - Scale
$8200 $83FF 512
SpriteData 3 Ypos
$8400 $85FF 512
SpriteData 4 Xpos
$8600 $867F 128
Sprite list for even scanlines
$8680 $86FF 128
Sprite list for odd scanlines
$8700 $87FF 256
Unused (free)

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'

Section NAME 
Detail
How to make this?
maincpu
68000 binary data compile a 68000 ASM file with VASM
fixed
FIX Layer Tiles My AkuSprite Editor can make this format
audiocpu
Z80 binary data compile a z80 ASM file with VASM
sprites
Sprite pattern data My AkuSprite Editor can make this format
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:
parameter
name
Detail
code used by my
MakeNeoGeoHash.exe
size
File size in bytes (0x denotes it's in HEX) %size%
crc
Cyclic Redundancy Check (32 bit) of file %crc%
sha1
sha1 of file %sha%
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
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

Color definitions
Palette data is stored between $400000-$401FFF
Each color is 2 bytes in size, there are 16 colors in each palette, and 256 palettes.

The first color in the first palette is special ($400000), it must be $8000... this is called the "Reference color"
The last color in the last palette is special ($401FFE), it is the "Background" color that shows through, when all other layers are transparent

the 16 bits of Color data are in the following format:

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 Color format is quite odd!
each color is defined by 5 bits.. .but the lowest bits for each channel is separate from the rest... this means each color can be quickly defined by a single nibble - or all 5 can be used together...
There is also a "Dark" bit... which is effectively the least significant bit for all 3 color channels.

FM Sound with the YM2610

Get the YM2610 PDF for all the info!

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:

Sound Ops

FM Sound over time
The sound created is affected over time by the various registers, we can see a simple representation below:

Sound Over Time

Z80 Sound Commands

The Z80 can recieve single byte commands from the 68000 to the Z80, it can also return a single byte
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!



Hardware Sprites
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)

Sprite Attributes
Each sprite is defined by 1-32 tile definitions, A palette/flip byte, a Scale byte, a Ypos/Height byte and an Xpos... lets see what all these bits do in detail!
Note, it's possible to scale a sprite DOWN, but it's not possible to scale them up...

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 248-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'


Sprite Attribute Addresses
We need to set various addresses in the Sprite Attribute data... to do this we use two 68000 addresses...

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

 Sprite Num
 TileAddr (1st)   TilePalr (1st)   TileAddr (32nd)   TilePalr (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


NeoGeo Links!
Neo Geo programming for the absolute beginner - My template Header/footer are based on this!
NeoGeo Programmers Guide PDF

NeoGeoDev.org



 

View Options
Default Dark
Simple (Hide this menu)
Print Mode (white background)

Top Menu
Youtube channel
ASM Programming Forums
GitHub
Dec/Bin/Hex/Oct/Ascii Table

Z80 Content
Learn Z80 Assembly
Hello World
Advanced Series
Multiplatform Series
Platform Specific Series
ChibiAkumas Series
Grime Z80
Z80 Downloads
Z80 Cheatsheet
Sources.7z
DevTools kit
Z80 Platforms
Amstrad CPC
Elan Enterprise
Gameboy & Gameboy Color
Master System & GameGear
MSX & MSX2
Sam Coupe
TI-83
ZX Spectrum
Spectrum NEXT
Camputers Lynx

6502 Content
Learn 6502 Assembly
Advanced Series
Platform Specific Series
Grime 6502
6502 Downloads
6502 Cheatsheet
Sources.7z
DevTools kit
6502 Platforms
Apple IIe
Atari 800 and 5200
Atari Lynx
BBC Micro
Commodore 64
Commander x16
Super Nintendo (SNES)
Nintendo NES / Famicom
PC Engine (Turbografx-16)
Vic 20

68000 Content
Learn 68000 Assembly
Platform Specific Series
Grime 68000
68000 Downloads
68000 Cheatsheet
Sources.7z
DevTools kit
68000 Platforms
Amiga 500
Atari ST
Neo Geo
Sega Genesis / Mega Drive
Sinclair QL (Quantum Leap)
X68000 (Sharp x68k)

My Game projects
Chibi Aliens
Chibi Akumas

Work in Progress
Learn 6809 Assembly
Learn 65816 Assembly
Learn 6809 Assembly
Learn PDP11 Assembly
Learn TMS9900 Assembly
Learn 8086 Assembly (x86)
Learn Risc-V Assembly
Wonderswan
MsDos
Learn ARM Assembly
Dragon 32/Tandy Coco
Ti 99
Gameboy Advance
Risc Os

Misc bits
Ruby programming




Chibi Akumas V1.666 has taken over 350 hours of development, if you want to support my work, and learn all the secrets of the game's development, please back me on patreon!





Thanks to Homebrew Legends for help promoting my game!
Buy Chibi Akuma(s) from PolyPlay
Buy ChibiAkuma(s) games now!