Learn Multi platform 8086 Assembly Programming... For World Domination!

Platform Specific Lessons

In this series we'll go over various 8086 based systems and learn about operating the hardware.

Lesson P1 - Bitmap graphics on DOS with CGA
CGA is pretty terrible by modern standards, with 4 colors and 2 palettes - and strange colors at that, it doesn't exactly give great graphics,

That said, the unique style gives it a surprising nostalgic charm - so lets see it in action!


Setting the Screen Mode and Palette
We're going to use 320x200 4 color CGA mode in this tutorial ... this is mode 4

To enable this we'll use Interrupt 10h (The BIOS interrupt) and function 0 (Set video Mode)

We specify function 0 in AH - and mode 4 in AL before executing INT 10h
We want to select our colors.
We need INT 10h again
We're going to use function 0Bh this time (Set Color Palette)
We need to set BH=1 to select a palette... BL will choose the palette.

BL=0 gives Black, Red,Green and Yellow
BL=1 gives Black, Cyan,Magenta and White
Although we have only two color options, we also have two brightness'
Again, we use INT 10h, but this time we use BH=0

BL should be set to 10h or 0h to set High brightness or Low brightness.

Calculating Screen Addresses
The screen is 320x200, and each byte has 4 pixels (in linear format - left 2 bits of a byte are leftmost pixel)

So each line is 80 bytes... BUT the screen is interlaced!

We need to set our segment to write to 0b800h
Y Line 0 is at address offset &0000
Y Line 1 is at address offset &2000
Y Line 2 is at address offset &0040... and so on

This GetScreenPos will take X,Y pos in BH,BL and return and address in ES:DI to write bitmap data to
When we want to move down a line, we also need to cope with the interlacing effect

Showing a sprite
We're going to include a bitmap file for our image
We're going to use our GetScreenPos to calculate a starting screen address,

We'll use movsb to transfer bytes from the source to the destination.

After each line, we'll use GetScreenNextLine to move down a line.
Here are the 4 possible renders of the character, depending on palette and brightness.

Isn't CGA amazing!?....
... (What do you mean 'no?')


If you want to create a valid bitmap file, try out my AkuSprite Editor, it's free and open source.

Use the "Save Raw Bitmap (CGA)" option from the x86->MS-DOS menu


CGA does support various other graphics modes, but we'll only be covering 4 color for now - as it's the most memorable for it's odd color scheme!

We may look at the others later, if enough people are interested!


Lesson P2 - Bitmap graphics on DOS with EGA
After CGA the PC managed a fair upgrade...EGA!  bringing an amazing 16 colors!

Unfortunately, these were chosen from a quite limited palette, so we're still rather limited in our color options


Setting the Screen Mode

We're going to use 320x200 16 color EGA mode in this time ... this is mode 13 (0Dh)

To enable this we'll use Interrupt 10h (The BIOS interrupt) and function 0 (Set video Mode)

We specify function 0 in AH - and mode 0Dh in AL before executing INT 10h

Calculating Screen Addresses
The screen is 320x200, and each pixel needs 4 bits... but rather than these 4 bits being kept in a nibble, they are stored in separate bitplanes.

This means eight pixels of bit0 are in a single byte... eight bit1 's are in another... the same for bit2 and bit3

