learn

Learn 8086 (x86) Assembly Programming - Lesson1 : For absolute beginners!



Sharing buttons:

Hello! its Keith here, and this is the first of my 8086 assembly programming tutorials,

now I've done a z80, 6502 and 68000 series in the past but this got

me interested in the other platforms ,and so I thought we'd start doing a bit of

exploration with the 8086! now, of course the 8086

is the foundation for all of the processors we have today the x86 range and

the x64 range... so the current processor you're probably

watching this series on is actually based on the history of the 8086

of course unless you're watching on a phone... in which case you want to watch my

ARM tutorials which will be starting very soon, but anyway you get the idea I'm making

so we're going to be covering the 8086 and also the 80186

and we're going to be doing this in DOSbox, primarily because that's a great way

of writing few little programs with 8086, and not worrying about damaging our real machine!

because we're protected by the DOS box emulation, and we're also going

to do the 186 on the wonderswan, because you may not know this

but the Japanese handheld system that was competing with things like the

gameboy color and the Neo Geo pocket... the wonderswan was based on a 186 put

compatible processor, so I thought that would have be a fun way of having two

systems in this tutorial, and we will be sort of comparing the two and things

but we're going to be primarily working on a DOS system today, because we're just

going to be learning the absolute bog-basics of the system... learning how the

processor works, and about registers and things like that... now I'm gonna be

assuming you've got absolutely no experience of programming at all,

so this is going to be really "from the ground up" if you've covered a z80 system or 6502

that's going help you obviously... but i'm going to be really going from the basics

so hopefully you'll be able to get started with this, even if you've no prior experience

now, first thing of course if you go to my website I have a cheat

sheet available for download.. this is a PDF with all of the commands in a big list

hopefully it will help you out, so please go ahead and grab that I made it

while I was learning this programming language - so it helped me, so hopefully

they'll help you as well!... anyway, beyond that we've got some links to some PDFs

I've found helpful, but I'm going to try and (through the course of this series)

explain everything I think you need to know, but obviously there'll be things

I've not covered yet, or things maybe I've not covered in enough detail for you

so please go and download those as well if you're interested... but anyway

let's carry on from that! now the first thing we do need to discuss very quickly

is the sort of concept of decimal, binary and hexadecimal

now, in assembly language we tend to use hexadecimal and we also use

binary quite a bit... now, these are different bases (so to speak)

now, the normal numbering systems we use are called "base 10" and this is typically

said to be because we have 10 fingers... so a number will be between 0 to 9 - that's 10

consecutive digits, and then once we go into 10 that becomes two digits

and so we have "10" a "1" and a "0" then and we've split that into two separate digits

now in a computer the sort of core workings are working in 1s and 0s.... base 2

to represent a number like 255 we would need 8 digits and they would all be 1

so and that's obviously a bit inconvenient for us, so we tend to merge things together into

something known as "base 16"... now, this is quite complicated I know... one thing

I'd say is there's a very simple chart here showing how decimal compares to

binary and hexadecimal here... the hexadecimal you see will use digits 0 to 9

and then we'll continue ABCDE and F here, and this allows for 16 digits in a

single space of our number here... now the thing you want to do if this is confusing

(which I totally understand it possibly will be) is try using your windows calculator

now if you get your calculator just here, this is windows calculator

and you turn it to programmer mode, this is the windows 7 version

but if you've got Windows 10 there's a even better one actually, and if you type in a

number in decimal here like 100... and we click hexadecimal, you'll see it's been

converted to 64 ... and we can convert to binary and see the binary equivalent here,

now, in a lot of cases you're not really going to have to worry too much

about these things... because our assembler is going to be doing the conversion for us,

if we want to use a decimal number it will convert it to what we need

in the actual resulting file ...if we want to do a binary number we can do that as well

but there will be some cases you need to understand it... so we're needed to

just basically cover it here, just to introduce you... now, if you need to see more

I've got a dedicated video on binary decimal and hexadecimal

and I've got some examples, and a little program I used... so please check out that video

on my youtube channel, if you do need to see the real details of it,

because (I mean) there'll be some things you can learn as you go along, and there might be

the case that you just need a real in depth and go over with it to get grips of it

