<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.neogeodev.org//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Eaglesoftware777</id>
	<title>NeoGeo Development Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.neogeodev.org//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Eaglesoftware777"/>
	<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php/Special:Contributions/Eaglesoftware777"/>
	<updated>2026-10-06T23:30:49Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=User_talk:Eaglesoftware777&amp;diff=9351</id>
		<title>User talk:Eaglesoftware777</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=User_talk:Eaglesoftware777&amp;diff=9351"/>
		<updated>2026-09-29T23:45:47Z</updated>

		<summary type="html">&lt;p&gt;Eaglesoftware777: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;NeoGeo Development Wiki&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents help pages].&lt;br /&gt;
Again, welcome and have fun! [[User:Furrtek|Furrtek]] ([[User talk:Furrtek|talk]]) 11:42, 23 September 2026 (CEST)&lt;br /&gt;
&lt;br /&gt;
Hello. I need to know if your edits are AI-generated, and/or if you allow AI agents to make edits on your behalf through your account.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hello, yes we did use AI to correct text and improve organization/language and layout manually ..no automated tool or direct connection via AI using our account.&lt;br /&gt;
The model we use is Gemini.&lt;br /&gt;
&lt;br /&gt;
We would like to thank you for your works Furrtek on the neo geo documentation and the wiki great work that was very usefull for us druing first days around 2015 to develop some basic parts of the Eagle software Neogeosdk&lt;/div&gt;</summary>
		<author><name>Eaglesoftware777</name></author>
	</entry>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=User_talk:Eaglesoftware777&amp;diff=9350</id>
		<title>User talk:Eaglesoftware777</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=User_talk:Eaglesoftware777&amp;diff=9350"/>
		<updated>2026-09-29T23:43:21Z</updated>

		<summary type="html">&lt;p&gt;Eaglesoftware777: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;NeoGeo Development Wiki&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents help pages].&lt;br /&gt;
Again, welcome and have fun! [[User:Furrtek|Furrtek]] ([[User talk:Furrtek|talk]]) 11:42, 23 September 2026 (CEST)&lt;br /&gt;
&lt;br /&gt;
Hello. I need to know if your edits are AI-generated, and/or if you allow AI agents to make edits on your behalf through your account.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hello, yes we did use AI to correct text and improve organization/language and layout manually ..no automated tool or direct connection via AI usisng our account.&lt;br /&gt;
The model we use is Gemini.&lt;br /&gt;
&lt;br /&gt;
We would like to thank you for your works Furrtek on the neo geo documentation and the wiki great work that was very usefull for us druing first days around 2015 to develop some basic parts of the Eagle software Neogeosdk&lt;/div&gt;</summary>
		<author><name>Eaglesoftware777</name></author>
	</entry>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=User_talk:Eaglesoftware777&amp;diff=9349</id>
		<title>User talk:Eaglesoftware777</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=User_talk:Eaglesoftware777&amp;diff=9349"/>
		<updated>2026-09-29T23:42:52Z</updated>

		<summary type="html">&lt;p&gt;Eaglesoftware777: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;NeoGeo Development Wiki&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents help pages].&lt;br /&gt;
Again, welcome and have fun! [[User:Furrtek|Furrtek]] ([[User talk:Furrtek|talk]]) 11:42, 23 September 2026 (CEST)&lt;br /&gt;
&lt;br /&gt;
Hello. I need to know if your edits are AI-generated, and/or if you allow AI agents to make edits on your behalf through your account.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hello, yes we did use AI to correct text and improve organization/language and layout manually ..no automated tool or direct connection via AI usisng our account.&lt;br /&gt;
The model we use is Gemini.&lt;br /&gt;
&lt;br /&gt;
We would like to thank you for your works Furrtek on the neo geo documentation and the wiki great work that was very usefull for us druing first days to develop some basic parts of the Eagle software Neogeosdk&lt;/div&gt;</summary>
		<author><name>Eaglesoftware777</name></author>
	</entry>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=User_talk:Eaglesoftware777&amp;diff=9348</id>
		<title>User talk:Eaglesoftware777</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=User_talk:Eaglesoftware777&amp;diff=9348"/>
		<updated>2026-09-29T23:40:33Z</updated>

		<summary type="html">&lt;p&gt;Eaglesoftware777: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;NeoGeo Development Wiki&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents help pages].&lt;br /&gt;
Again, welcome and have fun! [[User:Furrtek|Furrtek]] ([[User talk:Furrtek|talk]]) 11:42, 23 September 2026 (CEST)&lt;br /&gt;
&lt;br /&gt;
Hello. I need to know if your edits are AI-generated, and/or if you allow AI agents to make edits on your behalf through your account.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hello, yes we did use AI to correct text and improve organization/language and layout manually ..no automated tool or direct connection via AI usisng our account.&lt;br /&gt;
The model we use is Gemini.&lt;/div&gt;</summary>
		<author><name>Eaglesoftware777</name></author>
	</entry>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=Making_scrollable_backgrounds&amp;diff=9341</id>
		<title>Making scrollable backgrounds</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=Making_scrollable_backgrounds&amp;diff=9341"/>
		<updated>2026-09-27T12:50:25Z</updated>

		<summary type="html">&lt;p&gt;Eaglesoftware777: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Scrolling backgrounds are formed using a set of [[sprites]] positioned directly next to each other. A sprite is only 16 pixels wide, so many are needed to fill the screen horizontally. The [[Sticky bit]] makes this simpler: once a set of sprites is chained, the whole layer is moved by changing the position of its first sprite only.&lt;br /&gt;