These bitplanes are paged in with OUT commands OUTing to port 03C4h (we'll see them later)

for this reason, even though each line needs 160 bytes in each page the width is only 40 bytes

The screen base is in segment A000h

This GetScreenPos will take X,Y pos in BH,BL and return and address in ES:DI to write bitmap data to
When we want to move down a line, we just add 40 to the current position


Defining the palette
In these tutorials we use a common palette format for all our platforms, we then convert this to the format of the hardware.

each channel uses a nibble - with one nibble unused.
For EGA we need to convert this to a byte with bits in the following format:

 7 
 6 
 5
 4
 3
 2
 1
 0
- - R0 G0 B0 R1 G1 B1

Each channel has 2 bits...

R1/G1/B1 is the High bit... giving 2/3rds of the color value
R0/G0/B0 is the low bit...   giving 1/3rds of the color value

We need to shift two bits from the palette definition into BH (in the correct positions)

We then use function 10h (in AH), sub function 0 (in AL) and call INT 10h to set palette entry BL to color BH (in the bit definition above)
We'll apply the palette in our example

The EGA palette doesn't allow all combinations of these palette bits, so some settings may not look as good as you hope... if you want 'proper colors' take a look at VGA

Fear not, we'll be looking at this next!


Showing a sprite
We're going to include a bitmap file for our image
We're going to use our GetScreenPos to calculate a starting screen address,

We'll use movsb to transfer byte each from the source to the destination... this INCs the source (SI) and destination (DI)

BUT... we need to write bytes to each bitplane!... so we DEC DI after the first 3 writes

We select the bitplanes with OUT commands

OUT 03C4h,0102h selects bitplane 0
OUT 03C4h,0202h selects bitplane 1
OUT 03C4h,0402h selects bitplane 2
OUT 03C4h,0802h selects bitplane 3

We don't need it here, but we can combine to write to multiple bitplanes at the same time
OUT 03C4h,0F02h selects bitplane 0+1+2+3

After each line, we'll use GetScreenNextLine to move down a line.

Here is the result.


If you want to create a valid bitmap file, try out my AkuSprite Editor, it's free and open source.

Use the "Save Raw Bitmap (EGA)" option from the x86->MS-DOS menu

Lesson P3 - Bitmap graphics on DOS with VGA
We've looked at CGA, and EGA... but you still want more... MORE? MORE!!!!... well ok!

Let's take a look at VGA - 320x200 with 256 colors... how about that?!



Setting the Screen Mode

We're going to use 320x200 256 color VGA mode in this time ... this is mode 19 (13h)

To enable this we'll use Interrupt 10h (The BIOS interrupt) and function 0 (Set video Mode)

We specify function 0 in AH - and mode 13h in AL before executing INT 10h

Calculating Screen Addresses
The screen is 320x200, and each pixel needs a whole byte!

The screen base is in segment A000h

Each line is 320 bytes wide, so we just multiply the Ypos by 320, and add the xpos (in bytes)

This GetScreenPos will take X,Y pos in BH,BL and return and address in ES:DI to write bitmap data to
When we want to move down a line, we just add 320 to the current position


Defining the palette
In these tutorials we use a common palette format for all our platforms, we then convert this to the format of the hardware.

each channel uses a nibble - with one nibble unused.
For VGA we use the function 10h (in AH) subfunction 10h (In AL)

We use BL to select the palette entry we want to change... we use 6 bits to define the RGB component for each channel (top two bits unused)
Each is stored in a different register.

AX
1010h
BX
Palette entry to change (0-255)
CL
--BBBBBB
CH
--GGGGGG
DH
--RRRRRR


As we only have 4 bits in our common format, we shift these bits to the top 4 of the 6 bit definition

we then use INT 10h to define the palette
We'll apply the palette in our example

We're only using 4 bits of the 6 possible for the VGA display color definitions!

So we're not doing a great job... Sue me!... the priority with these tutorials is MULTIPLATFORM code... and these palette definitions are used on many other systems...
If you prefer, just write your own code with 6 bit palette definitions and quit whining!
Showing a sprite
We're going to include a bitmap file for our image
We're going to use our GetScreenPos to calculate a starting screen address,

We'll use movsb to transfer byte each from the source to the destination...

After each line, we'll use GetScreenNextLine to move down a line.
Thanks to VGA, We can now enjoy the bitmap in it's authentic colors!


If you want to create a valid bitmap file, try out my AkuSprite Editor, it's free and open source.

Use the "Save Raw Bitmap (VGA)" option from the x86->MS-DOS menu






Lesson P4 - Bitmap graphics on the Wonderswan / Wonderswan Color
It's time for something other than DOS! Lets take a look at the Wonderswan and Wonderswan color

They're pretty similar, but we can code in a way that works on both... Lets learn how to use the tilemap to draw an image



Setting the Screen Mode

First we're going to turn off the screen layers - we do this with port 00h

Next we use port 60h to set the display mode - and enable color functions on the WonderSwan Color.

We're using 'Planar mode' in these tutorials, so graphics are in Bitplanes.
When we want to define our palette on the WonderSwan color we need to write words to address FE00h in ram onwards

Each color takes two bytes in the format 0-RGBh - where each channel uses a nibble of the word and one nibble is unused


On the black and white WonderSwan, we define a pool of 8 colors with ports 1Ch / 1Dh / 1Eh /1Fh...
Each Byte contains 2 colors - as each nibble is one color

We then select 4 of these colors for Palette 0 - which we'll use for the tiles with port 20h
OK, lets clear the tilemap!

We needs to write 32 words to ram address 1000h... our tilemap is 32 * 32

We need to set up our screen

First we'll reset the tilemap position with port 10h,11h
Next we define the memory address of the tilemaps with port 07h

We'll enable the tilemap (SCR1) with port 00h

Finally, on the WonderSwan Color, we'll enable High Contrast mode 14h (Though it may have no effect on the emulator?)



We're going to draw a 48 x 48 image onscreen, but we'll do it with the tile-map...
To do this we need to split the pattern into 8x8 chunks, and fill a visible area of the screen with those tiles... Lets Learn how!

Defining Tiles
We're going to define some tiles to draw our image... we need them to be in the correct colordepth, (2bpp for Wonderswan, 4bpp for Wonderswan color)

We also need them to be in the format we selected during ScreenInit (these tutorials use PLANAR)
We'll need to transfer these tiles to VRAM

On the WonderSwan, tiles need to go to address 2000h - and each tile is 16 bytes,
On the WonderSwan Color, tiles need to go to address 4000h - and each tile is 32 bytes,

We'll use MOVSB to transfer bytes from DS:SI to ES:DI... REP tells the command to repeat CX times

Showing Tiles

We're going to need to fill a square area of the screen with consecutive tile numbers to show our sprite.
We're going to define a function called 'FillAreaWithTiles'

The (Start X,Y) position will be passed in (BH,BL)
The (Width,Height) will be in CH,CL)
The first tile number will be in AX