but as I say, for today we're only going to be

covering it very briefly, so how does the 8086 work? well the 8086 (like all processors)

has a set of registers, now the microprocessor is like a chip on the

motherboard and it connects via wires (obviously) to bits of memory, and there

will be the plug-in cards if you've ever built your own PC, but inside the processor

itself is some tiny tiny little bits very very fast memory, and these are

known as "registers" on an 8-bit processor... so they would typically only be 8-bit and

they would just store a single byte... on a 16 bit processor they're typically 16-bit

I say "typically" because the 68000 is considered 16-bit, but there's actually

32-bit registers on that system, so we only tend to have one or two of these ,

and it depends on the system how many we have... on the 6502 we kind of have 3

On the Z80 we have a few more, and on the 68000 we have an awful lot!

now, on the 8086 we have 4 general-purpose mathematics... registers AX BX CX and DX

these are 16 bits AX BX CX and DX.. we also have some special registers source

and destination, that have some other purposes... and we have some things that

are known as "base pointers" here, and we have some special ones which are segment registers

now we're going to go into those in detail later, so I'm just going

to briefly mention them, and move on at this point... but I did need to explain

that to you... now the 8086 is a 16-bit processor, which means that each register

can store 16 bits and that's 2 bytes... 0 to 65535 in decimal. now, the way it works

though is each of those registers can be split into two 8-bit parts, and where the

register AX is referred to, the two parts that make up the register AH and AL

and so we could load a value from 0 to 255 in AH, and 0 to 255 in AL

but that will of course affect the AX register, because these aren't separate registers

they're just different ways of addressing the same piece of memory

so AX is made up of the pair AH and AL, so again we'll see all of this in example later

I'm not going to cover segment registers at this point, because they're

a little bit more complex, and it's more appropriate to see them when we need to

know about them... so we're just going to skip over that

so we're just going to skip over Stack pointers, and base pointers at this point...

because we'll come to see them later... now another one that's very important is the

program counter which is called IP on the 8086... This is the current byte of code

that's running on our system, we're going to be writing a text file (ASM) of course

but that's going to compile to some bytes, and those bytes are going to

be loaded into memory, and then the processor will tick through all of those

bytes processing them, and just doing what they do... but of course the processor

needs to know what byte it was looking at last, to know what it's going to run next

and that's what the program counter does, it's the current running byte of the code,

and then we've got a Flags registe,r and this is this is how the processor

decides what to do next... it remembers the result of mathematical operations,

Did that result in a 0? did it overflow the byte, and now the data may be corrupted?

it remembers things like that and it's used for comparisons and things,

again, we'll see that in a later lesson but again I just wanted to give you a brief

introduction to the attributes of the processor... you don't need to worry about this,

we're gonna cover this in a later lesson... so let's just skip all the way

down here to the start of lesson one's content.... okay! well just before we have a

look at this... let's actually go over to our source code, and let's see some

programs running, because I want to show you some stuff that's actually working

as soon as possible... so here we go... ok, so here we've got a very simple sample

this is a minimal file... now you can go onto my website, you can download the sources.7z

and this will contain all of the assembly files, you see in these tutorials

in addition there's another file called "DevTools", and this is the

assembler I'm using.... the emulators and also the build scripts,

and the intention is that you should be able to download all of this, put it on to your machine

and just basically use everything you're seeing here as it is,

and hopefully you'll just be able to run these just as easily as I am today...

that's the plan anyway! so please go on there.... all of the stuff I use is free and open source

so hopefully it should all be fine for you... so this is my minimal

assembly file, and I'll just go ahead and I'll press F6 here... and I'm going to

select "DOS VGA"... and you can see here we've got a dump of some registers,

and that's this little command here "do monitor"... this is a program I wrote and it

just shows the state of all the registers... it's for debugging

we'll be using it through tutorials, but we're not going to learn

how that command works because it's a little bit tricky at this stage,

so just an example there of that running, now as well as that, I can select the wonderswan color here

if I just run this, you'll see the same program running on this

Wonderswan color emulator just here, and how did we do that? well the code here

and here in this header and footer are actually doing the conversion work for

the two systems, and that's how we were able to run this little program on both systems,