&lt;br /&gt;
The screen is 320 pixels wide. 20 sprites cover it exactly, but a layer that scrolls by less than 16 pixels at a time also shows part of a 21st sprite at the right edge. A set of 21 chained sprites is therefore the minimum for a single full-screen scrolling background layer.&lt;br /&gt;
&lt;br /&gt;
==How a chained layer works==&lt;br /&gt;
A layer is made of one &#039;&#039;&#039;driving sprite&#039;&#039;&#039; followed by any number of &#039;&#039;&#039;chained sprites&#039;&#039;&#039; in the next sprite slots.&lt;br /&gt;
&lt;br /&gt;
* The driving sprite holds the position of the whole layer: its [[SCB3]] word gives the Y position and height, and its [[SCB4]] word gives the X position.&lt;br /&gt;
* Each chained sprite has the sticky bit (bit 6) set in its SCB3 word. It takes its Y position, height and vertical shrink from the previous sprite, and is placed 16 pixels to the right of it (less when the previous sprite is horizontally shrunk). The rest of its SCB3 word and its SCB4 word are ignored.&lt;br /&gt;
* Each sprite has its own column of tiles in [[SCB1]], so every 16-pixel column of the layer can show different graphics.&lt;br /&gt;
&lt;br /&gt;
Moving the layer only takes one VRAM write (SCB4 of the driving sprite) for horizontal scrolling, and one more (SCB3 of the driving sprite) for vertical scrolling.&lt;br /&gt;
&lt;br /&gt;
===Wrap-around at 512 pixels===&lt;br /&gt;
The X position in SCB4 is 9 bits wide, so sprite positions wrap around every 512 pixels: a sprite at X = 500 is drawn 12 pixels to the left of the screen, partly visible. A chain of &#039;&#039;&#039;32&#039;&#039;&#039; sprites is exactly 512 pixels wide, so it covers every possible X position. Whatever value is written to the driving sprite&#039;s X, the screen is always fully covered, and the layer repeats every 512 pixels.&lt;br /&gt;
&lt;br /&gt;
This gives two ways to build a scrolling layer:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Looping layer&#039;&#039;&#039;: 32 chained sprites showing a 512-pixel-wide picture whose left and right edges join seamlessly. The tiles are written once. Scrolling is only X = -camera, which wraps by itself. This is enough for skies, distant mountains, and repeating ground.&lt;br /&gt;
* &#039;&#039;&#039;Streamed layer&#039;&#039;&#039;: the same 32 chained sprites, but the tile column of each sprite is replaced as the camera moves, with columns read from a level map in ROM. The level can then be any width, with no repetition. Only the columns that come into view are written.&lt;br /&gt;
&lt;br /&gt;
===Parallax===&lt;br /&gt;
Several layers can move at different speeds by using a fraction of the camera position for each one: for example the full camera X for the ground, half of it for hills, and a quarter for clouds. Each layer is a separate chain, and each only needs its own driving sprite updated. Sprites in higher slots are drawn in front of sprites in lower slots, so the farthest layer uses the lowest slots.&lt;br /&gt;
&lt;br /&gt;
===Sprites per line===&lt;br /&gt;
The hardware draws at most 96 sprites on a line. A sprite counts towards that limit on every line it covers vertically, whatever its X position, so a 32-sprite layer costs 32 sprites on every line it covers, even though only 21 of them are on screen. Keep this in mind when stacking several full-height layers: three of them already use every sprite a line can show.&lt;br /&gt;
&lt;br /&gt;
==Updating VRAM==&lt;br /&gt;
VRAM is accessed through three registers:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Register !! Address !! Use&lt;br /&gt;
|-&lt;br /&gt;
| REG_VRAMADDR || $3C0000 || VRAM word address for the next access&lt;br /&gt;
|-&lt;br /&gt;
| REG_VRAMRW || $3C0002 || Data to write (or data read) at that address&lt;br /&gt;
|-&lt;br /&gt;
| REG_VRAMMOD || $3C0004 || Value added to the address after each access&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
With REG_VRAMMOD set to 1, consecutive writes to REG_VRAMRW fill consecutive VRAM words, so a whole tile column or a run of SCB entries is written with one address setup. REG_VRAMRW must always be written as a word: a long write would also write REG_VRAMMOD.&lt;br /&gt;
&lt;br /&gt;
The sprite control blocks are laid out as follows:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Block !! VRAM address !! Content per sprite&lt;br /&gt;
|-&lt;br /&gt;
| [[SCB1]] || $0000 + sprite × 64 || 32 pairs of words: tile number (bits 0-15), then attributes: palette (bits 15-8), tile number bits 16-19 (bits 7-4), auto-animation (bits 3-2), V flip (bit 1), H flip (bit 0)&lt;br /&gt;
|-&lt;br /&gt;
| [[SCB2]] || $8000 + sprite || Shrink: horizontal (bits 11-8), vertical (bits 7-0). $0FFF = full size&lt;br /&gt;
|-&lt;br /&gt;
| [[SCB3]] || $8200 + sprite || Y position as 496 - Y (bits 15-7), sticky bit (bit 6), height in tiles (bits 5-0)&lt;br /&gt;
|-&lt;br /&gt;
| [[SCB4]] || $8400 + sprite || X position (bits 15-7)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All scroll updates should be done during vertical blank. Writing the position in the middle of a frame moves the layer part-way down the screen, which shows as a visible tear.&lt;br /&gt;
&lt;br /&gt;
==Example code==&lt;br /&gt;
The code below builds a 32-sprite chained layer, scrolls it, and streams tile columns from a level map in ROM. The same routines also give a looping layer: skip the streaming step and load 32 columns of a 512-pixel picture once.&lt;br /&gt;
&lt;br /&gt;
The level map is stored column by column. Each column holds 32 tiles as pairs of words (tile number, attributes), so every column is 128 bytes long and column n starts at LevelMap + n × 128. Rows below the layer height are never read by the hardware and can be left empty.&lt;br /&gt;
&lt;br /&gt;
===Definitions===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
REG_VRAMADDR	equ	$3C0000&lt;br /&gt;
REG_VRAMRW	equ	$3C0002&lt;br /&gt;
REG_VRAMMOD	equ	$3C0004&lt;br /&gt;
&lt;br /&gt;
SCB1		equ	$0000		;tile maps, 64 words per sprite&lt;br /&gt;
SCB2		equ	$8000		;shrink&lt;br /&gt;
SCB3		equ	$8200		;Y, sticky bit, height&lt;br /&gt;
SCB4		equ	$8400		;X&lt;br /&gt;
&lt;br /&gt;
LAYER_FIRST	equ	33		;first sprite slot of the layer (in front of a far layer at 1-32)&lt;br /&gt;
LAYER_STRIPS	equ	32		;32 x 16 = 512 pixels: covers every X position&lt;br /&gt;
LAYER_ROWS	equ	14		;height in tiles (14 x 16 = 224 pixels)&lt;br /&gt;
LAYER_Y		equ	0		;screen Y of the top of the layer&lt;br /&gt;
&lt;br /&gt;
		;in work RAM&lt;br /&gt;
LastCol		ds.w	1		;first column visible on the last update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Writing one column===&lt;br /&gt;
Copies world column d0 from the level map into the sprite that shows it. Column n always goes to sprite LAYER_FIRST + (n mod 32), which is exactly where the chain places it on screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;In:  d0.w = world column&lt;br /&gt;
;Uses d0-d1/a0-a1. REG_VRAMMOD must be 1.&lt;br /&gt;
WriteColumn:&lt;br /&gt;
	lea	REG_VRAMRW,a1&lt;br /&gt;
	move.w	d0,d1&lt;br /&gt;
	and.w	#LAYER_STRIPS-1,d1	;sprite = first + column mod 32&lt;br /&gt;
	add.w	#LAYER_FIRST,d1&lt;br /&gt;
	lsl.w	#6,d1			;x 64 words: its SCB1 address&lt;br /&gt;
	move.w	d1,REG_VRAMADDR&lt;br /&gt;
&lt;br /&gt;
	lea	LevelMap,a0&lt;br /&gt;
	moveq	#0,d1&lt;br /&gt;
	move.w	d0,d1&lt;br /&gt;
	lsl.l	#7,d1			;column x 128 bytes&lt;br /&gt;
	adda.l	d1,a0&lt;br /&gt;
&lt;br /&gt;
	moveq	#LAYER_ROWS*2-1,d1	;tile word + attribute word per row&lt;br /&gt;
.copy:&lt;br /&gt;
	move.w	(a0)+,(a1)&lt;br /&gt;
	dbra	d1,.copy&lt;br /&gt;
	rts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setting up the layer===&lt;br /&gt;
Writes the shrink, height, sticky bits and position of all 32 sprites, then loads the 21 columns visible at camera X = 0.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
InitLayer:&lt;br /&gt;
	move.w	#1,REG_VRAMMOD&lt;br /&gt;
	lea	REG_VRAMRW,a1&lt;br /&gt;
&lt;br /&gt;
	;SCB2: full size for every sprite&lt;br /&gt;
	move.w	#SCB2+LAYER_FIRST,REG_VRAMADDR&lt;br /&gt;
	moveq	#LAYER_STRIPS-1,d1&lt;br /&gt;
.scb2:&lt;br /&gt;
	move.w	#$0FFF,(a1)&lt;br /&gt;
	dbra	d1,.scb2&lt;br /&gt;
&lt;br /&gt;
	;SCB3: the driving sprite has Y and height, the others are chained to it&lt;br /&gt;
	move.w	#SCB3+LAYER_FIRST,REG_VRAMADDR&lt;br /&gt;
	move.w	#((496-LAYER_Y)&amp;lt;&amp;lt;7)|LAYER_ROWS,(a1)&lt;br /&gt;
	moveq	#LAYER_STRIPS-2,d1&lt;br /&gt;
.scb3:&lt;br /&gt;
	move.w	#$0040|LAYER_ROWS,(a1)	;sticky bit + height&lt;br /&gt;
	dbra	d1,.scb3&lt;br /&gt;
&lt;br /&gt;
	;SCB4: X of the driving sprite (chained sprites ignore theirs)&lt;br /&gt;
	move.w	#SCB4+LAYER_FIRST,REG_VRAMADDR&lt;br /&gt;
	move.w	#0,(a1)&lt;br /&gt;
&lt;br /&gt;
	;tiles for the columns on screen at camera X = 0&lt;br /&gt;
	moveq	#0,d0&lt;br /&gt;
