Assembly Language for Veggies (And C programmers) Part 3
Welcome back to assembly for veggies.... Well I've said a lot about real simple stuff now.. perhaps it's time to provide you lot with some decent assorted infos?
Where to start is the BIG question.. there's a hell of a lot to know about your PC, and it's overall structure.... I said you'd have to get akin with the hardware, so why don't we leap into some hardware discussions this section (consider it a primer to bring you into a better understanding - because you use the hardware directly quite a bit in ASM)..
I will leap in by talking a bit about the IBM machine... (This could be a long story ;-)...)
The original IBM PC was based around the Intel 8088 CPU. CPU Stands for Central Processing Unit and is the "Brain" of the computer.. In fact, a computer can be correlated very well with the human body (thus the body is often referred to as a biological computer!!).
The CPU is equivalent to the human brain. It controls everything else, and does MOST of the workload. The people who made the 8088 (Intel) soon progressed with the 80286, 386 and 486 chips which are Upward compatible with the 8088 - this means that they will correctly run anything made for an EARLIER version (IE 386 runs all 286, 8088 stuff too) of the CPU. Each new CPU added extra features, not found in earlier models, thus the later models are NOT Downward compatible. (OK the order here may seem wrong, but if you follow the logic that everything is compatible as you go up the chain (88 - 286 - 386 -486), but not down the chain (486 - 386 - 286 - 88) you'll understand.
The CPU alone is the clever but, but put it on it's own and it won't do a lot... you need to add INTERFACING around it. you also need to provide a source of POWER to run it, and give it a TASK to perform. Remember the highlighted words - we'll look at each of them now...
POWER : In human terms, we'd be looking at the digestive, lung - blood system. to simplify things, we say food goes in, gets converted into the right sor of energy to run the brain, piped there via the blood/veins and is uses by the brain in it's normal operation.
In computer terms we have a POWER SUPPLY - it takes mains voltage, converts it to the DC 5v and 12v required for the CPU and pipes it there via metal wires where it is used in the action of processing.
INTERFACING : This topic is huge and basically covers the rest of the body... it ill the input and output devices... there are many sub-systems here to be considered - for example the eyeball-brain connection is like the VGA-CPU connection and so forth.. I'll have a lot more to say about this lter... Oh, and it's often called I/O, but I don't like that term as it is easily confused with I/O external (serial, parallel ports etc) to the machine... the kind of interfacing I mean is between the CPU and the other components inside the case...
TASK : Well, you're always doing something - take breathing for example... so too the CPU must always be doing something - it's forever running a program of some sort - remember, DOS or whatever is just a program to the CPU, and it makes no distinction between one program and another...
So what do we have so far? A CPU capable of processing instructions fed to it, and the unknown quantity known as Interfacing...
Ok... well believe it or not the CPU is really pretty dumb... it has a set of about 150 or so separate instructions that it recognises and can do things with.. It has no memory WHAT SO EVER!!!
As you know, it has some registers and that's it! Pretty poor, eh? well that's because it's designed as a CONTROLLER... just as your muscles take instructions from the brain and actually do the work, so too the CPU tells it's "workers" what to do and that's what actually produces results...
Let's look at all the bits put in round the CPU to support it.
The original IBM Machine was designed around standard off-the-shelf chips. In fact you can take a bare IBM Motherboard (XT I mean), wander down to Dick Smith, Radio parts and maybe one other shop and buy all the bits (with one important exception) for no more than a dollar or two each - there's about 60 of them to buy, and a complete set at today's prices is about $180. There's only 1 set of chips you can't get - because they contain the BIOS and have to be pre-programmed by IBM before you buy...
Anyhow, I digress! The point is that everybody (indeed right thru to the 486 machines) has remained compatible with this original design - thus anything you write to work with the basic setup will run on anything...
Here's what they put in:
RAM up to 640k of RAM in 10 banks
ROM up to 64k in 1 bank
8237 a chip that controls the DMA
8255 parallel I/O chip for miscellaneous control - NOT the printer ports!!
8253 programmable timer for assorted timing (including the clock!)
8259 interrupt controller for handling important hardware events
An exhaustive discussion of the actual functions of each chip would take YONKS so I'll leave it here for now... suffice to say that that's the stuff that does all the basic I/O internal to the motherboard.... it is essential that all these bits work before the machine will fire up..
IBM Then added the expansion bus (wonderfull idea!!) and designed the video card, the serial card, the parallel and floppy disk drive cards. These used more garden variety chips that slotted into pre-allocated spaces inside the design of the PC.. This allocation of specic locations to specific parts of the PC was to be a bad shortcoming indeed (if they allowed us to relocate the hardware elsewhere we'd be able to have as much as 768k of RAM to use in most cases, maybe even as much as 896k in good designs!!!).
BASIC PC MEMORY MAP
FFFF
F000 F000-FFFF System BIOS lives here (usually only top 8k used)
E000 E000-EFFF Traditionally add on BIOS (Normally free)
D000 D000-DFFF Traditionally add on BIOS (Normally free)
C800-CFFF Add on card useage (Usually XT Type HDD contolleer BIOS)
C000 C000-C7FF Add on card useage (Usually extra VGA bios)
B800-BFFF CGA Video RAM
B000 B000-B7FF MONO Video RAM
A000-AFFF EGA/VGA Video RAM (Graphics modes)
A000 --- 640k RAM --- LIMIT of user RAM
9000 --- 576k RAM
8000 --- 512k RAM
7000 --- 448k RAM
6000 --- 384k RAM
5000 --- 320k RAM
4000 --- 256k RAM
3000 --- 192k RAM
2000 --- 128k RAM
1000 --- 64k RAM
0000 --- bottom of memory ---
In these modern times, things like EMS make use of the "empty" D and E blocks... You should be able to see that it is impossible to add more "conventional" memory because of the hard design that says you have to use the A block as VGA RAM (If you didn't have VGA you COULD add extra RAM on some sort of custom design card, hack DOS and use the extra 64k as normal RAM, but why bother!!)
It is now normal to reserve all of the A and B blocks for video RAM, the E000-E800 for video BIOS, the E800-EFFF block for XT Hard disk BIOS's, and the D & E blocks for EMS drivers. The F block is usually left alone, it's use being decided by the particular designers of any given motherboard (for example to save a wire, IBM actually mde their bios appear TWICE in memory - once from F000:FA00 - F000:FFFF, and once some 16k lower... there was only one physical copy in the hardware, but because they left out a wire (apparently for simpstic design of the motherboard) it appears twice in the memory map. Many true-blue PC Programs relied on this fact (Flight simulator 1 being the most memorable) by directly calling routines from their 16-lower address instead of using the correct method of going via the interrupts... clone makers didn't copy IBM's BUG and so the software would crash because the routines it wanted weren't there!! (But soon the clone makers got wise and fixed that one up - by making the same bug as IBM!!! one motherboard I saw physically had had the wire cut with a sharp knife (Effectively leaving it out) to make the board more compatible!!)
note that the 80xxx range of chips (after a reset or power on) always begin executing from address F000:FFF0 - thus the bios should always be present in that location!! normally there'd be a JMP instruction to lower down (seeing as that address is only 16 bytes from the end of the memory map!) in the BIOS where the initial self test & startup routines execute. The initial self test routines are often called the POST (Power on self test) - they initialize the video, floppy, hard disks, set up all the onboard 82xx chips and so on... then search for the first bootable device.
The first 64k of RAM is used in part by the 80xxx and the BIOS and by DOS...
- 0000-0100 - 256 4 byte entries hold the actual addresses that each interrupt relates to - so if you want to know where interrupt 2F is pointing, look at the 4 bytes starting at offset (2Fh=47d 47x4=188d=BCh) 00BC... (or use the DOS getintvector call!)
- 0101-03FF - undocumented mystery - probably used by BIOS internals or even free.
- 0400-04FF - BIOS Data table - holds data critical to normal working of BIOS
- 0500-05FF - DOS Data table - holds critical data that BIOS and DOS use
- 0600-7BFF - undocumented mystery - apparently free or for later expansion.
- 7C00-xxxx - When you boot up, the BIOS reads track 0, head 0, sector one of the first bootable disk into memory starting here at 0000:7C00 and hands control to 0000:7C00. Everything from this point on is dependent on what this boot track tells the machine to do. In DOS based systems, it loads the two hidden system files into RAM (thus starting DOS) or proclaims "non-system disk or disk error..."
There's also a similar I/O map for the hardware chips - the 80xxx series can access up to 64k worth of I/O ports, but the design of the IBM allows the use of only the first 400h (1024d) ports (which is heaps!!)
I/O port Map
Port # Use Chip Number used by IBM
000-00F DMA Registers 8237
010-01F AT Second DMA Chip 8237 #2
020-027 Interrupt controller 8259
028-03F AT Interrupt controller 8259 #2
040-047 Timer chip 8253
048-05F AT Timer chip 8253 #2
060-06F Parallel Chip (NOT LPTx!) 8255
070-07F AT NMI Mask registers
080-083 DMA Page registers
084-09F AT DMA Page registers
0Ax Free
0Bx Free
0Cx Free
0Dx Free
0Ex Free
0Fx Free
100-1FF Due to a stuff up in IBM, all ports in the range 000-0FF appear
again in this range - they didn't decode address line A8!!
200-20F Game (Joystick) D/A converters & fire buttons
210-217 XT Expansion unit
218-277 Free (soundblaster usually at 220h)
278-27F LPT3: 74LS273/74LS373
280-2E7 Free
2E8-2EF COM4: 8250
2F0-2F7 Free
2F8-2FF COM2: 8250
300-31F Prototype card
320-32F Hard disk use WD10x00 MFM HDD Series Chipset
330-377 Free
378-37F LPT2: 74LS273/74LS373
380-38F SDLF Communications Card (IBM Failure of a design!!)
390-39F Free
3A0-3AF Binary Synchronous Comms (Another IBM Failed design!)
3B0-3BB MONO Video MC6845
3BC-3BF LPT1: 74LS273/74LS373
3C0-3CF EGA/VGA Video
3D0-3DF CGA Video MC6845
3E0-3E7 Free
3E8-3EF COM3: 8250
3F0-3F7 Floppy Disk controller NEC uPD765c
3F8-3FF COM1: 8250
Basically that's it!! As I said before, an exhaustive reference to individual chips would be a large hassle!, not to mention hundreds of pages long!! So I won't bother!
INTERRUPTS
Interrupts are the other big deal on the PC .. there's too many to list individually, so i'll cover them in blocks..
INT# Made by Use
0 80xxx divide by Zero error
1 80xxx single stepper
2 80xxx NMI
3 80xxx Breakpoint
4 80xxx Overflow
5 BIOS Printscreen (Why the fuk did they use 5!!!)
6,7 IBM Reserved
8 8259 IRQ0 - Timer tick - timeclock basicly
9 8259 IRQ1 - Keypressed - calls BIOS readkey from 8048 KB CPU
A 8259 IRQ2 - EGA/VGA Vertical retrace, 8087 error
B 8259 IRQ3 - COM2: I/O done COM4: I/O done
C 8259 IRQ4 - COM1: I/O done COM3: I/O done
D 8259 IRQ5 - Hard disk data ready/needed
E 8259 IRQ6 - Floppy disk data ready/needed
F 8259 IRQ7 - Parallel printer, SoundBlaster loadx
10 to
1F BIOS Bios routines, pointers etc.
20 to
3F DOS DOS routines, pointers, drivers etc.
40 HDD HDD Puts original floppy INT13 call here
41 HDD Points to table holding HDD head, cyl etc. data
42 EGA/VGA Puts original video routines here
43 EGA/VGA Low 128 video char font pointer
44 EGA/VGA 6845 data for intializing a video mode
45 ? ?
46 HDD As 41, but for HDD #2
47 ? ?
48 PCjr Keyboard translate table pointer
49 PCjr non keyboard translate table pointer!
4A AT-BIOS User alarm routine pointer
4B to
5F ? DesqView redirects IRQ0-7 to int 50-57
5C often used by networking software
60 to
67 User Free for user use - INT67 often software call for EMS drivers
68 to
6F ? ?
70 AT 8259 IRQ8 AT Real time Clock
71 AT 8259 IRQ9 AT LAN (often patched to IRQ2)
72 AT 8259 IRQA ?
73 AT 8259 IRQB ?
74 AT 8259 IRQC ?
75 AT 8259 IRQD AT 80287 Error (patched to IRQ2 for compatibility)
76 AT 8259 IRQE AT Hard disk (IDE types only)
77 AT 8259 IRQF ?
78 to
7F ? ?
80 to
F0 BASIC Used bu GWBASIC, BASICA, otherwise ?
F1 to
FF ? ?
As you can see, some interrupts are used as simple xxxx:xxxx address pointers, some are for calling software routines, and some are generated by hardware and call a user routine automaticly..
SO! What does all this mean? What it means is probably not a hell of a lot at this stage... in the future, you will find this is a valuable reference of low level tables when you come to nutting out a program that mysteriously performs OUT's, direct memory reads etc...
For more in-depth instruction on the BIOS and dOS data areas, see norton's programmer's guide to the IBM PC (first ed. pages 51-58 - good reading!!)
to round things off, I'll finish with another small demo ASM program that shows off some more instructions...
Ever needed to move memory about FAST? how about fast reading from sequential memory locations (or indeed writing..)??? There's a set of instructions designed just for this.
They are:
- STOSB - write byte
- STOSW - write word
- LODSB - read byte
- LODSW - read word
- MOVSB - move byte
- MOVSW - move word
- *OUTSB - output byte to port
- *OUTSW - output word to port
- *INSB - input byte from port
- *INSW - input word from port
- * = only executable on 286 or above!
All of these routines can be looped a given number of times - place the number of repetitions to be performed into the CX register and preface the instruction with the letters REP - IE: REP MOVSB ...
The data comes from DS:SI (for LOD or OUT types) and goes to ES:DI (for STO or OUT types). further, if you use OUT or IN instructions, they use the port in DX for their reading/writing.
further note that the instructions alter their associated pointer register!! - thus if you have SI=5312 and you do a LODS, afterwards SI will be one greater or lower, depending on the setting of the Direction flag! - the direction flag should always be set by you before using these instructions otherwise thids could go the wrong way!! - for incrementing after read/writing, first execute a CLD (Clear direction flag) instruction. For decrement after Read/Write, first execute a STD (set direction flag) instruction. Note that a maximum of 64k can be moved in any one go, and that the segment registers are not altered as a result of an instruction, only the offset pointers, so a 20 byte read starting at 1000:FFFC will NOT read on into the next segment, but rather the last 7 bytes will come starting from 1000:0000!!!!! this is a bad limitation of the instructions, so don't get caught out!!!
THESE ARE VERY POWERFULL INSTRUCTIONS!!! ... let's say you wish to move a chunk of memory from 3C00:2745 to 3212:5678 (assume a length of 2c0 bytes)
this does it:
CLD
MOV CX,02C0
MOV DS,3C00
MOV SI,2745
MOV ES,3212
MOV DI,5678
REP MOVSB
Dead simple, eh? If one divides CX by two and uses REP MOVSW then one gets a 2x speed transfer on 16 bit machines!!
This is the method used to scroll display memory in my second VGA Demo - it's too slow to do smooth scrolling animation, but quite quick enough for simple memory moves.
The actual speed can be calculated thus:
Instructions are measured in clock ticks... a clock tick is 1 divided by the CPU clock frequency... On a 20MHz machine, each clock tick is 1/20million - about 0.05 of a microsecond!!!
Let's take a MOVSW instruction - this takes 1 tick to read the instruction, 1 tick to process it, 2 ticks to read the word in, 1 tick to process, 2 ticks to write it out, along with 2 RAM refresh ticks in the middle.. a total of 9 tics - so each MOVSB takes 9 x 0.05 uS = about 1/2 a microsecond....
A 64k move takes 65535x0.5uS = about 32.8 milliseconds!!!!
This translates into being able to move about 1.9MB in a second (At 20MHZ!!!!!) The old 4.77MHz XT did about 1/4,770,000=21uS/tick - 0.18mS/MOVSW - 64k moved in about eleven SECONDS!!! (That's indirectly why a 4.77MHz XT 640 RAM Test [on bootup] takes about 3 minutes!)
The 386 and 486 are capable of running faster at the same clock speed because they takes less ticks to execute the same instruction (They only do 1 RAM refresh, and only take 1 tick to read or write a word) .. this is why a 286 and a 386 (NOT 386 SX!!) don't run at the same speed even though they have the same clock speed (all the instructions take less ticks on a 386 - not just the MOVSW!)
If that isn't enough to keep your minds flowing, then I'll go he! It's midnight, I'm going to bed! Until ASMVEG4, Cya's!!
.\\erlin