now the idea of this file is that if you wanted to go it yourself and

just try and play around with things on your own, this is kind of a very bare

minimum file for you to use as a template, just replace this with whatever

you want to do... just leave this start and bottom bit the same until you understand it

and then go ahead and do whatever you want, but this is a kind of template file

for you to just get started with the bare minimum for if you want to

experiment on your own...Now, that said that's not what we're going to be using

today in these tutorials, every episode has a lesson file and that is going to

be showing some very standard examples of what we can do, and giving practical

visible results from the commands... that's what we're going to be doing today!

So that's the source file, and now how do we actually compile that? well the easiest

way to compile is exactly as I just showed you... just press F6, and select the

option from my menu from within the notepad+-+ that I've set up

Now, what about if that doesn't work? let's say you're not using notepad++

let's say you're working on a Mac or a Linux machine ,and you can't use that

you want to go it yourself? that's totally brilliant, if you're

feeling confident! I totally encourage that, that's superb!... so let's have a look

at the script I'm using to actually compile the program, so here is the file

that was building that DOS example, and you can see there's this

list of commands just here... now this batch file is quite complex, but a lot of its

just error checks to make sure that the user hasn't done something strange

that will cause us some problems! so let's go over to here, and have a look at this

example which has been highlighted with the different sections,

and we'll discuss those part by part just in case you're using your own assembler.

So the first thing is for DOS, we're building an executable file, we're using an EXE here

and we specify that with this MZ, the next thing we're doing is we're

defining some symbols - these... we'll learn a bit more about symbols later,

but basically it's so that my code can compile on wonderswan and DOS,

I'm having to tell the system "Hey, you're compiling on DOS today!" "hey, you know

you're using VGA not EGA"... because we're going to cover different graphics modes later on

so these are just some some kind of "pointers" to say to the source code

"compile yourself for this system today"... so that's just something

I'm using here, symbols defined on the command line... this listing file is the

debugging file, it's quite handy if you're having trouble...

It will show the contents of the file that was compiled, and what bytecode that resulted in

it's going to be too complex for beginners though, but it's something

if your assembler does allow you to output one - try and get it to output it,

because it will save you later on if you start getting stuck... of course we need to

specify a destination file, so I'm creating a file called "Prog.EXE"

you may want to create a COM file... they're slightly different, but we're going to be

using EXE's in this example, just because I'm more focusing on the ASM commands

and how the commands work at this stage than the actual technicalities of DOS files

and things... it's much more theoretical at this stage in this tutorial.

and then finally we need to specify the source file, and this would be your

lesson1.asm (in this case) because it's running from a batch file its

%build file% - and so that's what we need to do to actually compile our program

so let's go over to our source code, and let's look in detail at then

ok so over to this minimal file again, we're going to look at the

"real foundations" of this program. Right...well what do we want to look at first?

well we're going to ignore a few of the more complex things here, the first thing

is we've got an "include" statement here, this is attaching another assembly file

so this program splits into lots of different text files, and so we're just

including a few other ones and that hides the code, that we don't want to

worry about today... and what this is going to be template code that will be kept

compatible along this tutorial series, so hopefully these can just be left as is,

the ones we really want to look at here are this CALL command, if you're familiar with basic

you'll have heard of a GOSUB command, which is where you run a subroutine

and then return, and assembly has the same thing... it's called a "CALL"

and so that's just running a piece of code, and then that code will complete

and then execution will continue with the next line

so this calls a routine called "screen init" when that "screen init" finishes

the IP (the program counter) will jump back to here and then

it will call the "do monitor", and then when that completes it will jump back to here,