The Tilemap is stored at memory address 0000h and is 32x32 tiles in size.

so our formula is:

Tile Address = 1000h + (Ypos * 32 * 2) + (Xpos * 2)

Each uses one word (Two Bytes) in the format: VHBPPPPT TTTTTTT
V = V-flip
H = H-flip
B = wsc Bank
P = Palette
T = Tile



putting it into effect
First we need to transfer the patterns to vram.

We'll use our DefineTiles function to do that.
Now our Tile patterns are in VRAM, we can show them on screen,

We use FillAreaWithTiles to do this.
Here is the WonderSwan Color, and regular Wonderswan version...
 


If you want to create a valid bitmap file, try out my AkuSprite Editor, it's free and open source.

Use the "WonderSwan" options from the x86 menu

Lesson P5 - Key reading in DOS
Lets take a look at reading the keyboard... Unfortunately the hardware is rather tricky, so we'll have to use the Bios Interrupt calls.

INT 16h can read keys, check for them and test shift keys, depending on the value in AH... lets learn more.

Dos_Keyboard.asm
Dos_Keyboard2.asm


Reading the keyboard with INT 16h
We're going to use INT 16 to read the keyboard.

There are 3 commands we'll be looking at - the 'command' is specified in AH.

BUT there are 2 versions of these commands... the XT versions (for old keyboards) and AT versions which can read more keys... other than that they are basically the same.

In all cases the result is returned in AX... the Z flag is also set depending on if a key was read by AH=01h

XT
AT
Read a key from buffer ld ah,00h ld ah,10h
See if keys are waiting ld ah,01h ld ah,11h
Read shift keys ld ah,02h ld ah,12h
The shift keys can be read while other keys are pressed... here are the possible options:

Bit 7
6
5
4
3
2
1
0
Key Ins CapsLk NumLk ScrollLk Alt Ctrl LeftShift RightShift




We will use 3 commands... AH=00h will read a key from the key buffer...but it will wait if no key is in the buffer, which isn't what we want.

AH=01h will test the buffer, but doesn't empty it... we'll do that, and only use AH=00h when there is one (We need 00h to clear the buffer)... flag Z=true if no key is pressed

AH=02h will test the shift buttons, this is instant and doesn't use the buffer.


We've used this to read the keystate and show it with our monitor.

We've also created a 'ClearBuffer' function which will read in any outstanding keys, and remove them from the buffer.
Here BL has read in the control/shift keys... 04 means we had CTRL down

AX is the key pressed (Space).... AL shows the ASCII for the pressed key...  AH shows the 'keycode'

The Ascii is affected by keys like CapsLock... the keycodes are not!

In most cases 00h,01h and 02h are the same as 10h,11h and 12h - but there are a few differences.

F12 was added with the later keyboards... so cannot be read by 00h,01h and 02h!

Keyreading to simulate a 'joystick'
We can read in the cursors and some shifts and other keys, and convert them into a 'bitmask'... we can then test this for direction movement in a game.

Here we're reading Up,Down,Left, and Right cursors... Space and Enter