.cols:&lt;br /&gt;
	move.w	d0,-(sp)&lt;br /&gt;
	bsr	WriteColumn&lt;br /&gt;
	move.w	(sp)+,d0&lt;br /&gt;
	addq.w	#1,d0&lt;br /&gt;
	cmp.w	#21,d0&lt;br /&gt;
	bne.s	.cols&lt;br /&gt;
&lt;br /&gt;
	clr.w	LastCol&lt;br /&gt;
	rts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Scrolling and streaming===&lt;br /&gt;
Called once per frame during vertical blank, with the camera position in world pixels. The visible columns are always c to c + 20, where c = camera X / 16.&lt;br /&gt;
&lt;br /&gt;
* When the camera enters column c from the left, column c + 20 is about to appear at the right edge: it is written now, while it is still just off-screen.&lt;br /&gt;
* When the camera enters column c from the right, column c is appearing at the left edge and is written.&lt;br /&gt;
&lt;br /&gt;
Each step writes one column, and a camera that moves less than 16 pixels per frame needs at most one step. The other 11 sprites of the chain are off-screen at all times, so the old tiles they hold are never seen. Finally the driving sprite is moved to X = -camera; the wrap-around at 512 keeps every column at its correct screen position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;In:  d0.w = camera X in world pixels (0 to level width - 320)&lt;br /&gt;
;Uses d0-d3/a0-a1&lt;br /&gt;
ScrollLayer:&lt;br /&gt;
	move.w	d0,d3			;keep the camera position&lt;br /&gt;
	move.w	d0,d2&lt;br /&gt;
	lsr.w	#4,d2			;c = first visible column&lt;br /&gt;
&lt;br /&gt;
.right:					;camera moved right: bring in columns on the right&lt;br /&gt;
	cmp.w	LastCol,d2&lt;br /&gt;
	ble.s	.left&lt;br /&gt;
	addq.w	#1,LastCol&lt;br /&gt;
	move.w	LastCol,d0&lt;br /&gt;
	add.w	#20,d0&lt;br /&gt;
	bsr	WriteColumn&lt;br /&gt;
	bra.s	.right&lt;br /&gt;
&lt;br /&gt;
.left:					;camera moved left: bring in columns on the left&lt;br /&gt;
	cmp.w	LastCol,d2&lt;br /&gt;
	bge.s	.move&lt;br /&gt;
	subq.w	#1,LastCol&lt;br /&gt;
	move.w	LastCol,d0&lt;br /&gt;
	bsr	WriteColumn&lt;br /&gt;
	bra.s	.left&lt;br /&gt;
&lt;br /&gt;
.move:&lt;br /&gt;
	move.w	#SCB4+LAYER_FIRST,REG_VRAMADDR&lt;br /&gt;
	neg.w	d3			;X = -camera&lt;br /&gt;
	lsl.w	#7,d3			;into bits 15-7; bits above 511 fall off&lt;br /&gt;
	move.w	d3,REG_VRAMRW&lt;br /&gt;
	rts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The level map must have at least 21 columns past the rightmost camera position, so the camera bounds must keep it inside 0 to (level width - 320).&lt;br /&gt;
&lt;br /&gt;
===Looping and parallax layers===&lt;br /&gt;
A looping layer needs no streaming: load all 32 columns once in InitLayer (loop to 32 instead of 21), then each frame only write its driving sprite&#039;s X. For a layer that moves at half the camera&#039;s speed:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
FAR_FIRST	equ	1		;far layer in slots 1-32: drawn behind the main layer at 33-64&lt;br /&gt;
&lt;br /&gt;
;In: d0.w = camera X&lt;br /&gt;
ScrollFarLayer:&lt;br /&gt;
	asr.w	#1,d0			;half speed&lt;br /&gt;
	neg.w	d0&lt;br /&gt;
	lsl.w	#7,d0			;wraps every 512 pixels by itself&lt;br /&gt;
	move.w	#SCB4+FAR_FIRST,REG_VRAMADDR&lt;br /&gt;
	move.w	d0,REG_VRAMRW&lt;br /&gt;
	rts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use asr.w #2 for a quarter of the speed, or a multiply by a fixed-point factor for other ratios.&lt;br /&gt;
&lt;br /&gt;
===Vertical scrolling===&lt;br /&gt;
The same principle applies vertically: write the Y position to the driving sprite&#039;s SCB3, keeping the sticky bit clear and the height unchanged. The chained sprites follow it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;In: d0.w = screen Y of the top of the layer&lt;br /&gt;
SetLayerY:&lt;br /&gt;
	move.w	#496,d1&lt;br /&gt;
	sub.w	d0,d1			;496 - Y&lt;br /&gt;
	lsl.w	#7,d1			;into bits 15-7&lt;br /&gt;
	or.w	#LAYER_ROWS,d1		;height&lt;br /&gt;
	move.w	#SCB3+LAYER_FIRST,REG_VRAMADDR&lt;br /&gt;
	move.w	d1,REG_VRAMRW&lt;br /&gt;
	rts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Demos==&lt;br /&gt;
Interactive demos with source can be found [http://smkdan.eludevisibility.org/neo/scroll_02.zip here].&lt;br /&gt;
&lt;br /&gt;
[[Category:Code]]&lt;br /&gt;
[[Category:Graphics Code]]&lt;/div&gt;</summary>
		<author><name>Eaglesoftware777</name></author>
	</entry>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=Using_the_SSG_sound_channels&amp;diff=9340</id>
		<title>Using the SSG sound channels</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=Using_the_SSG_sound_channels&amp;diff=9340"/>
		<updated>2026-09-27T03:57:21Z</updated>

		<summary type="html">&lt;p&gt;Eaglesoftware777: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==SSG==&lt;br /&gt;
The SSG part of the YM2610 is compatible with the AY-3-8910 (without its I/O ports). It has 3 square-wave tone channels (A, B, C), one noise generator that can be mixed into any channel, and one envelope generator (EG) shared by all channels. Each channel has a 4-bit volume, or can take its volume from the EG instead.&lt;br /&gt;
&lt;br /&gt;
The SSG registers are on YM2610 &#039;&#039;&#039;port A&#039;&#039;&#039;: the Z80 writes the register number to port &#039;&#039;&#039;$04&#039;&#039;&#039; and the value to port &#039;&#039;&#039;$05&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Definitions of [[YM2610_registers#SSG part|SSG registers]]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
;SSG register defines (YM2610 port A: address $04, data $05)&lt;br /&gt;
SSG_AFINE:	EQU $00		;channel A tone period, bits 0-7&lt;br /&gt;
SSG_ACOARSE:	EQU $01		;channel A tone period, bits 8-11&lt;br /&gt;
SSG_BFINE:	EQU $02		;channel B&lt;br /&gt;
SSG_BCOARSE:	EQU $03&lt;br /&gt;
SSG_CFINE:	EQU $04		;channel C&lt;br /&gt;
SSG_CCOARSE:	EQU $05&lt;br /&gt;
SSG_NOISE:	EQU $06		;noise period, 5 bits (0-$1F)&lt;br /&gt;
SSG_MIXER:	EQU $07		;bits 0-2: tone A/B/C off, bits 3-5: noise A/B/C off (1 = off)&lt;br /&gt;
SSG_AVOL:	EQU $08		;bits 0-3: volume 0-$F, bit 4: use EG instead&lt;br /&gt;
SSG_BVOL:	EQU $09&lt;br /&gt;
SSG_CVOL:	EQU $0A&lt;br /&gt;
SSG_EGFINE:	EQU $0B		;EG period, bits 0-7&lt;br /&gt;
SSG_EGCOARSE:	EQU $0C		;EG period, bits 8-15&lt;br /&gt;
SSG_EGSHAPE:	EQU $0D		;bits 0-3: hold, alternate, attack, continue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Full list of defines [[YM2610 ASM defines|here]])&lt;br /&gt;
&lt;br /&gt;
===Frequencies===&lt;br /&gt;
With the YM2610&#039;s 8 MHz clock:&lt;br /&gt;
&lt;br /&gt;
 Tone:  f = 125000 / TP      TP = 12-bit tone period (1-$FFF)&lt;br /&gt;
 Noise: f = 125000 / NP      NP = 5-bit noise period (1-$1F)&lt;br /&gt;
 EG:    f = 7812.5 / EP      EP = 16-bit EG period; f is the repeat rate of one full ramp&lt;br /&gt;
