|Lesson P1 - Basic Firmware Text functions|
|Lesson P2 - More Text Functions, Improvements... and the Sam Coupe!|
|Lesson P3 - Bitmap graphics on the Amstrad CPC and Enterprise 128|
|Lesson P4 - Bitmap graphics on the ZX Spectrum and Sam Coupe|
|Lesson P5 - Bitmap graphics on the TI-83 and MSX|
|Lesson P6 - Keyreading on the Amstrad CPC, ZX Spectrum and Sam Coupe|
|Lesson P7 - Keyreading on the MSX, Enterprise and TI-83|
|Lesson P8 - Tilemap graphics on the Sega Master System & Game Gear|
|Lesson P9 - Tilemap graphics on the Gameboy and Gameboy Color|
|Lesson P10 - Tilemap graphics on the MSX1|
|Lesson P11 - Tilemap graphics on the MSX2|
|Lesson P12 - Joypad reading on Master System,GameGear, Gameboy and Gameboy Color|
|Lesson P13 - Palette definitions on the Amstrad CPC and CPC+|
|Lesson P14 - Palette definitions on the Enterprise and Sam Coupe|
|Lesson P15 - Palette definitions on the MSX2 and V9990|
|Lesson P16 - Palette definitions on the Sega Master System and Game Gear|
|Lesson P17 - Palette definitions on the Gameboy and Gameboy Color|
|Lesson P18 - Making Sound with the AY on the Amstrad CPC, MSX,ZX Spectrum.... and NeoGeo + Atari ST!!|
|Lesson P19 - Sound on the Elan Enterprise|
|Lesson P20 - Sound on the Sam Coupe|
|Lesson P21 - Sound on the Gameboy and GBC|
|Lesson P22 - Sound with the SN76489 on the Master System, GameGear, Megadrive (Genesis) and BBC Micro!|
|Lesson P23 - Sound with the 'Beeper' on the ZX Spectrum and Apple II|
|Lesson P24 - Bankswitching and hardware detection on the Amstrad CPC|
|Lesson P25 - Bankswitching and hardware detection on the MSX|
|Lesson P26 - Bankswitching and hardware detection on the ZX Spectrum|
- Hardware Sprites on the Master System / Game Gear and MSX1!
SMS /GG sprites are much easier, so we'll take a look at them, and also look at the MSX1 as a bonus!
|Hardware Sprites on the SMS / GG|
|The SMS/GG memory
supports up to 64 sprites,
There are 3 memory bytes for each hardware sprite, but they are not consecutive!
Look at sprite 0 - shown in black... it's X co-ordinate is at &3F00 ... it's Y co-ordinate is at &3F80... it's Sprite Number is at &3F81
Sprite Numbers can come from memory address &2000, or &0000 (The Tile Patterns) depending on the setting of register &06... we'll be using the Tile patterns for simplicity in our example!
It's important to note that the sprites ALWAYS use colors 16-31
Unfortunately there is no way to flip sprites, so we will need a pair of sprites to allow a player sprite to turn around!
|Sprite Attribute Table (In VRAM)
Attribute Table is
held in VRAM so we have to access it using OUT commands, we'll use our
PrepareVram command to set the correct memory address..
When we want to set a sprite, we first set the Y co-ordinate in the first 63 bytes of the table, then we set the X pos and the Tile number
|We make up our 16x16 sprite using 4 separate sprites
SMS sprites can be read from pattern data, or from a seperate bank...
in the same ways, the Tilemap can use the same colors as the sprites,
or a separate palette...
These examples will use the simplest option - sharing both between sprites and tilemap - of course, if you're creating a big game, you'll want to separate them to make your game look the best!
|Hardware Sprites on the MSX|
On the MSX the system is capable of 32 sprites onscreen... but just 4 can be on the same line... The sprites are 2 color.
The sprites patterns can be 8x8 or 16x16 and can be 'doublesize' 2x scaled , but this is declared at the screen level in register 0... so you cannot have some sprites 8x8 regular, and others 16x16 doublesize
Each Sprite is defined by 4 concecutive bytes in the sprite attribute table (usually at &1B00) containing a Y and X co-ordinate, a Pattern number (corresponding to a tile in the sprite data at &3800)
in 16x16 mode patterns will be 4x size, and the tilenumber will only use the top 6 bits %111111-- ... the bottom two will be ignored
when X,Y= 0,0 the sprite will be in the top corner of the drawable area, but will be completely visible.
if you want to clip The Y lines of the sprite, use Y positions of 255 or less - this is effectively -1 or lower
Because the screen is 256 pixels wide, we cannot do this for X Co-ordinates - instead we use the top bit of the 'Color' attribute of each sprite (only the bottom nibble defines color)... When the top bit is 1 - the sprite will be shifted 32 pixels left, so 0,0 will now be -32,0
the order of the 8x8 chunks in 16x16 sprite mode is possibly a little odd...imagine 4 8x8 blocks in a 16x16 sprite... they need to be in the following order:
|We need to actually
sprites, by setting SPD to 0 in Register 8... it's important to notice
that this will make the MSX graphics slightly slower
Register 1 controls the size and scale of the sprites, so can be used for 16x16 or doublesize sprites.
|To set the MSX
parameters, we just need to set our write address to the
relating to the sprite we want to change.
Then we just OUT the 4 bytes of data to that address... the address increments automatically with each write.
|We can make up a 16x16 sprite using 4 8x8 sprites
we can also use a single sprite - and doublesize for a bigger sprite!
MSX 2 is capable of much more powerful sprites, and sprites can be
bit-combined to allow a lot of colours! - and that's just hardware
sprites, but hardware sprites slow down the hardware by about 20% - and
are still quite limited
Chibiakumas uses software sprites using 'area copying' VDP commands - meaning no limit to the number of sprites onscreen - just a reduction in speed!
- Hardware Sprites on the CPC+
The CPC Plus is capable of better palettes, but it's prime feature is sixteen 16 color 16x16 sprites... These are separate from screen mode, so are 16 color even in 4 color mode 1...
Lets take a look!
|Like most CPC+ features, Sprites are set and altered by
writing to ASIC ram after turning on Plus features,
We've discussed how to do this before in the lesson on CPC+ Palettes
Each sprite is 16x16 making 128 bytes... but the definitions only use the bottom nibble of each address (The top nibble of the sprite data registers cannot store data!), so each sprite is defined by 256 bytes of bitmap data.
as well as bitmap data, there is an address storing the X and Y co-ordinate - and a 4 bit 'Magnification', 2 width bits and 2 height bits
A magnification of 0 is a disabled sprite, a magnification of 1x1 is a 'Mode 2' sized pixel sprite... 2x1 is 'Mode 1'... and so on
So 'Resolution' setting of 9 will be a normal Mode 1 sized sprite
CPC+ sprites are always 16 color, and use an 'extra' 16 colors to the normal palette... these palette definitions are held in the range &6422-&643F
you don't know how to turn on PLUS features, see the CPC+ Palette
lesson of these tutorials....
Also, just remember the ASIC ram uses the area &4000-&7FFF , so your program code and sprite data have to be somewhere else!
|Before we can do
anything with a sprite, we need to set it's bitmap data!
We need to write 256 nibbles to 256 addresses in ASIC ram to set the sprite bitmap... but that's only 128 bytes of data!
To save RAM, we'll 'Compress' two nibbles into the same byte, and unwrap them when we write to the ASIC ram...
We'll also 'misuse' the stack pointer to PUSH data into the asic ram more quickly to save time... unfortunately it's still quite slow, so may mess up interrupts, so we'll do the job in 4 chunks so interrupts can still run frequently
This is the code used by ChibiAkumas to handle CPC+ Sprites!... This is why the bitmap copy is done in 4 parts - as Interrupts had to be handled quickly to keep the 'raster color switching' reliable.
Because we're using PUSH commands, we going backwards, so we need to pass the LAST BYTE of the sprite data in HL
Sprites have a LOT of data, and we can't just change a pointer to
change the 'image' of a sprite... This means it may be slow to animate
them - at least compared to other systems with hardware sprites...
That said, the CPC+ sprites are big and colorful compared to other 8 bit systems!
|Now our sprite has
an image, we need to position it on the screen, and give it a scale!
If we want our Sprite to be sized with mode 1 pixels, we need to set it's scale to '9'
To allow a single byte to define an X position, the X co-ordinate is defined in Mode 0 pixels, however you can change this if you want better definition..
Negative numbers can be used to clip a sprite to have it go off the Top/Left of the screen
It is not possible to have a sprite in the border areas of the screen - the sprites are drawn in the normal bitmap area of the screen.
|Now we have our
routines to do the work, we need to use them!
To start we need to turn on the plus features...
Then we need to load in the bitmap data - we add 127 to the source address, because our code works BACKWARDS from the last byte of the sprite...
Now we set a position and scale of our sprite - remember the scale cannot be 0 or it will be disabled.
Finally, we set the color, the sample sprite only uses color 3, so that's all we'll set!
|The sprite will be drawn to the screen!|
more than 16 sprites? Well, it's possible if you're REALLY clever - you
can reposition the sprites while the screen is drawing, and you will
effectively see them twice... in ChibiAkumas 2 player mode the
Heart+Scroll sprites were repositioned midscreen - so all 12 sprites
were actually just 6!
Unfortunately, it's so much work to change the bitmap data, it's not possible to use a different sprite bitmap with this method, so you'll have to be clever in your sprite use!
- Bitmap Graphics on the Camputers Lynx
The Camputers Lynx has a very unusual screen layout, it's screen memory conflicts with the normal memory, the effect of this is we cannot use the stack during the writing procedure when we have the video ram paged in.
Lets take a look at how to get graphics onscreen on the Lynx!
|8k ram bank||Seen at Addresses|
|4||Off Board Expansion|
Bank 2 / 3
|Write Green /
|Write Red /
|Write Green /
|We can't use the
drawing, so we'll define some macros to easily turn on the banks to
correctly write to the banks we want to.
This involves paging in the correct banks using port &FFFF, and locking the banks we don't actually want to write to using port &0080
however, if we don't lock either of the vram banks , we can write to All Colors more quickly, and we'll use this for our font routine!
|When it comes to
printing characters to the screen we can take advantage of a quirk of
the Lynx memory map.
We can Write to Red+Green at the same time! this means we can do two writes to &C000 and &A000 and set all 3 channels - which will save time
Because the screen memory overlaps normal memory where the stack is, we can't use the stack between the ScreenDrawAllColors and ScreenStopDrawing
|Bear in mind that while this writes to RED,
GREEN and BLUE - it also writes to ALTGREEN
Altgreen isn't used by the visible screen in this example, but depending on how you're using the screen and memory, that could be a problem for you?!
|We need a way to
get the correct memory location for writing data to the screen... we'll
pass an X,Y co-ordinate in BC...
Because it's spit into bitplanes, The Camputers screen has 8 pixels per byte, and the screen is 32 bytes wide...
Therefore we need to multiply the Ypos *32
|When we want to
show a bitmap to
the screen, we should first use the GetScreenPos to get the correct
screen destination, and set HL to the source destination of the bitmap.
We need to write to the screen 3 times, so we back up the destination pos into the IY register - we can't use the stack while we're drawing to the screen.
We use our macros to page in the graphics ram, and the LDIR command to actually do the data copy, BLUE and RED are in the same bank, we need to add &2000 to the memory address we're writing to so we can write to the RED area
once we've done the RED and BLUE channels, we page in the GREEN and do the same.
finally we repeat for the next line of the bitmap
|When we want to
make use of this
function, we need to get the screen position into DE, set the bitmap
data source in HL, set the width in IXH, and the height in lines in IXL
My AkuSprite editor can export a bitmap in the correct layout for this example and the camputers lynx
is just an example of the kind of code you can use - depending on your
exact requirements, you should modify this to do what you need..
For example the Grime Z80 port for the Lynx uses Tilemap code designed to work in 8x8 blocks, which is designed to work in the best way for one byte width blocks.
- Sound and Keyboard on the Camputers Lynx
The Keyboard and sound of the Lynx will be pretty familiar to regulars of these tutorials! The sound is basically an upgraded spectrum (With Volume levels) and the keyboard is pretty similar to the CPC or Spectrum...
Lets learn how to use them!
|Like most Z80
computers, the Lynx keyboard uses a set of ports, which represent
'rows' of the keyboard, and each
These 'rows' are relating to the electrical membrane, not keys as they appear,
The keyboard responds to all ports with a bitmask of %****XXXX 10***00* ... where XXXX is one of the ports shown
In this data, a key will be 1 if it is UP , or 0 if it's pressed down
|In practical terms,
this means we set C to 128, and B to 0... then INC B until we get
This allows us to read in the raw bit data from the keyboard... we can then use the existing Multplatform Code (Click Here) to convert raw data to letter keys (if we want)
|A beeper is a crude system, where we can define 'blips'
of sound to make up a tone
By altering the time between these 'blips' we can affect the pitch of the resulting tone!... the upside is we can make a good range of tones... the downside is, we'll pretty much have to use all our CPU power calculating the delay between the 'blips' re-sounding the blips... unlike the ZX Spectrum, however the Lynx can set volume levels using 6 bits
Sound is controlled on the lynx by port &0084 - or any port that matches the bitmask %********10***10*
This means, unlike the other options, sound will not play during normal operation... so background music will be pretty much impossible
If we want to make a distorted noise, that's pretty easy too... all we need to do is 'randomly' skip some of the 'blips'... the tone will sound rough and distorted as a result!
we're having to create the waveform ourselves here by creating high and
low peaks... it's a real pain to do, but if you're very clever you can
do some impressive stuff!
There is some sourcecode online for some ZX Spectrum 'music players' online that can play 'proper' multi-channel music using the beeper speaker if you really want to push beeper systems to the max!
|The principle of
sound is easy ...
1. Blip the speaker ( with noise if required)
2. Wait a while for the next blip
3. Repeat for the desired tone length
But the procedure is a bit of a pain! We need to calculate a good delay to keep the sound the same length whatever the tone, and we need to get some random noise to produce distorted sounds...
'ChibiSound' uses a single byte parameter in the format NVPPPPPP... where P is the pitch (0-63) V is the Volume (Low/High) and N is the Noise (On/Off)
On the Lynx we use the R register as a random source and a AND command with self modifying code to set the volume
- Playing Digital Sound with WAV on the AY!
We've looked before at normal sounds, but lets start to learn how we can convert WAV files so we can play them back on 8 bit machines for Speech and SFX!
Lets take a look!
| Most WAV files these days will be 16 bit - these will
Signed, and will end up representing a wave with values from 32768 to
-32768 - with silence being Zero.
When we play the wave file on an 8 Bit sytem, we do so by adjusting the 'Volume' of the channel to match the wave, this will recreate the waveform, and the sound!
BUT no 8 bit system has a 16 bit volume level... and memory is limited!
A system like the AY has a 4 bit volume level - so we can 'pack' our wave data into two samples per byte... but we need to convert the 16 bit values to 4 bit unsigned ones.. you can see how the wave is represented by numbers in each bit option in the diagram to the right:
|A wave file, and how it's range is represented in
different bits per sample:
|I've made a tool to
convert to 1/2/4 bit per sample wave files, but you need to prepare
your file for my program!
You can convert your sound file with Audacity, you'll want to make it as small and loud as possible, you'll also want the file to be MONO... (a stereo file can be used, but the right sound channel is ignored!)
then use the Export option
|Select the Wave signed 16-bit PCM option|
ChibiWave converter supports MONO only, if the file is stereo, the LEFT
channel will be used... files MUST be SIGNED 16 bit, but can be 22050
hz or lower... but if you have trouble, make sure your input file is
44100 hz, MONO and 16 bit as shown above!
|In these tutorials
we'll look at playing 1, 2 and 4 bit per sample sound files,
I've written a little program called ChibiWave Converter... that can convert a WAV file into a RAW (headerless) file in the correct format!
Just select a wave file, select a Bits per sample... and a Frequency DownSample... if you source file is 44100hz (CD Quality), and you use a 1/4 Downsample, the resulting file will be 11025 hz (voice quality)
The AY sound chip volume is linear, so the sample may be quiet, you can use AV Vol Boost to make it louder!
Most systems can play 4 bit samples, some like the ZX Spectrum can only play 1 bit - actually some can play higher bit depth, but that's not supported by my tool, or these tutorials, so you're on your own!
|There's no reason you can't do 3 bits per
sample too, but it's not supported in these tutorials...
It should also be noted that the code here is a 'one size fits all' solution, if you only need 4 bits per sample, you could modify it and write something far better!
|We're going to create a ChibiWave function! this will
play our wave files... it takes 4 parameters:
HL is the address of the wave data in memory
DE is the length of the wave data in bytes
A is the bit depth of the samples... values of 0/1/2 represent 1/2 or 4 bit per sample
B is the delay between each sample - increasing it slows down playback - due to the difference in the code and hardware, unfortunately the playback speed is not consistant on all systems.
|When the routine
starts, we need
to use Self Modifying code to reprogram some of the functions - we need
to use different modules to split out the sound depending on the bit
depth, and mod in the length of the pause...
We also use IX as the byte count.
|We need to init the AY to some default values, to make sure it's not playing some weird pitch in the channel we're going to use - this could make the sample sound odd!|
|This is the start
of the wave
routine... we load in a byte, and shift the first bit in from the byte
to the Accumulator - we then run 'Do4BitWav' - or one of the other
routines, as this call is modified by selfmodifying code.
|However many bits
of sample we
have, we need to bit shift them into the maximum volume position, so if
we have 1 bit, because the volume is 4 bits, we shift it left 3 times.
We then send the byte to the 'Volume' of one of the channels (via AYRegWriteQuick - see ChibiSound.asm)
Setting the volume causes a 'blip' to that volume level, doing this repeatedly creates the waveform, and we hear it as the original sample...
|We use B to pause a
while (this slows back playback rate) - this is selfmodded in
Now we decrease E, and if there are any more samples in the byte - we repeat the play routine
If there are not, we decrease IX, and if it's nonzero, we read in a new byte...
When playing is done, we turn off the sound!
some AY systems, It's possible to play multiple samples at different
volumes to increasae the bits per sample from 4 to 8 or more...
Unfortunately the Author of these tutorials is to stupid to make it
work... so if you want to look into it check out this site
|The Spectrum 128k+ also have an AY sound chip, and this code will work on those systems too... but if you want to support the 48k spectrum, you'll want to use a 1 bit per sample file, and we'll learn how to do that in a later lesson!|
- Playing Digital Sound with WAV on the CPC+ via DMA!
The CPC+ has an added function for sound - it can automatically set AY registers from a 'script' within memory without the Z80 doing anything (known as DMA - Direct Memory Access)
This means we can play a digital sound without using ANY cpu power - unfortunately the 'script' is quite large, so it takes a lot of memory...
Lets Check it out!
|Function||Format||Channel 0||Channel 1||Channel 2||Global|
2 bytes - Little Endien (LH)
|LLLLLLLL HHHHHHHH||&6C00 / 01||&6C04 / 05||&6C08 / 09|
|LOAD||&0RVV||Set AY Register R to V|
|PAUSE||&1NNN||Wait N*prescaler ticks - if we have 3+ samples that are the same we can use this to reduce the wav file size|
|REPEAT||&2NNN||Repeat command - this is like FOR I=0 to NNN|
|NOP||$4000||Do nothing this tick|
|LOOP||&4001||return to repeat point - this is like NEXT|
|INTerrupt||&4010||Cause an interrupt - Status register bit 6-4 will be set depending on current channel|
|STOP||&4020||Stop the DMA - end of the sound script|
to use DMA to play one sound sample after another - or you want to keep
filling a buffer (of calculated/decompressed samples) - you may want to
have an INT command (&4010) at the end of your list - this will
cause an RST7 call to &0038
Your interrupt handler could then check &6C0F to see if the interrupt was caused by VBLANK or the DMA and act accordingly!
|Lets actually make
the AY do something via the DMA!
We're just going to do a simple 'Beep' using channel 2 to start, but all we'll need to do is swap in a proper sample later!
This example should be compiled with Winape's internal assembler.
Because we're going to use CPC+ features, we first need to enable them, by sending the plus init sequence to the Gate Array..
Next we page in the CPC+ registers by OUTing &7FB8 to the Gate array...
We store the address of our DmaList in &6C00 (DMA Channel 0's data)
Now we turn on DMA channel 1 with the Control register at &6C0F
We now turn off the CPC+ registers by OUTing &7FA0 and return to basic...
Because we're using a DMA, the list will be processed WHILE basic is usable!
The sample DmaList
The list in this example just turns Channel 1 on, sets it to top volume, and makes a middle tone before reaching a STOP command.
|If you've been folowing these tutorials, you
should understand these commands... if not please see Lesson
P13 - we covered the CPC+ functions in that lesson
Converter can convert a WAV file for use with DMA on the CPC plus -
just select CPC+DMA
As the DMA runs at 15khz, the best quality will be provided by a downsample of 1/3, but you can use 1/4 or more if you prefer...
Note: This converter replaces sequences of the same volume with PAUSE commands - these will reduce the filesize by around 50% - but the size will vary depending on the wave data.
ChibiWave Converter will also include commands to turn on the sound at the start, and turn it off at the end - all you need to add is a STOP command...
|When we want to use the sample we just use INCBIN to
include it in our code...
In this example we've added a REPEAT (&2nnn) and a LOOP (&4001) - as we've specified a REPEAT of 2 (&4002) the wave file will play 3 times!
|If we want to slow down the sample, we can change the PRESCALER (playback speed)... 0 is the fastest... 1 will halve the speed - so should be used with Frequency Downsample of 1/6 (around 8khz)|
Prescaler only affects PAUSE commands - but as we added a load into the
data (as part of compression) it will probably work OK... techinically
the playback speed will not be even, but in practacle terms, there's no
- Playing Digital Sound with WAV on the Sam Coupe, Camputers Lynx and
The principle of playing waves on the AY are the same as other systems... all we need to do is manipulate the volume of the system... and use an appropriate bit per sample...
Lets learn how to play waves on 3 other systems
|Playing Sound Samples on the ZX Spectrum Beeper|
|The ZX spectrum
only has a 1 bit beeper... controlled by bit 4 of port &FE
As there's no point using a 4 bit sample when we can only use 1 bit, we'll use a simple version of ChibiSound that only plays 1 bit samples...
|We could convert 4 bit samples to get them to
play on the Spectrum beeper, but it would be a waste of memory!
That said if your game was going to support AY on 128k systems, and Beeper on 48k ones, it may be worth it!
|Playing Sound Samples on the Camputers Lynx|
|The Camputers lynx a 'beeper speaker'.. but unlike the
spectrum is uses a 6 bit volume level
We use port &84 to set the volume, we just need to shift the bits 2 to the left to pad the 4 bit sample out to 6 bits
|Unlike other systems, just setting the volume isn't
it wouldn't make a sound - and setting a tone won't help either - as
the frequencies are too low and will make weird squeals...
What we need to do is we need to configure the Envelope to use option B - this will make a peak in our waveform when we send the digital data
|Before we can play our waves We need to do some set
We need to enable sound, Set Envelope B and turn envelopes on,and select the Volume register for channel 2 - we have to use channel 2 as it's the one affected by the Envelope option
Because all wave writes will be to the volume register, we're just going to write the volume levels to the data register at port 255, without reselecting the volume register with port 511
|Figuring out how to make the wave play well
on the Sam Coupe was a pain in the ass!
The Author of these tutorials cheated, and disasembled the 'Megablast demo' on FRED Magazine Issue 12 (1991) to figure out how to do it right!... Remember! if you can't figure it out yourself, just steal someone elses good ideas!
|If you want to see some super impressive Sam
Coupe sound, check out SAM MOD
player by Stefan Drissen!
It's far better than the sound in this tutorial, it can handle 4 channels, and It's even open source!
- Playing Digital Sound with WAV on the Sega MasterSystem/GameGear,
Elan Enterprise and GameBoy/GBC
We've looked at most of our systems now, but there's still a few left, fortunately, it's all pretty similar, just like before we just need to switch our volume levels to get the job done...
Lets finish the job!!
|We're just covering the differences here...
so please see Lesson P35...
We covered the basics of how ChibiWave works, the concept of playing
digital sound, and how to convert wave files with ChibiWave!
|Playing Sound Samples on the Enterprise|
|The Enterprise is pretty easy, we use ports &A8
and &AC to set the Left and Right sound channel volumes
The EP128 has a 6 bit volume, but we're only using 4 bit samples,so we have to shift left by 2 bits
|Playing Sound Samples on the SMS/GG|
|The SMS/GG version
is slightly different, rather than using Self modifying code, we use IX
and IY to store our extra values...
Also rather than a direct CALL , we use a JP(IY) to execute the required sample converter.
|On the Sega Mastersystem, we just need to set the top 4 bits to %1101 to set the volume, the remaining 4 bits are the volume level|
|This version of ChibiWave will work on other
systems too... just change the 'volume command'!
Depending on your system, and what you use the registers for, you may prefer this version that can run from ROM... or the version that needs IX and IY... Remember, some systems like the speccy use IY in their firmware!
|Playing Sound Samples on the GB/GBC|
|On the Gameboy we
have to do things differently, because of the limited command set.
We use bytes of ram to simulate IX and IY - but otherwise the code is basically the same as the SMS/GG version
|Again our main code
is virtually the same, the significant change is the 'Call IY'
We have to use BC as a temporary pair, load our IY values into that, push them onto the stack, and then RETurn
The result is the same as jumping to IY
|Finally the job of
setting the volume level...
On the Gameboy our volume levels are only 3 bit - so we ignore the 4th bit of our samples,
When we set the volume levels, we need to set 3 bits of the top nibble, and 3 bits of the bottom nibble - this sets the Left and Right channels
Gameboy DOES have a digital sound channel that can play 4 bit samples -
but it uses just 32 bytes of samples (64 samples)...
In theory this could mean we could do better sound, but it seems impossible to 'stream' data into this bank - as the channel needs to be disabled when the data is updated, and we can't detect when the buffer has been played...
- Setting the CPC screen with CRTC registers
CRTC registers define the position and shape of the screen.... they allow us to do crazy things, like resize and hardware scroll the screen... they also allow page flipping - and are generally responsible for the impressive demos the CPC has gained over recent years.
Lets check out the CRTC registers and see what they can do!
|When we want to reconfigure CRTC registers we do so by
writing to the CRTC,
The CRTC registers are selected with &BCxx (where xx is the register number),
We then set the new value with &BDxx
|Reg Num||Name||Range||Bits|| Default
|&00||Horizontal Total||0-255||DDDDDDDD||63||63||63||Physical width of screen – Leave alone!|
|&01||Horizontal Displayed||0-255||DDDDDDDD||40||32||48||Logical width in Chars (8 pixels in mode 1)|
|&02||Horizontal Sync Position||0-255||DDDDDDDD||46||42||51||Logical Xpos|
|&03||Horizontal and Vertical Sync Widths||0-15,0-15||VVVVHHHH||142||134||142||Physical width of screen – Leave alone!|
|&04||Vertical Total||0-127||-DDDDDDD||38||38||38||Physical height of screen – Leave alone!|
|&05||Vertical Total Adjust||0-31||---DDDDD||0||0||0||Scanline Offset|
|&06||Vertical Displayed||0-127||-DDDDDDD||25||24||34||Logical Height in Chars (8 Pixels)|
|&07||Vertical Sync position||0-127||-DDDDDDD||30||31||35||Logical Ypos of screen|
|&08||Interlace and Skew||0-3||------DD||0||0||0||0/2=off 1/3=on – Leave alone!|
|&09||Maximum Raster Address||0-31||---DDDDD||7||7||7||Max Raster Address – Leave alone!|
|&0A||Cursor Start Raster||0-127||-DDDDDDD||0||0||0|
|&0B||Cursor End Raster||0-31||---DDDDD||0||0||0|
|&0C||Display Start Address (H)||0-63||xxPPSSOO|| 00 / 16 /
32 / 48
| 00 / 16 /
32 / 48
|12+1 / 28 /
44+1 / 60
S=Size(11=32k else 16k) O=Offset
|&0D||Display Start Address (L)||0-255||OOOOOOOO||0||0||0||O=Offset|
|&0E||Cursor Address (H)||0-63||--DDDDDD||0||0||0|
|&0F||Cursor Address (L)||0-255||DDDDDDDD||0||0||0|
|&10||Light Pen Address (H)||0-63||--DDDDDD||0||0||0||Read Only|
|&11||Light Pen Address (L)||0-255||DDDDDDDD||0||0||0||Read Only|
|We can effect a Scroll by changing
&0D (13)... each change to this register will move the screen
by one mode1 character
We can effect fine Horizontal scrolling by changing &05... and vertical scrolling with &03 - but BEWARE! these may work on the original Amstrad monitor - but people using TFT's may see the screen jump and flicker when you do this - so your game will be unplayable on their machines!... but maybe that'll learn them for not paying respect to the CTM644!
|Double buffering is great, but you may not want
to use it!
If you can redraw the screen quickly in small sections you can get away with a single buffer - this works best for 464 games (leaving 48k free for game code) and also for games with super high frame rate... Games like Dizzy and Skweek used single buffers, and this allowed more ram for sprite data while keeping 64k support
For a game like ChibiAkumas - where everything changed every frame (due to background parallax and high sprite/bullet count) two buffers were essential!
|We're going to
define a simple function called SetCRTC... it will set CRTC reg C to
We're going to use this in a little test program!
|We're not going to
look at the
program code - it's long and not particularly related to the CRTC -
what it does is let us see the changes to each register onscreen!
To use it, load "CPC_CRTC_TEST.asm" in winape and compile it.
then type Call &8000 in basic to start the program
|You should see the
screen to the right...
Note: there are some yellow and cyan lines at the bottom of the screen - these are NOT corruption - they are filled bytes of memory to show the top of the &FE00-&FFFF range
On the left are two letters - these are keys you can press to change the register - for example J and K will change the address of the start of the screen!
Try the keys - you'll see the settings in VAL (decimal) and &VL (hex) and the effect onscreen!
|Because our text
hasn't changed, Altering AddrH will make the screen look weird - we'd
need to reprogram our drawing code to accommodate our new settings to
make it all work seamlessly..
|It's very easy to
use some setting that are impossible to view, and now we can't see the
settings any more!
The tool has a Safe Mode to get around this...
Press 0 (zero)... this will turn on safe mode!
In Safe Mode, the settings you choose will be applied for an instant, and then it will flip back to the defaults - so you can see the effect of the settings you chose, and still see all the options on a normal screen
program just allows you to test what each register does - and find
suitable settings for the screen size and position you need...
Once you've done that, you'll need to reprogram your sprite, font and other drawing routines to work with the new screen position and orientation.
- Syncronized mode switches for 320x200 @ 16 color EGX graphics on the
With Imperial Mahjong, Cargosoft invented a new graphics mode...
By switching between Mode 0 and Mode 1 every single line, we can create graphics which have the colors of Mode 0, with the high resolution of mode 1...
Of course we'll need to design our graphics accordingly... but as always in these tutorials - AkuSprite Editor can do the job!
|EGX - full Screen
The Full EGX screen as we see it in the CPC, each alternate line is Mode 1/0, and the screen has been optimized so where possible the graphics have the smoothness of mode 1, but the improved color of Mode 0
| 0 part
The Mode 0 lines (even lines) have full 16 colors, and give the game better color than could be managed in Mode 1
|Mode 1 part
The Mode 1 lines (odd lines) are 4 colors - we've selected the most used 4 colors to allow us to 'blend' the mode 1 and mode 0 lines, we've also positioned the text, so that the top and bottom line of the text are mode one - allowing for smooth O's and curves in letters
|1||0||-||I||H||L||M||M||Rom / Mode||I= Interrupt mode H=High rom bank L=Low rom bank M=screen mode|
screw up our timings, you'll see something go wrong... with this
example, if the 'Mode Flip' doesn't happen at the end of the line,
you'll see no mode changes at all (as both happen on the same line,
cancellinjg each other out before the CRTC sees either!)
If something goes wrong, and our code takes more time than the screen takes to draw, then the effect will toggle on and off alternating frames...
Try to start simply with an easy example, and take things from there.
only happen 6 times a screen (every 52 lines) Interrupts can't help us
achieve this trick!... we'll have no choice but to design our code
around changing the screen mode every two lines...
The result is writing our code will be a pain, and we'll end up use a lot of our Z80 power on the effect...
|AkuSprite Editor has a special 'EGX' View mode, it will simulate the display of a 4/16 color alternating screen layout (with the top line as Mode 1)|
|We're going going to start by disabling the firmware interrupt handler, we write a "EI RET" to &0038
The code in today's example are very sensitive to timing... we're going to sync to the screen redraw by waiting for a screen to start redrawing
We read in a byte from port &F5xx... if bit 0 is 1 then we're at the top of the screen
Now we're going to HALT... to wait for the Vblank to end... this allows us to be sure any code that follows will run in a consistant way, syncronized with the screen drawing of the CPC
|We're going to start the main loop...We need to start our 'Mode Manipulation' at the start of the visible screen...
We check again for the start of a new Vblank, so we know we're at the top of a new screen.
When we are, then we disable interupts, and wait 64 lines until we get to the first line of the active screen.
We're going to set IYL to 100 - this is the number of line pairs in the screen (100*2 = 200)
Finally we have another 32 NOPs (via the DS 32)... this will wait until the end of the raster line
|We're using port &7Fxx to set the screen mode, we also need to turn off the High and Low rom...
We set the screen mode to 0, then swith it back to mode 1...
Because we're at the end of a line, the Mode 1 change happens on a different line... and as the screen mode can only change once a line, the change to Mode 1 happens a line later...
We've effectively created 2 lines with alternating modes, with 5 concecutive commands!
We now have a delay...DS 110 is effctively 110 NOPs... this to wait until the next pair of lines... It's at this time we'd need to do any game logic or music playing - and we'd have to make sure our code was 'timed' to take exactly 110 NOPS, otherwise the EGX effect wouldn't be stable!
|We need to 'Call &8000' to enable the effect, but you'll need to make sure you have a proper screen to view!... a sample screen 'EGXTest.scr' is provided in the sources.7z (in the ResALL folder)|
the effect to be balenced the code for each line needs to be the
equivalent of 64 NOPS... On the CPC each command will take a
multiple of 4 'ticks'... so a command like 'Dec IX' which takes 10
'ticks' in the Z80 documenation actually takes 12..
For the full details check out the docomentation on CPC-Live