Each will set a bit of AL

We're also loading shifts into AH
Here UP was pressed, so bit 0 of AX is 1.

if DOWN was pressed bit 1 would be 1... Left would be bit 2 and so on.


Lesson P6 - Joypad reading on the Wonderswan and Joystick reading on DOS!
IKeyboards are not so great for our gaming needs... lets take a look at the Joystick on DOS... also as it's super easy, we'll look at the wonderswan controls... Here we go!

Dos_Joypad.asm
WSW_Joypad.asm


Joypad reading on the Wonderswan

The Wonderswan has two 4 direction Joypads (Pad X,Pad Y) two Fire buttons (A and B) and a start button (Start!)

The Wonderswan controls are controlled by port 0B5h

We write to this port with one of the bits 4-6 set, then read back from the same port, bits 0-3 will be a pads directions or the buttons.

7
6
5
4
3
2
1
0
Write - B X Y - - - -
Read - - - - D D D D


7
6
5
4
3
2
1
0
Pad Y 0
0 0 1 L D R U
Pad X 0
0 1 0 L D R U
Buttons
0
1 0 0 B A S -
Here we're reading in all the directions of both pads, and all the buttons.

These are loaded and combined into BX one bit per button in the format 0b----RLDU-BASRLDU
The results are shown in BX, here Up+Start were pressed

Joystick reading on MS-DOS via INT 15

We can use INT 15h, function 84H to quickly read the joystick.

We specify AH=84H to select the joystick function, and we specify the result we want in DX

DX=0 will read the fire buttons of both joysticks into AL.... Bit 4,5 are Joystick 1... But 6,7 are Joystick 2 fires

DX=1 will read the directions of both joysticks... Joy 1 (X,Y) is in (AX,BX)... Joy 2 (X,Y) is in (CX,DX)
In the first run, We've read in the Fire Buttons into AL

In the second run, We've read the Analog joystick position of Joy 1 into AX,BX... and Joy 2 into CX,DX

Joystick reading on MS-DOS via INT 15h

We can use INT 15h, function 84H to quickly read the joystick.

We specify AH=84H to select the joystick function, and we specify the result we want in DX

DX=0 will read the fire buttons of both joysticks into AL.... Bit 4,5 are Joystick 1... But 6,7 are Joystick 2 fires

DX=1 will read the directions of both joysticks... Joy 1 (X,Y) is in (AX,BX)... Joy 2 (X,Y) is in (CX,DX)

In the first run, We've read in the Fire Buttons into AL

In the second run, We've read the Analog joystick position of Joy 1 into AX,BX... and Joy 2 into CX,DX

Reading the joystick with INT 15h is easy but boring!

Because we enjoy pain(!), lets learn how to read directly from the hardware with Port 201h!!!

Joystick reading on MS-DOS via Port 201h

We can read in both joysticks from a single port - Port 201h!

The two fires of each joystick are represented by a bit... and each direction has a single bit.

But the joysticks are Analog!... how do we get an analog value from a single bit?

Well we strobe the port, and count how long it takes for the bit to change to zero - that 'count' is our X or Y position.
Port 201h
Bit   7    6    5    4    3    2    1    0 
Purpose F2 F1 F2 F1 Y X Y X

Joystick 1 - Joystick 2
Here is a sample routine to read from Joystick 1.

First we read IN from port 201h to get the Fire buttons.
Next we need to strobe port 201h... we OUT 255 to this port (apparently this charges the capacitors!?)

Now we read in from the port,
We INC BX until Bit 0 reaches zero (the X pos)
We INC CX until Bit 1 reaches zero (the Y pos)

Of course we could do the same with Bit 2,3 for Joystick 2 if we wished
In this example AL has the joystick buttons... BX is the X-pos, and CX is the Y-pos

Here we had Left pressed and one fire button.

Here we've learned how to read in 2 button joystick... But what about 4 or 6 button non USB joysticks?
Well... there are none!... I mean, they CHEAT, a 4 button joystick will use Fire 1/2 of Joy 2... and a 6 button joystick will use the X/Y axis of Joy 2 as two extra buttons - so you couldn't connect two 4 button pads in the DOS days!... Bet you appreciate USB more now eh?

Lesson P7 - Mouse reading in MS DOS
We've learned how to read Keys and Pads, but what about our point and click adventure?

Lets learn about Mouses... er I  mean Mice... and how to read them.

Dos_Mouse.asm