&lt;br /&gt;
For example, TP = $040 gives about 1953 Hz, and A4 (440 Hz) is TP = 284 ($11C). Going up one octave halves TP; going down one octave doubles it.&lt;br /&gt;
&lt;br /&gt;
===Mixer register===&lt;br /&gt;
In register $07 a bit set to &#039;&#039;&#039;1&#039;&#039;&#039; turns the source &#039;&#039;&#039;off&#039;&#039;&#039;. Bits 0-2 control the tone of channels A, B and C, and bits 3-5 control the noise on channels A, B and C. So $3F silences all tone and noise, $3E enables only the tone of channel A, and $37 enables only noise on channel A.&lt;br /&gt;
&lt;br /&gt;
The mixer controls all three channels at once. A driver that plays several channels independently should keep a copy of the register in RAM and change only its own bits (see the example below).&lt;br /&gt;
&lt;br /&gt;
===Write routine===&lt;br /&gt;
The examples below use RST $08 to write register D with value E on port A. An RST slot is only 8 bytes long, and the write routine does not fit in it together with a RET, so the slot jumps to the routine instead. Polling the busy flag (bit 7 of port $04) before each write is the safe choice on real hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
	.org $0008&lt;br /&gt;
	jp	WritePortA		;RST $08: set YM2610 port A register D to value E&lt;br /&gt;
&lt;br /&gt;
;Write E to YM2610 port A register D&lt;br /&gt;
;Destroys: nothing&lt;br /&gt;
WritePortA:&lt;br /&gt;
	push	af&lt;br /&gt;
WPA_wait1:&lt;br /&gt;
	in	a,($04)			;status 0&lt;br /&gt;
	rlca				;busy flag -&amp;gt; carry&lt;br /&gt;
	jr	c,WPA_wait1&lt;br /&gt;
	ld	a,d&lt;br /&gt;
	out	($04),a			;register number&lt;br /&gt;
WPA_wait2:&lt;br /&gt;
	in	a,($04)&lt;br /&gt;
	rlca&lt;br /&gt;
	jr	c,WPA_wait2&lt;br /&gt;
	ld	a,e&lt;br /&gt;
	out	($05),a			;value&lt;br /&gt;
	pop	af&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beep using the envelope generator===&lt;br /&gt;
Plays a 2 kHz tone on channel A whose volume repeatedly ramps down.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
FastBeep:&lt;br /&gt;
	ld	de,$0040		;Channel A tone period: $040 (about 2 kHz)&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0100&lt;br /&gt;
	rst	$08&lt;br /&gt;
&lt;br /&gt;
	ld	de,$0B0F		;EG period: $050F (about 6 Hz)&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0C05&lt;br /&gt;
	rst	$08&lt;br /&gt;
&lt;br /&gt;
	ld	de,$0810		;Channel A volume is taken from the EG&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0D08		;EG shape: repeating ramp down&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$073E		;Only the tone of channel A is on&lt;br /&gt;
	rst	$08&lt;br /&gt;
&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the mixer value is $3E, not $0E. $0E leaves the noise enabled on channels B and C.&lt;br /&gt;
&lt;br /&gt;
Writing the EG shape register restarts the envelope, so write it last, when the sound should start.&lt;br /&gt;
&lt;br /&gt;
===EG shapes===&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Value !! Shape&lt;br /&gt;
|-&lt;br /&gt;
| $00-$03, $09 || Single ramp down, then stay at 0&lt;br /&gt;
|-&lt;br /&gt;
| $04-$07, $0F || Single ramp up, then drop to 0 and stay there&lt;br /&gt;
|-&lt;br /&gt;
| $08 || Repeating ramp down (sawtooth)&lt;br /&gt;
|-&lt;br /&gt;
| $0A || Repeating down-up (triangle)&lt;br /&gt;
|-&lt;br /&gt;
| $0B || Single ramp down, then stay at maximum&lt;br /&gt;
|-&lt;br /&gt;
| $0C || Repeating ramp up (sawtooth)&lt;br /&gt;
|-&lt;br /&gt;
| $0D || Single ramp up, then stay at maximum&lt;br /&gt;
|-&lt;br /&gt;
| $0E || Repeating up-down (triangle)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Playing a note===&lt;br /&gt;
Sets channel C (0 = A, 1 = B, 2 = C) to note A (0-11 = C to B, octave 4). The table holds TP values; the fine and coarse registers of channel n are 2n and 2n+1.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
;In: A = note 0-11, C = channel 0-2&lt;br /&gt;
SSG_SetNote:&lt;br /&gt;
	push	hl&lt;br /&gt;
	ld	hl,SSG_NoteTable&lt;br /&gt;
	add	a,a			;2 bytes per entry&lt;br /&gt;
	add	a,l&lt;br /&gt;
	ld	l,a&lt;br /&gt;
	jr	nc,SSG_SN_nc&lt;br /&gt;
	inc	h&lt;br /&gt;
SSG_SN_nc:&lt;br /&gt;
	ld	a,c&lt;br /&gt;
	add	a,a&lt;br /&gt;
	ld	d,a			;fine tune register&lt;br /&gt;
	ld	e,(hl)&lt;br /&gt;
	rst	$08&lt;br /&gt;
	inc	d			;coarse tune register&lt;br /&gt;
	inc	hl&lt;br /&gt;
	ld	e,(hl)&lt;br /&gt;
	rst	$08&lt;br /&gt;
	pop	hl&lt;br /&gt;
	ret&lt;br /&gt;
&lt;br /&gt;
SSG_NoteTable:				;octave 4, TP = 125000 / f&lt;br /&gt;
	dw	478,451,426,402,379,358,338,319,301,284,268,253&lt;br /&gt;
	;	C   C#  D   D#  E   F   F#  G   G#  A   A#  B&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For other octaves, shift the TP right (higher) or left (lower) once per octave before writing it.&lt;br /&gt;
&lt;br /&gt;
===Enabling one channel without affecting the others===&lt;br /&gt;
Keeps a copy of the mixer register in RAM, so each channel can be switched on or off independently.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
MixerCopy:	EQU $F800		;1 byte of Z80 RAM, initialised to $3F&lt;br /&gt;
&lt;br /&gt;
;Enable the tone of channel C (0-2)&lt;br /&gt;
SSG_ToneOn:&lt;br /&gt;
	ld	a,c&lt;br /&gt;
	call	SSG_ChannelBit		;A = 1 &amp;lt;&amp;lt; channel&lt;br /&gt;
	cpl&lt;br /&gt;
	ld	b,a&lt;br /&gt;
	ld	a,(MixerCopy)&lt;br /&gt;
	and	b			;clear bit = tone on&lt;br /&gt;
	jr	SSG_WriteMixer&lt;br /&gt;
&lt;br /&gt;
;Disable the tone of channel C (0-2)&lt;br /&gt;
SSG_ToneOff:&lt;br /&gt;
	ld	a,c&lt;br /&gt;
	call	SSG_ChannelBit&lt;br /&gt;
	ld	b,a&lt;br /&gt;
	ld	a,(MixerCopy)&lt;br /&gt;
	or	b			;set bit = tone off&lt;br /&gt;
&lt;br /&gt;
SSG_WriteMixer:&lt;br /&gt;
	ld	(MixerCopy),a&lt;br /&gt;
	ld	d,SSG_MIXER&lt;br /&gt;
	ld	e,a&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ret&lt;br /&gt;
&lt;br /&gt;
;A = channel 0-2 -&amp;gt; A = 1 &amp;lt;&amp;lt; channel&lt;br /&gt;
SSG_ChannelBit:&lt;br /&gt;
	ld	b,a&lt;br /&gt;
	ld	a,1&lt;br /&gt;
	inc	b&lt;br /&gt;
SSG_CB_loop:&lt;br /&gt;
	dec	b&lt;br /&gt;
	ret	z&lt;br /&gt;
	add	a,a&lt;br /&gt;
	jr	SSG_CB_loop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The same approach works for noise, using bits 3-5 (shift the channel bit left 3 times).&lt;br /&gt;