now, this line (you'll notice) is not indented... these ones have got a TAB

indenting them over here... this one doesn't, and there's a special reason for that

this is a label, and the colon (:) at the end is important as well,

so this defines a label and what this is: this doesn't actually "appear" in the resulting

byte code this is just a piece of text that the assembler takes, and then it

remembers the byte position in the (compiled) file, and then any other reference to that

label will be converted to that byte position, so if this was byte position 10

then this would be saying "jump back to byte position 10", and it's the assemble

doing that work for us, and this is a command, and that is denoted by the fact

is indented by a TAB... this is a label because it's got the colon (:) and no tab

so those labels are a piece of text that the assembler converts to a number

for the purpose of positions in our data, and this JuMP command here is a

bit like your GOTO if you're familiar with basic, so where as a call goes to

a subroutine and then comes back, a JuMP never comes back, so the JuMP here is

jumping to that label just before, and this is (as the text suggests) an infinite loop

so it's just going to go round around forever, it will never will finish

so it's just a way of stopping the program without having to worry about returning

to DOS or waiting for a key or anything, now you wouldn't want to do that the

real system of course... but we're using that DOSBox emulator, so we can

be a bit cheeky, and do some things we maybe shouldn't!... okay, so let's go back

to our source code for lesson one here, this is what we're going to be going through today

so again you can see there's the call here to screen in it

and we're just running this command called DoMonitor that will show the

contents of all the registers to the screen, just so we can see what's going on

and there's a new line here which is going to move the screen down a line

just to clear some space before our main code. We're now going to start looking at

some very very simple mathematical operations with those registers.

Because that's where we need to start with assembly,

now I know you're gonna think that this is going really slowly in this lesson,

And it is... but things will start to build up quite quickly, and you'll soon realize

that mathematical operations while they seem simple and boring, Are really they are

foundation of sprites and graphics and everything really, so it will build up quite quickly,

but we do need to start from the basics, so the first thing we're

doing here is a command called move. now, a move command on the 8086 will take a

destination and a source, and it will move the source into the destination in

this case we're moving the value 0x1234 in hexadecimal,

and we're moving that into the register AX, and if you remember AX... any register with an X

at the end is a 16-bit register, and if we just get our calculator, switch it to hex

and type 1234 and then switch to decimal, you can see that's

4660 in decimal, or if we switch to binary, you can see it's this

really long string here!... and that's way more than eight bits of binary and

that's why we're using a 16-bit register here, so that's how we can convert that into decimal

if we need to know and that's why we're

moving it into AX not AH, because it won't fit in AH... so we're just moving

that into AX, and then we're running this function which I've written

and we're not going to cover it but that's just going to show AX to the screen,

okay well let's press F6 here, and let's start DOSVGA here, let's see the result!

okay ,so here at the top here is the result of the registers when the program started

and that's this "Do Monitor" function just here, so that's before the

change occurred... you can see AX with 0013. Now here, we've loaded AX with 1234

and you can now see AX here is 1234, all of these are in hexadecimal here,

just for screen space reasons and because that's really how you want to

think in assembly most of the time, so we've loaded 1234 into AX here,

now you remember I said that AX was a 16-bit register, but it was made up of 8-bit

H for high part of A and AL for low part of A and we can use that, and when you

can see we've done that just here, next what we've done is we've loaded AA into AL

and BB into AH, and you can see here we did another dump of DoMonitor here,

and this first one here has indeed got the low part of AX (the AL part) set to AA

and then the second dump which we did just here, has got BB at the high part just here

so you can see those changes to AH and AL have indeed

affected AX just here... so there we go! now I discussed the different bases before

(binary, decimal, hexadecimal) now, our assembler can do this for is

converting these, so that we can enter the number or value that we want to use

and the assembler will figure out how that actually needs to be stored in the

resulting file, so we can use decimal just by putting a number here,

so 128 will be 128 in decimal. Now, because of the way

hexadecimal works that will be 80 in hexadecimal, and we've done another DoMonitor

command here, and that's dumped AX just here, and you can see 128 is 80h (in hex)

and if we think the assembler might be lying to us we can just type 128

into our calculator here, and click hex and you can see that is 80!

and if we click in binary you'll see that's 8 bits, and just the top bit is 1 and if you

start to switch between them as you're working with things, you'll start to

understand more of how things are working, and it will get a bit clearer for you

although I do understand it's going to be a bit tough at the start,

but it's going to just unfortunately the way it is! so we can use move commands to move a

value into a register, now with these commands the destination is always on

the left of the comma, and the value is always on the right of the comma.

so in this case we're moving 128 into AX now MOVe is just transferring data from one

place to another, but we we you of course will want to do mathematical operations

and we can do those in the same way, we've got a command called SUB for subtract

and we've got a command for ADD which is addition of course,

and so we can do a subtraction of hexadecimal 10 from AX just like this, and if we do the

DoMonitor again, we've subtracted hexadecimal 10 from the 80, and that has

gone down to 70, and you can just see there in hexadecimal... of course now

the fact that there's a 'h' here it denotes this value is in hexadecimal

but we can do other values as well, if we put a

'b' here in this addition line, we're actually adding one zero in binary.

well let's have a look and see what 10 in binary will be, if I just type 10

and then I press 'decimal' you'll see that 2 in decimal and it's also 2 in hexadecimal.

so that's the value that we are effectively adding when we say "10b"

10 in binary... and you can see here that AX used to be 70, but it's now gone

up to 72, because we've added two in binary... and we can just prove that if I

just change this to 11b -and this is really what you want to do, you want to

download these files and have a play with them, change some of the values and see

how the code is affected, because that's how you learn these things...

that's why I'm making all these source sources available to you as well as doing them in this video

so I change that to 11, and it's gone from 70

it used to be 72, but it's now 73... so you can see that this addition is definitely working ,

and the changes being reflected in this code here... now we've done decimal here with

with no symbols denoting the format, so that was defaulting to decimal...

a H told is that its hexadecimal.... a B is told the assembler t's binary, but there's going to be

times we're going to want to work with letters of symbols...

we're going to need to print text to the screen, we're going to need to show

colons between a register label and hexadecimal value, so we're going to need

to do a lot with symbols, and we can use characters just by putting them in quotes

so if we put a space in quotes here, and we load that into AH

the assembler will work out what the value of the space symbol is in what's known as ASCII

and we can just see that now, so if we just run this and we will see

now AH is of course the top half, and that's been set to 20, and that is actually 32 in decimal

and if you know your ASCII, then you will know that that's correct

now of course we can change that if we wanted to do a letter "A"... we can just

do that...

and you can see that's now changed to a 41 here, and if we get our calculator up

and type in 41 in hex and change the decimal that's 65... which is indeed a capital 'A'

so you can see we can do that quite easily, now in those examples we've

been doing addition and subtraction to AX, and we've been using fixed values

but all of these commands will work with other registers, and both with 16-bit and 8-bit registers,

so we can add AH to AL here, if we want or we could have added BX to AX

where we're only using A- here just for starters, but as I say,,

all of these are interchangeable, but you have to sort of 'match pairs'... you can add AH to AL

or BH to AL... but you can't add BH to AX, you'd have to expand it out into a

16-bit component to do that addition, but we'll cover all of that later on,

but you can see here there's a wide variety of simple mathematical operations here

just to get started with... moving data around registers, and playing with the

different bases, and as I say please download this and have a go yourself!

now, we've only played with a X there but it's time to branch out... as I said before,

the 8086 has AX BX CX and DX, and these are the four main registers we will be using,

there are some others, but these are the main ones, so let's do the same

with BX here... we've loaded hexadecimal 666 into BX, and you can see in this

next example BX now contains 666, and that was just shown to the screen by

this new monitor function here... we then moved BX into AX, because remember the

source is on the right, and the destination is on the left

so that's been transferred across here from BX to AX and now both equals 666, and that's

how we can work with multiple registers... very easy... now this is how we can move a

value from one register to another, but there will be times where we actually

want to swap two registers, now of course one way we could do this would be to use

a temporary register if we wanted to swap AX and BX, we could load AX into CX and

then load AX with BX and then load BX with CX... but that's going to be a bit of pain

and we're going to use up these precious registers, we really don't have

very many... so one option would be to use memory to do that but that's slow

so what we have is a really nice command , on the 8086, which just swaps registers around

so no temporary memory, no temporary delays using extra registers, let's use

two registers, and just use an exchange command XCHG... and once again there's two

parameters separated by a comma, but of course there's not really a source or

destination here, because they literally swapping over... so let's just see that

connection just here, so here we've got 7777 in AX here

and we still got our 666 over here, and then we did an exchange of AX and

BX so they swapped over just here, and then we started playing around with the

high and low components of AX here AH and AL were swapped over,

so 0666 became 6606, because you can see these two have

crossed over just here, and then what we did is we swapped BH and AL,

because this exchange command doesn't just work within one register, we can do the High

part of one 8-bit part, and the Low part of the another registers 8-bit part

and that's what we've done just here this 06 has transferred over to here

and this 77 here has transferred to here... you can see we've got quite a bit

of flexibility with working with these commands... there we go!... now, we've done some

addition and subtraction... we've done moving values into registers,

and we've done swapping of bits of registers around the last thing I want to cover

today is a simple version of the addition and subtraction... now we're going

to cover loops later on, but of course in programming if you done BASIC before,

you'll do your sort of "FOR I=1 TO 10" loop, and I'll go up by

one each time, increasing by one is going to be a thing you can have to do an awful lot

and while you could of course do add one each time, or sub one each time,

that's a relatively "large" command... it compiles through to two bytes, I believe

so that's gonna be taking up a little bit memory, and a little bit processing power

and while the 8086 is very fast by the comparison of the z80,

we're still going to be want to be as efficient as possible, especially because the

processor has some memory limitations, which are going to be a bit of a pain to us

so we want to make our code as smaller and as efficient as possible

wherever we can, so rather than doing an add one or subtract one, we've got some

special commands which you'll know if you've used other systems, INC and DEC

INC increases a register (by 1) and DEC decreases a register by one

so these are the way that it's quickest to increase the value by one and

decrease the value by one... and these are what you would use in your loop when

you're increasing yout value, or when you're reading back some memory and

you're moving across one each time, these are the options available to you.

so very simple commands, they work on all registers, so you can see here we had 6677

we did an INC and that became 6678 and we had

0677 here, and we did a DEC of BX, and that went down to 0676 here

now of course these aren't just limited to two sixteen bits,

we could do get BH as well, we just run that ,where you can see now that the H

part has gone down by one as well to 05, so both parts have now gone down by one,

as I said before you really... I'm sure you're having a lot of fun watching this(?)

and I totally encourage that... and I've gotten gonna have loads more of

these coming up, but really if you're actually planning to program

these yourself, you're gonna want to create some code of your own, or modify this one

so that's why that minimal examples is there for you, and that's why

you can download this lesson, and you can do the kind of thing I've just shown you there

go have a play around to change things, see what works... have a go!

that's really what the fun of this is , you should be having a play around and

learning things yourself! so we've covered a lot of stuff in this lesson

I know we've not gone into massive detail here, but I wanted to give a good

quick lesson with a fair amount of stuff that wasn't too overpowering for you,

now all of the content that we've covered in this video of course... you can get the source code

but there's also a companion text tutorial that matches the same

content with visual diagrams on my website, so please go and have a look at that

if you want more information, I'd say download the development tools

download the sources... I also now have a forum where you can discuss assembly programming

and I'll try and help you out if I can, I have a discord now,

so you can chat with people who are interested in programming

and so you know, please them take a look around all of the options I've made available

and let's find what works for you please like and subscribe, you know...

subscribe to my channel, give the video I like... because it takes a lot of work making these and

it's a real encouragement for me... anyway I hope you've enjoyed this,

I hope this has given you some interest in x86 and given you some encouragement,

I know we've not covered much today, but we're really going to go through it

pretty quickly... and we'll find in just a few lessons, we will be putting graphics

on the screen, and making a little game or some things.. so don't think that just

because we've not made very much progress today it's gonna really build up

and I hope you're going to enjoy i,t and I hope you're going to stick around and watch it

anyway I hope you've liked what you've seen today, if this seems

something that's interesting to you but you'd prefer something else

have a look around my youtube channel, because I've already done Z80, 6502 and 68000 and

I've covered tutorials on all of the major systems really that use those

processors.. I've done Amiga, CPC C64, Nes/Famicom, PC engine, Genesis

you know... I've covered all the major ones and I've got more I'm planning to do in the future!

so if this doesn't quite look like what you had in mind today,

take a look around and see if there's something else you like more, anyway I hope you

enjoyed this... anyway I hope you're going to enjoy playing with the 8086,

and I hope you're going to enjoy programming in general... thanks for watching today

and goodbye!