Turning on the mouse and cursor with INT 10h
We control the mouse with INT 10H... this takes a parameter in AX

AX=0 will reset the mouse to default settings

AX=1 will display a hardware cursor... (the mouse works with it off too though!)

AX=2 will turn off the hardware cursor again!
If we want to control the range of mouse movement we can specify a range of screen co-ordinates, the mouse cursor will be limited to this range.

We specify the Horizontal range with AX=7... the range is CX-DX
We specify the Vertical range with AX=8... the range is CX-DX

We can move the mouse cursor to a particular position with AX=4... The (X,Y) pos is in (CX,DX)
We can alter the mouse speed with AX=0Fh - we pass an (X,Y) speed in (CX,DX)

Mouse co-ordinates are mesured in 'mickeys' because apparently someone thought that was funny!
the Default speed is 8x16 mickeys... a higher value
We can read the X,Y position of the cursor, and the Mouse buttons with AX=3h
The (X,Y) Cursor position will be returned in (CX,DX)... the mouse buttons will be returned in BL in the format 0b-----CRL

We can read in the relative move of the mouse with AX=0Bh... this returns an (X,Y) movement size in (CX,DX)
it does NOT return the buttons in BL
The relative movement returns how much the mouse moved, so 0,0 means the mouse has not changed...
Note: AX=0Bh will return movement even if the cursor didn't move because it's already at the extremity of the screen.
First we loaded the Cursor position in CX,DX... we also loaded the Mouse buttons in BL (Left Mouse was pressed)

Then we loaded the relative movement in CX,DX... the mouse was moving Left, so CX is negative.
If you're looking to make a point and click adventure you'll probably want to use AX=3 to do the cursor with screen limits...

If you're trying to make Wolfystine 3B, then you'll want to use AX=0Bh, so the player can keep turning round and round!


 

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

Top Menu
***Main Menu***
Youtube channel
Forum
AkuSprite Editor
Dec/Bin/Hex/Oct/Ascii Table

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

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

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

8086 Content
Learn 8086 Assembly
Platform Specific Series
Hello World Series
8086 Downloads
8086 Cheatsheet
Sources.7z
DevTools kit
8086 Platforms
Wonderswan
MsDos

ARM Content
Learn ARM Assembly
ARM Downloads
ARM Cheatsheet
Sources.7z
DevTools kit
ARM Platforms
Gameboy Advance
Nintendo DS
Risc Os

Risc-V Content
Learn Risc-V Assembly
Risc-V Downloads
Risc-V Cheatsheet
Sources.7z
DevTools kit

PDP-11 Content
Learn PDP-11 Assembly
PDP-11 Downloads
PDP-11 Cheatsheet
Sources.7z
DevTools kit

TMS9900 Content
Learn TMS9900 Assembly
TMS9900 Downloads
TMS9900 Cheatsheet
Sources.7z
DevTools kit
TMS9900 Platforms
Ti 99

6809 Content
Learn 6809 Assembly
6809 Downloads
6809/6309 Cheatsheet
Sources.7z
DevTools kit
6809 Platforms
Dragon 32/Tandy Coco
Fujitsu FM7
TRS-80 Coco 3
Vectrex

My Game projects
Chibi Aliens
Chibi Akumas

Work in Progress
Learn 65816 Assembly
Learn eZ80 Assembly

Misc bits
Ruby programming






















































Recent New Content
* Lesson YQuest4 - Amiga Specific code
* Joystick and Key Reading on the TI-99 with the CRU
* Sinclair QL Specific code - 68000 ASM YQuest3
* Nintendo DS Bitmap graphics (16 bit) Arm ASM









Buy Chibi Akuma(s) from PolyPlay
Buy ChibiAkuma(s) games now!





































































































Recent New Content
* Lesson YQuest4 - Amiga Specific code
* Joystick and Key Reading on the TI-99 with the CRU
* Sinclair QL Specific code - 68000 ASM YQuest3
* Nintendo DS Bitmap graphics (16 bit) Arm ASM









Buy Chibi Akuma(s) from PolyPlay
Buy ChibiAkuma(s) games now!





































































































Recent New Content
* Lesson YQuest4 - Amiga Specific code
* Joystick and Key Reading on the TI-99 with the CRU
* Sinclair QL Specific code - 68000 ASM YQuest3
* Nintendo DS Bitmap graphics (16 bit) Arm ASM









Buy Chibi Akuma(s) from PolyPlay
Buy ChibiAkuma(s) games now!