&lt;br /&gt;
===Noise hit===&lt;br /&gt;
A short noise burst on channel C that decays by itself, usable as a snare or explosion.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
NoiseHit:&lt;br /&gt;
	ld	de,$0608		;Noise period: 8&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0B00		;EG period: $0800 (about 4 Hz: a decay of about 0.26 s)&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0C08&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0A10		;Channel C volume is taken from the EG&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$071F		;Noise on channel C only (tone off everywhere)&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0D00		;EG shape: single ramp down, then silent&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A lower noise period gives a brighter, hissier sound; a higher one sounds rougher.&lt;br /&gt;
&lt;br /&gt;
===Silence===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
SSG_Silence:&lt;br /&gt;
	ld	de,$0800		;Channel A volume = 0&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0900		;Channel B volume = 0&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$0A00		;Channel C volume = 0&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ld	de,$073F		;Disable tone and noise on all channels&lt;br /&gt;
	rst	$08&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the mixer value is $3F, not $0F. $0F only disables the three tones and the noise on channel A; noise on channels B and C stays enabled.&lt;br /&gt;
&lt;br /&gt;
[[Category:Code]]&lt;br /&gt;
[[Category:Sound Code]]&lt;/div&gt;</summary>
		<author><name>Eaglesoftware777</name></author>
	</entry>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=Playing_sound_samples&amp;diff=9339</id>
		<title>Playing sound samples</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=Playing_sound_samples&amp;diff=9339"/>
		<updated>2026-09-27T03:53:59Z</updated>

		<summary type="html">&lt;p&gt;Eaglesoftware777: /* ADPCM-A */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==ADPCM-A==&lt;br /&gt;
The YM2610 has 6 ADPCM-A channels. They play 4-bit ADPCM samples from V ROM at a fixed rate of 18.5 kHz (8 MHz / 432); there is no pitch control. Each channel has its own start address, end address, pan and volume, and all six share a master volume.&lt;br /&gt;
&lt;br /&gt;
The ADPCM-A registers are on YM2610 &#039;&#039;&#039;port B&#039;&#039;&#039;: the Z80 writes the register number to port &#039;&#039;&#039;$06&#039;&#039;&#039; and the value to port &#039;&#039;&#039;$07&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Sample addresses are given in 256-byte units: the start and end registers hold bits 8-23 of the V ROM byte address. The end address is inclusive, so a sample occupying $000000-$00FFFF has start $0000 and end $00FF. A sample must not cross a 1 MB boundary, because the top 4 bits of the address counter are not incremented during playback.&lt;br /&gt;
&lt;br /&gt;
Definitions of [[YM2610_registers#ADPCM-A part|ADPCM-A registers]]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
;ADPCM-A register defines (YM2610 port B: address $06, data $07)&lt;br /&gt;
PA_CTRL:	EQU $00		;bit 7: 0 = key on, 1 = dump (key off). Bits 0-5: channel mask&lt;br /&gt;
PA_MVOL:	EQU $01		;master volume, 0-$3F ($3F = loudest)&lt;br /&gt;
PA_CVOL:	EQU $08		;+channel: bit 7 = left, bit 6 = right, bits 0-4 = volume 0-$1F&lt;br /&gt;
PA_STARTL:	EQU $10		;+channel: start address bits 8-15&lt;br /&gt;
PA_STARTH:	EQU $18		;+channel: start address bits 16-23&lt;br /&gt;
PA_ENDL:	EQU $20		;+channel: end address bits 8-15&lt;br /&gt;
PA_ENDH:	EQU $28		;+channel: end address bits 16-23&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Full list of defines [[YM2610 ASM defines|here]])&lt;br /&gt;
&lt;br /&gt;
Registers marked &amp;quot;+channel&amp;quot; exist once per channel: add the channel number (0-5) to the base address. For example, the start address low register of CH3 is PA_STARTL+2 = $12. In PA_CTRL, bit 0 is CH1 and bit 5 is CH6, so several channels can be keyed on or off with a single write.&lt;br /&gt;
&lt;br /&gt;
===Writing to the YM2610===&lt;br /&gt;
The YM2610 cannot accept a new write while it is busy. Bit 7 of the status register (read from port $04) is set while it is busy. Polling it before each write is the safe choice on real hardware; code that relies on fixed delays may work in an emulator and fail on a real board.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
	ORG	$0018&lt;br /&gt;
	jp	WritePortB		;RST $18 vector (only 8 bytes available here, so jump)&lt;br /&gt;
&lt;br /&gt;
;Write E to YM2610 port B register D (ADPCM-A, FM channels 3-4)&lt;br /&gt;
;Destroys: nothing&lt;br /&gt;
WritePortB:&lt;br /&gt;
	push	af&lt;br /&gt;
WPB_wait1:&lt;br /&gt;
	in	a,($04)			;status 0&lt;br /&gt;
	rlca				;busy flag -&amp;gt; carry&lt;br /&gt;
	jr	c,WPB_wait1&lt;br /&gt;
	ld	a,d&lt;br /&gt;
	out	($06),a			;register number&lt;br /&gt;
WPB_wait2:&lt;br /&gt;
	in	a,($04)&lt;br /&gt;
	rlca&lt;br /&gt;
	jr	c,WPB_wait2&lt;br /&gt;
	ld	a,e&lt;br /&gt;
	out	($07),a			;value&lt;br /&gt;
	pop	af&lt;br /&gt;
	ret&lt;br /&gt;
&lt;br /&gt;
;Write E to YM2610 port A register D (SSG, ADPCM-B, FM channels 1-2, flag control)&lt;br /&gt;
WritePortA:&lt;br /&gt;
	push	af&lt;br /&gt;
WPA_wait1:&lt;br /&gt;
	in	a,($04)&lt;br /&gt;
	rlca&lt;br /&gt;
	jr	c,WPA_wait1&lt;br /&gt;
	ld	a,d&lt;br /&gt;
	out	($04),a&lt;br /&gt;
WPA_wait2:&lt;br /&gt;
	in	a,($04)&lt;br /&gt;
	rlca&lt;br /&gt;
	jr	c,WPA_wait2&lt;br /&gt;
	ld	a,e&lt;br /&gt;
	out	($05),a&lt;br /&gt;
	pop	af&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Playing a sample===&lt;br /&gt;
Example: play V ROM $000000-$00FFFF on CH1, centred, at maximum volume. The start and end addresses must be written before the channel is keyed on. The master volume is global, so it usually only needs to be set once, at driver initialisation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
;playback parameters&lt;br /&gt;
CH:		EQU 0			;channel 0-5 (0 = CH1)&lt;br /&gt;
MVOL:		EQU $3F			;master volume&lt;br /&gt;
CVOL:		EQU $C0+$1F		;left + right, channel volume $1F&lt;br /&gt;
START_ADDR:	EQU $000000		;first byte of the sample in V ROM&lt;br /&gt;
END_ADDR:	EQU $00FFFF		;last byte of the sample (inclusive)&lt;br /&gt;
&lt;br /&gt;
PlayADPCMA:&lt;br /&gt;
	ld	de,(PA_MVOL&amp;lt;&amp;lt;8)+MVOL&lt;br /&gt;
	rst	$18&lt;br /&gt;
	ld	de,((PA_CVOL+CH)&amp;lt;&amp;lt;8)+CVOL&lt;br /&gt;
	rst	$18&lt;br /&gt;
	ld	de,((PA_STARTL+CH)&amp;lt;&amp;lt;8)+((START_ADDR&amp;gt;&amp;gt;8)&amp;amp;$FF)&lt;br /&gt;
	rst	$18&lt;br /&gt;
	ld	de,((PA_STARTH+CH)&amp;lt;&amp;lt;8)+((START_ADDR&amp;gt;&amp;gt;16)&amp;amp;$FF)&lt;br /&gt;
	rst	$18&lt;br /&gt;
	ld	de,((PA_ENDL+CH)&amp;lt;&amp;lt;8)+((END_ADDR&amp;gt;&amp;gt;8)&amp;amp;$FF)&lt;br /&gt;
	rst	$18&lt;br /&gt;
	ld	de,((PA_ENDH+CH)&amp;lt;&amp;lt;8)+((END_ADDR&amp;gt;&amp;gt;16)&amp;amp;$FF)&lt;br /&gt;
	rst	$18&lt;br /&gt;
	ld	de,(PA_CTRL&amp;lt;&amp;lt;8)+(1&amp;lt;&amp;lt;CH)	;key on&lt;br /&gt;
	rst	$18&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keying on a channel that is already playing restarts it from its start address. When the channel reaches its end address it stops on its own and sets its end flag; there is no looping.&lt;br /&gt;
&lt;br /&gt;
===Stopping a sample===&lt;br /&gt;
Writing PA_CTRL with bit 7 set stops (dumps) the channels selected in bits 0-5:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
StopADPCMA:&lt;br /&gt;
	ld	de,(PA_CTRL&amp;lt;&amp;lt;8)+$80+(1&amp;lt;&amp;lt;CH)	;dump CH&lt;br /&gt;
	rst	$18&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Writing $BF stops all six channels.&lt;br /&gt;
&lt;br /&gt;
===End flags===&lt;br /&gt;
The end flags of the ADPCM-A channels can be read in bits 0-5 of status 1 (port $06); bit 7 is the ADPCM-B end flag. A flag stays set until it is cleared through the flag control register $1C on port A. Writing 1 to a bit clears and masks that flag, and writing 0 unmasks it again so it can be set by the next sample end.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
;Z flag clear on return if CH has finished playing&lt;br /&gt;
CheckADPCMAEnd:&lt;br /&gt;
	in	a,($06)			;status 1&lt;br /&gt;
	and	1&amp;lt;&amp;lt;CH&lt;br /&gt;
	ret&lt;br /&gt;
&lt;br /&gt;
;Clear the end flag of CH&lt;br /&gt;
ClearADPCMAEnd:&lt;br /&gt;
	ld	de,($1C&amp;lt;&amp;lt;8)+(1&amp;lt;&amp;lt;CH)	;clear and mask&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,($1C&amp;lt;&amp;lt;8)+$00		;unmask&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ADPCM-B==&lt;br /&gt;
The YM2610 has one ADPCM-B channel. It plays 4-bit ADPCM samples at a variable rate, from about 1.85 kHz to 55.5 kHz, and can loop. This makes it suited to music, longer ambience and voice. Like ADPCM-A, samples are addressed in 256-byte units with an inclusive end address. Depending on the cartridge board, ADPCM-B samples are read from the same V ROM as ADPCM-A or from a separate ROM.&lt;br /&gt;
&lt;br /&gt;
The ADPCM-B registers are on YM2610 &#039;&#039;&#039;port A&#039;&#039;&#039;: the Z80 writes the register number to port &#039;&#039;&#039;$04&#039;&#039;&#039; and the value to port &#039;&#039;&#039;$05&#039;&#039;&#039; (see WritePortA above).&lt;br /&gt;
&lt;br /&gt;
Definitions of [[YM2610_registers#ADPCM-B part|ADPCM-B registers]]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
;ADPCM-B register defines (YM2610 port A: address $04, data $05)&lt;br /&gt;
PB_CTRL1:	EQU $10		;bit 7 = start, bit 4 = repeat, bit 0 = reset&lt;br /&gt;
PB_CTRL2:	EQU $11		;bit 7 = left, bit 6 = right&lt;br /&gt;
PB_STARTL:	EQU $12		;start address bits 8-15&lt;br /&gt;
PB_STARTH:	EQU $13		;start address bits 16-23&lt;br /&gt;
PB_ENDL:	EQU $14		;end address bits 8-15&lt;br /&gt;
PB_ENDH:	EQU $15		;end address bits 16-23&lt;br /&gt;
PB_DELTAL:	EQU $19		;Delta-N (playback rate) low byte&lt;br /&gt;
PB_DELTAH:	EQU $1A		;Delta-N high byte&lt;br /&gt;
PB_VOL:		EQU $1B		;volume, 0-$FF ($FF = loudest)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Playback rate===&lt;br /&gt;
The playback rate is set by the 16-bit Delta-N value:&lt;br /&gt;
&lt;br /&gt;
 rate = 55.5 kHz × Delta-N / 65536&lt;br /&gt;
 Delta-N = rate × 65536 / 55555&lt;br /&gt;
&lt;br /&gt;
For example, a sample recorded at 22050 Hz needs Delta-N = 26011 ($659B), and one at 11025 Hz needs 13006 ($32CE). Changing Delta-N while the sample plays changes its pitch, which can be used to play one sample at different notes.&lt;br /&gt;
&lt;br /&gt;
===Playing a sample===&lt;br /&gt;
Example: play V ROM $100000-$13FFFF on ADPCM-B at 22050 Hz, centred, at maximum volume. All parameters must be written before the start bit is set. The pan bits in PB_CTRL2 must be set, otherwise nothing is heard.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
;playback parameters&lt;br /&gt;
B_START:	EQU $100000		;first byte of the sample in V ROM&lt;br /&gt;
B_END:		EQU $13FFFF		;last byte of the sample (inclusive)&lt;br /&gt;
B_DELTA:	EQU $659B		;22050 Hz&lt;br /&gt;
B_VOL:		EQU $FF&lt;br /&gt;
B_PAN:		EQU $C0			;left + right&lt;br /&gt;
&lt;br /&gt;
PlayADPCMB:&lt;br /&gt;
	ld	de,(PB_CTRL1&amp;lt;&amp;lt;8)+$01	;reset, in case a sample is playing&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_CTRL1&amp;lt;&amp;lt;8)+$00&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_CTRL2&amp;lt;&amp;lt;8)+B_PAN&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_STARTL&amp;lt;&amp;lt;8)+((B_START&amp;gt;&amp;gt;8)&amp;amp;$FF)&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_STARTH&amp;lt;&amp;lt;8)+((B_START&amp;gt;&amp;gt;16)&amp;amp;$FF)&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_ENDL&amp;lt;&amp;lt;8)+((B_END&amp;gt;&amp;gt;8)&amp;amp;$FF)&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_ENDH&amp;lt;&amp;lt;8)+((B_END&amp;gt;&amp;gt;16)&amp;amp;$FF)&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_DELTAL&amp;lt;&amp;lt;8)+(B_DELTA&amp;amp;$FF)&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_DELTAH&amp;lt;&amp;lt;8)+(B_DELTA&amp;gt;&amp;gt;8)&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_VOL&amp;lt;&amp;lt;8)+B_VOL&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_CTRL1&amp;lt;&amp;lt;8)+$80	;start ($90 = start with repeat)&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the repeat bit set ($90), the sample loops from its end address back to its start address until it is stopped. Only the whole start-to-end range can loop; there is no separate loop point.&lt;br /&gt;
&lt;br /&gt;
===Stopping a sample===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
StopADPCMB:&lt;br /&gt;
	ld	de,(PB_CTRL1&amp;lt;&amp;lt;8)+$01	;reset&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,(PB_CTRL1&amp;lt;&amp;lt;8)+$00&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===End flag===&lt;br /&gt;
The ADPCM-B end flag is bit 7 of status 1 (port $06), and it is cleared through bit 7 of the flag control register $1C on port A, the same way as the ADPCM-A flags:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;z80&amp;quot;&amp;gt;&lt;br /&gt;
;Z flag clear on return if ADPCM-B has finished playing&lt;br /&gt;
CheckADPCMBEnd:&lt;br /&gt;
	in	a,($06)			;status 1&lt;br /&gt;
	and	$80&lt;br /&gt;
	ret&lt;br /&gt;
&lt;br /&gt;
ClearADPCMBEnd:&lt;br /&gt;
	ld	de,($1C&amp;lt;&amp;lt;8)+$80		;clear and mask&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ld	de,($1C&amp;lt;&amp;lt;8)+$00		;unmask&lt;br /&gt;
	call	WritePortA&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ADPCM-A demo==&lt;br /&gt;
&lt;br /&gt;
An interactive demo with source files can be found [http://smkdan.eludevisibility.org/neo/adpcma_demo2.zip here].&lt;br /&gt;
&lt;br /&gt;
[[Category:Code]]&lt;br /&gt;
[[Category:Sound Code]]&lt;/div&gt;</summary>
		<author><name>Eaglesoftware777</name></author>
	</entry>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=Development_tools&amp;diff=9338</id>
		<title>Development tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=Development_tools&amp;diff=9338"/>
		<updated>2026-09-27T03:46:28Z</updated>

		<summary type="html">&lt;p&gt;Eaglesoftware777: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
==68000==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Assemblers&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| [http://john.ccac.rwth-aachen.de:8000/as/ AS] || Alfred Arnold, et al || Multi-target assembler || (multiple) || Provided as source code and binaries (Windows, DOS) || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://sun.hasenbraten.de/vasm/ vasm] || Volker Barthelmann, et al || Multi-target assembler || (multiple) || Provided as source code&amp;lt;br/&amp;gt;&amp;quot;official&amp;quot; binaries are for older versions || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| JAS || Charles Doty, Paul Lee, Michael Hope || Modified version of AS || Windows || (base AS version unknown; binary is circa 1999/12/30) || [[File:JAS.zip]]&lt;br /&gt;
|-&lt;br /&gt;
| Maccer || Michael Hope || Pre-processor for AS-series assemblers || (multiple) || Provided as source code and Windows binary || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://gendev.spritesmind.net/page-macX.html MaccerX] || Kaneda || Updated version of Maccer || (multiple) || Provided as source code and Windows binary; added support for XGCC (gcc) and comments || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| SNASM68K || S.N. Systems || 680x0 assembler || Windows || &amp;amp;nbsp; || [http://segaretro.org/SNASM68K SNASM68K at Sega Retro]&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Modified version by Nemesis)&amp;lt;/small&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Compilers&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| NeoDev kit || Fabrice Martinez, Jeff Kurtz, et al || GCC compiler and library || (multiple) || &amp;amp;nbsp; || [[File:NeoDev001.zip]]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/docs/DEPENDENCIES.md NeoGeoSDK toolchain] || Eagle Software || m68k-unknown-elf GCC cross compiler (crosstool-NG build) with C and C++ support, plus cross-GDB || Linux, WSL, Windows || Part of [[NeoGeoSDK]]. Linux/WSL use the prebuilt &amp;lt;code&amp;gt;x-tools&amp;lt;/code&amp;gt; bundle from the release page; Windows uses a SysGCC-style m68k-elf GCC via &amp;lt;code&amp;gt;MakefileWin32.mak&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;M68K_ELF_ROOT&amp;lt;/code&amp;gt; selects the location). See also [https://github.com/eaglesoftware777/neogeosdk/blob/main/docs/GDB_GUIDE.md GDB guide] || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Disassemblers&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| IRA || Tim Ruehsen, ported by Antirad || Intelligent ReAssembler for M680x0 || (multiple) || PC port of an Amiga app; provided as source (&amp;quot;PC&amp;quot;) and binary (Windows) || [[File:Ira.zip]]&lt;br /&gt;
|-&lt;br /&gt;
| unidasm || MAMEdev || Universal Disassembler || (multiple) || Included with the Windows MAME distribution; can be built from source || &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Z80==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Assemblers&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| [http://john.ccac.rwth-aachen.de:8000/as/ AS] || Alfred Arnold, et al || Multi-target assembler || (multiple) || Provided as source code and binaries (Windows, DOS) || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://sun.hasenbraten.de/vasm/ vasm] || Volker Barthelmann, et al || Multi-target assembler || (multiple) || Provided as source code&amp;lt;br/&amp;gt;&amp;quot;official&amp;quot; binaries are for older versions || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/vhelin/wla-dx WLA DX] || Ville Helin, et al || Multi-target assembler || (multiple) || Provided as source code. Used (wla-z80 / wlalink) to build the [[NeoGeoSDK]] sound driver || [http://www.niksula.cs.hut.fi/~tursas/wla/wladx_binaries_20040822.zip WLA-DX 9.2 Win32 binaries]&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.nongnu.org/z80asm/ z80asm] || Bas Wijnen (and others?) || Z80 assembler || (multiple) || Provided as source code || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Compilers&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| ZCC || Ken Yap, et al || Z80 development package with C compiler || (multiple) || Provided as source code and binaries (Windows); circa January 1996 || [[File:zcc096.zip]]&lt;br /&gt;
|-&lt;br /&gt;
| [http://sdcc.sourceforge.net/ SDCC] || Sandeep Dutta, et al || &amp;quot;Small Device C Compiler&amp;quot; || (multiple) || Provided as source code and binaries (various platforms) || [http://sdcc.sourceforge.net/snap.php Snapshot Builds]&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.z88dk.org/forum/ z88dk] || (many people) || z80 C cross compiler with assembler/linker || (multiple) || Provided as source code and binaries (Windows, Mac) || [http://nightly.z88dk.org/?C=M;O=D Nightly Builds]&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Hit escape as soon as you see the links for &amp;quot;latest&amp;quot;)&amp;lt;/small&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk z80c-special] || Eagle Software || Experimental Z80 C compiler || (multiple) || Part of [[NeoGeoSDK]]; used for the experimental C port of the sound driver (&amp;lt;code&amp;gt;make m1rom-c&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;make compare-driver&amp;lt;/code&amp;gt;). The assembler driver remains the release path || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Disassemblers&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| DASM || Charles Doty || Z80 disassembler || DOS || Source code and binary included. || [[File:dasmz80.zip]]&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.inkland.org.uk/dz80/ DZ80] || Inkland || Z80 disassembler || (multiple) || Provided as source code (command line version) and binaries (DOS command line, Windows GUI) || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| unidasm || MAMEdev || Universal Disassembler || (multiple) || Included with the Windows MAME distribution; can be built from source || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Z80DASM || ? || Z80 disassembler || Windows || Binary || http://trd.speccy.cz/sbor/Z80DASM.ZIP&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Source Editors==&lt;br /&gt;
There are a lot of source code editors out there... Use whatever you&#039;re comfortable with (hopefully one with 68000 and Z80 syntax highlighting).&lt;br /&gt;
&lt;br /&gt;
==Sound and Music==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Music Drivers and Tools&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| [[MVSTracker]] || Ivan Mackintosh || FM tracker || Windows || [http://www.archaic.fr/interviews/interview-jeff-kurtz-repond-a-nos-questions/3/ Z80 driver does not work on hardware] || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://gendev.spritesmind.net/page-mvst.html MVSTracker Suite] || Pascal Bosquet, Kaneda || Modified version of MVSTracker || Windows || supports Mega Drive as well. Neo-Geo driver still doesn&#039;t work on hardware. || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/sound/SOUND_DRIVER_GUIDE.txt NeoGeoSDK sound driver] || Eagle Software || Z80 YM2610 sound driver (&amp;lt;code&amp;gt;sound/driver/driver.asm&amp;lt;/code&amp;gt;): FM, SSG, ADPCM-A, ADPCM-B || (multiple) || Part of [[NeoGeoSDK]]; assembled with WLA DX. Real-time FM tempo, LFO, panning, noise and CSM control from the 68000; fade engine; recorded voice bank driven by &amp;lt;code&amp;gt;speakText()&amp;lt;/code&amp;gt;. Written for real-hardware compatibility || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/docs/SOUND_STUDIO_GUIDE.md Sound Studio] || Eagle Software || GUI for the audio pipeline (&amp;lt;code&amp;gt;sound/sound_studio.py&amp;lt;/code&amp;gt;): FM patch editor, MML composer with piano roll, SSG preset editor, ADPCM sample manager with waveform view, YM2610 channel simulator, mix and ROM views || Linux, Windows || Part of [[NeoGeoSDK]]; Python 3 + PyQt6, numpy, scipy. Front end for the same scripts the Makefile calls || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/sound/mml/readme NeoGeoSDK MML / FM / SSG compilers] || Eagle Software || Compile MML music, FM tracks and patch banks, and SSG tracks and presets into driver tables for the M1 ROM || (multiple) || Part of [[NeoGeoSDK]]; Python. Make targets &amp;lt;code&amp;gt;mml&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fmpatches&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ssg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ssgconfig&amp;lt;/code&amp;gt; || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Sound Editors&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.goldwave.com/release.php GoldWave] || GoldWave Inc. || commercial sound editor || Windows || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.sonycreativesoftware.com/soundforgesoftware Sound Forge] || Sony || commercial sound editor || Windows, Mac || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://audacity.sourceforge.net/ Audacity] || Audacity developers || open-source sound editor || (multiple) || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Sound Encoders&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/freem/adpcma ADPCM-A encoder] || freem || Command-line ADPCM-A encoder || (multiple) || Provided as source code and binary (Windows) || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.smspower.org/forums/11965-VGMLoggingWithOtherEmulators?start=200#66597 ADPCM-B encoder] || ValleyBell and Fred/FRONT || Command-line ADPCM-B encoder || (multiple) || Provided as source code and binary (Windows) || [[File:ADPCM_Encode.zip]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Neo Sound Builder]] || Jeff Kurtz/Neobitz || GUI V ROM/PCM file creator || Windows || ADPCM-A only || [https://www.facebook.com/Neobitz/photos/a.462349983789893.110879.221161891242038/1093044660720419/?type=3 announcement post]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/sound/samples/readme NeoGeoSDK ADPCM encoder] || Eagle Software || WAV to ADPCM-A / ADPCM-B encoder and V ROM builder || (multiple) || Part of [[NeoGeoSDK]]; cross-platform Python, SoX optional. Pre-roll ramp reduces the click at sample start. Make targets &amp;lt;code&amp;gt;samples&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vrom&amp;lt;/code&amp;gt; || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Graphics==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Graphics Viewers and Editors&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| [[YY-CHR]] || YY || multi-format tile editor || Windows || FIX files require plugin (YY-CHR.NET only, see below); Sprites need conversion (see tools below) || [http://www.romhacking.net/utils/119/ YY-CHR 0.99]&lt;br /&gt;
|-&lt;br /&gt;
| NGFX || blastar || Fix, Sprite, TITLE_*.SYS viewer/editor; LOGO_*.SYS viewer || Windows || WIP; not yet released. || [https://www.romhacking.net/download/utilities/1175/]&lt;br /&gt;
|-&lt;br /&gt;
| neospriteviewer || Matt Greer || S and C ROM tile viewer || Web || &amp;amp;nbsp; || [https://neospriteviewer.mattgreer.dev site]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/docs/ARTBOX_PIPELINE.md Artbox Studio] || Eagle Software || GUI for the graphics pipeline (&amp;lt;code&amp;gt;artbox/artbox_studio.py&amp;lt;/code&amp;gt;): C ROM tile viewer, sprite designer with C export, hitbox editor, 16-colour paint editor, pipeline runner, movement and level designers, ROM inventory, asset-rule editor || Linux, Windows || Part of [[NeoGeoSDK]]; Python 3 + PyQt6. Front end for the Artbox scripts || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk NeoGeoSDK GIMP plugins] || Eagle Software || GIMP plugins for preparing Neo Geo art || (multiple) || Part of [[NeoGeoSDK]] || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|-&lt;br /&gt;
!colspan=6 style=&amp;quot;background-color:#ccc&amp;quot;|Graphics Converters and Tools&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| [[DATLib]] graphics tools || HPMAN || Tools used to process and display graphics on Neo-Geo. || Windows || Animator, BuildChar, CharSplit, Framer || [https://www.dropbox.com/s/wqviye5xxzktr6y/DATlib_0.3.rar?dl=0 download]&lt;br /&gt;
|-&lt;br /&gt;
| [[NGGTool|NeoGeo Graphics ToolSuite]] || evo || Tool to convert between SNES/SFC and Neo-Geo graphics. || Windows  || Fix conversion is botched (see page for details) || [http://furrtek.free.fr/noclass/neogeo/nggts.zip NGGTS]&lt;br /&gt;
|-&lt;br /&gt;
| Sprite graphics converter || IQ || Converts MVS graphics (.c*) to CD graphics (.SPR). || Windows || &amp;amp;nbsp; || [http://furrtek.free.fr/noclass/neogeo/gfxmvstocd.zip MVS to CD sprite converter]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/freem/NeoSpriteConv Neo-Geo Sprite Converter] || freem || Convert 4BPP SMS/GG/WSC graphics to Neo-Geo format. || (multiple) || Provided as source code and binary (Windows)&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;Further work required for converting to Cart (split files by words (2 bytes)) and CD (byteswap file)-usable files.&amp;lt;/small&amp;gt; || [http://ajworld.net/neogeodev/utils/neosprconv.zip main download]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/Kannagi/Neoconvert Neoconvert] || Kannagi || Convert PNG to rom Cx with map, palette and HiColor. || Windows,Linux || &amp;amp;nbsp; || [https://github.com/Kannagi/Neoconvert download]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/Kannagi/Neoextract Neoextract] || Kannagi || extract rom Cx or s1 to bmp. || Windows,Linux || &amp;amp;nbsp; || [https://github.com/Kannagi/Neoextract download]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/city41/sromcrom sromcrom] || Matt Greer || Generate S and C ROMs from images, generates corresponding source code as well || cross platform || &amp;amp;nbsp; || [https://github.com/city41/sromcrom download]&lt;br /&gt;
|-&lt;br /&gt;
| [https://neo-source.com/index.php?topic=4180.msg37936 buildobj] || iq_132 || Compress / Decompress NeoGeo CD OBJ files || Windows || &amp;amp;nbsp; || [https://neo-source.com/index.php?topic=4180.msg37936 buildobj]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/docs/ARTBOX_PIPELINE.md Artbox] || Eagle Software || PNG to C ROM sprite converter (&amp;lt;code&amp;gt;artbox/img2neo.py&amp;lt;/code&amp;gt;) with perceptual quantisation in CIE-Lab on the Neo Geo&#039;s 5-bit colour lattice; rule-driven through &amp;lt;code&amp;gt;artbox/assets.cfg&amp;lt;/code&amp;gt; || (multiple) || Part of [[NeoGeoSDK]]; Python 3. Void-and-cluster blue-noise dithering, per-tile and master sprite palettes, sprite halo removal, content-preserving screen fit; generates &amp;lt;code&amp;gt;sprite_meta.h&amp;lt;/code&amp;gt; for 68000 code || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/docs/ARTBOX_PIPELINE.md NeoGeoSDK fixtiles] || Eagle Software || PNG to 128 KB S1 FIX ROM || (multiple) || Part of [[NeoGeoSDK]]; Python 3. Make target &amp;lt;code&amp;gt;sfix&amp;lt;/code&amp;gt; || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Other Tools==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Name !! Author(s) !! Description !! Platform(s) !! Notes !! Download&lt;br /&gt;
|-&lt;br /&gt;
| MemCardTool || Fabrice Martinez || Memory card manager || Windows || &amp;amp;nbsp; || [[File:memcardtool.zip]]&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/freem/romwak ROMwak] || Jeff Kurtz, ported by freem || Binary image manipulation tool || (multiple) || Provided as source code and binary (Windows) || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/eaglesoftware777/neogeosdk/blob/main/docs/MAKEFILE_INTEGRATION.md NeoGeoSDK ROM packaging] || Eagle Software || P1 ROM crop to 512 KB and byte-swap; MAME software-list (&amp;lt;code&amp;gt;hash_eagle/neogeo.xml&amp;lt;/code&amp;gt;) regeneration with CRC/SHA1; &amp;lt;code&amp;gt;make dist&amp;lt;/code&amp;gt; release packaging || (multiple) || Part of [[NeoGeoSDK]]; lets homebrew ROM sets load in MAME without hand-editing hash files || [https://github.com/eaglesoftware777/neogeosdk GitHub]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Code]]&lt;/div&gt;</summary>
		<author><name>Eaglesoftware777</name></author>
	</entry>
</feed>