Category Archives: hardware

PIC–ing

Ref: www.jamesmolloy.co.uk https://wiki.osdev.org/8259_PIC / http://www.brokenthorn.com/Resources/OSDevPic.html

The IBM PC 8259 PIC Architecture
In the beginning (IBM PC and XT), only a single 8259 PIC chip was used, which provided 8 IRQs to the system. These were traditionally mapped by the BIOS to interrupts 8 to 15 (0x08 to 0x0F). It is unlikely that any of these single-PIC machines will be encountered these days.


The IBM PC/AT 8259 PIC Architecture
The IBM PC/AT extended the PC architecture by adding a second 8259 PIC chip. This was possible due to the 8259A’s ability to cascade interrupts, that is, have them flow through one chip and into another. This gives a total of 15 interrupts. Why 15 and not 16? That’s because when you cascade chips, the PIC needs to use one of the interrupt lines to signal the other chip.
The low-level concepts behind external interrupts are not very complex. All devices that are interrupt-capable have a line connecting them to the PIC (programmable interrupt controller). The PIC is the only device that is directly connected to the CPU’s interrupt pin. It is used as a multiplexer, and has the ability to prioritize between interrupting devices. It is, essentially, a glorified 8-1 multiplexer. At some point, someone somewhere realized that 8 IRQ lines just wasn’t enough, and they daisy-chained another 8-1 PIC beside the original. So in all modern PCs, you have 2 PICs, the master and the slave, serving a total of 15 interruptable devices (one line is used to signal the slave PIC).
Only hardware interrupts are handled through the Programmable Interrupt Controller. The special, CPU-dedicated interrupts are shown below.

0 – Division by zero exception
1 – Debug exception
2 – Non maskable interrupt
3 – Break-point exception
4 – ‘Into detected overflow’
5 – Out of bounds exception
6 – Invalid opcode exception
7 – No co-processor exception
8 – Double fault (pushes an error code)
9 – Co-processor segment overrun
10 – Bad TSS (pushes an error code)
11 – Segment not present (pushes an error code)
12 – Stack fault (pushes an error code)
13 – General protection fault (pushes an error code)
14 – Page fault (pushes an error code)
15 – Unknown interrupt exception
16 – Co-processor fault
17 – Alignment check exception
18 – Machine check exception
19-31 – Reserved

See: Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B, 3C & 3D): System Programming Guide – 6.3.1 External Interrupts
WR Pin: This pin connects to a write strobe signal (One of 8 on a Pentium)
RD Pin: This connects to the IOCR (Input Output Control Routine) signal.
INT Pin: Connects to the INTR pin on the microprocessor.
INTA Pin: Connects to the INTA pin on the microprocessor.
A0 Pin: Selects different Command WORDS
CS Pin: Enables the chip for programming and control.
SP/EN Pin: Slave program (SP) / Enable Buffer (EN).
Slave Program (1=Master, 0=Slave)
Enable Buffer (Controls data bus transievers when in buffered mode)
CAS0, CAS1, CAS2 Pins: Used to output from master to slave PIC controllers in cascaded systems.
D0 – D7 Pins: 8 bit Data connector pins.

x86 Hardware Interrupts
8259A Input pinInterrupt NumberDescription
IRQ00x08Timer
IRQ10x09Keyboard
IRQ20x0ACascade for 8259A Slave controller
IRQ30x0BSerial port 2
IRQ40x0CSerial port 1
IRQ50x0DAT systems: Parallel Port 2. PS/2 systems: reserved
IRQ60x0EDiskette drive
IRQ70x0FParallel Port 1
IRQ8/IRQ00x70CMOS Real time clock
IRQ9/IRQ10x71CGA vertical retrace
IRQ10/IRQ20x72Reserved
IRQ11/IRQ30x73Reserved
IRQ12/IRQ40x74AT systems: reserved. PS/2: auxiliary device
IRQ13/IRQ50x75FPU
IRQ14/IRQ60x76Hard disk controller
IRQ15/IRQ70x77Reserved

8259A Registers

  • Command Register – This is a write only register that is used to send commands to the microcontroller.
  • Status register – This is a read only register that can be accessed to determin the status of the PIC.
  • Interrupt Request Register (IRR) – This register specifies which interrupts are pending acknowledgment. Note: This register is internal, and cannot be accessed directly.
  • In-Sevice Register (ISR) – This register specifies which interrupts have already been acknowledged, but are awaiting for the End of Interrupt (EOI) signal.
  • Interrupt Mask Register (IMR) – This specifies what interrupts are to be ignored, and not acknowledged.

Programming with the 8259 PIC
When the computer boots, the default interrupt mappings are:
IRQ 0..7 – INT 0x8..0xF
IRQ 8..15 – INT 0x70..0x77
Each chip (master and slave) has a command port and a data port (given in the table below). When no command is issued, the data port allows us to access the interrupt mask of the 8259 PIC.

Chip – Purpose I/O port
Master PIC -Command0x0020
Master PIC – Data0x0021
Slave PIC -Command0x00A0
Slave PIC – Data0x00A1

8253/8254 PIT – Programmable Interval Time

Original source: http://heim.ifi.uio.no/~stanisls/helppc/8253.html

Spec documentation:  8254 PROGRAMMABLE INTERVAL TIMER

Port 40h, 8253 Counter 0 Time of Day Clock (normally mode 3)
Port 41h, 8253 Counter 1 RAM Refresh Counter (normally mode 2)
Port 42h, 8253 Counter 2 Cassette and Speaker Functions
Port 43h, 8253 Mode Control Register, data format:
	|7|6|5|4|3|2|1|0|  Mode Control Register
	 | | | | | | | `---- 0=16 binary counter, 1=4 decade BCD counter
	 | | | | `--------- counter mode bits
	 | | `------------ read/write/latch format bits
	 `--------------- counter select bits (also 8254 read back command)
Bits
76 Counter Select Bits
00 select counter 0
01 select counter 1
10 select counter 2
11 read back command (8254 only, illegal on 8253, see below)
Bits
54 Read/Write/Latch Format Bits
00 latch present counter value
01 read/write of MSB only
10 read/write of LSB only
11 read/write LSB, followed by write of MSB
Bits
321 Counter Mode Bits
000 mode 0, interrupt on terminal count; countdown, interrupt,

then wait for a new mode or count; loading a new count in the
middle of a count stops the countdown

001 mode 1, programmable one-shot; countdown with optional

restart; reloading the counter will not affect the countdown
until after the following trigger

010 mode 2, rate generator; generate one pulse after ‘count’ CLK

cycles; output remains high until after the new countdown has
begun; reloading the count mid-period does not take affect
until after the period

011 mode 3, square wave rate generator; generate one pulse after

‘count’ CLK cycles; output remains high until 1/2 of the next
countdown; it does this by decrementing by 2 until zero, at
which time it lowers the output signal, reloads the counter
and counts down again until interrupting at 0; reloading the
count mid-period does not take affect until after the period

100 mode 4, software triggered strobe; countdown with output high

until counter zero; at zero output goes low for one CLK
period; countdown is triggered by loading counter; reloading
counter takes effect on next CLK pulse

101 mode 5, hardware triggered strobe; countdown after triggering

with output high until counter zero; at zero output goes low
for one CLK period
Read Back Command Format (8254 only)
	|7|6|5|4|3|2|1|0| Read Back Command (written to Mode Control Reg)
	 | | | | | | | `--- must be zero
	 | | | | | | `---- select counter 0
	 | | | | | `----- select counter 1
	 | | | | `------ select counter 2
	 | | | `------- 0 = latch status of selected counters
	 | | `-------- 0 = latch count of selected counters
	 `----------- 11 = read back command
Read Back Command Status (8254 only, read from counter register)
	|7|6|5|4|3|2|1|0|  Read Back Command Status
	 | | | | | | | `--- 0=16 binary counter, 1=4 decade BCD counter
	 | | | | `-------- counter mode bits (see Mode Control Reg above)
	 | | `----------- read/write/latch format (see Mode Control Reg)
	 | `------------ 1=null count (no count set), 0=count available
	 `------------- state of OUT pin (1=high, 0=low)
  • the 8253 is used on the PC & XT, while the 8254 is used on the AT+
  • all counters are decrementing and fully independent
  • the PIT is tied to 3 clock lines all generating 1.19318 MHz.
  • the value of 1.19318MHz is derived from (4.77/4 MHz) and has it’s roots based on NTSC frequencies
  • counters are 16 bit quantities which are decremented and then tested against zero. Valid range is (0-65535). To get a value
    of 65536 clocks you must specify 0 as the default count since
    65536 is a 17 bit value.
  • reading by latching the count doesn’t disturb the countdown but reading the port directly does; except when using the 8254 Read
    Back Command
  • counter 0 is the time of day interrupt and is generated approximately 18.2 times per sec. The value 18.2 is derived from
    the frequency 1.10318/65536 (the normal default count).
  • counter 1 is normally set to 18 (dec.) and signals the 8237 to do a RAM refresh approximately every 15æs
  • counter 2 is normally used to generate tones from the speaker but can be used as a regular counter when used in conjunction
    with the 8255
  • newly loaded counters don’t take effect until after a an output pulse or input CLK cycle depending on the mode
  • the 8253 has a max input clock rate of 2.6MHz, the 8254 has max input clock rate of 10MHz

Programming considerations:

1. load Mode Control Register
2. let bus settle (jmp $+2)
3. write counter value
4. if counter 0 is modified, an INT 8 handler must be written to

call the original INT 8 handler every 18.2 seconds. When it
does call the original INT 8 handler it must NOT send and EOI
to the 8259 for the timer interrupt, since the original INT 8
handler will send the EOI also.

Example code:

	countdown  equ	8000h ; approx 36 interrupts per second
	   cli
	   mov	al,00110110b  ; bit 7,6 = (00) timer counter 0
				  ; bit 5,4 = (11) write LSB then MSB
				  ; bit 3-1 = (011) generate square wave
				  ; bit 0 = (0) binary counter
	   out	43h,al	      ; prep PIT, counter 0, square wave&init count
	   jmp	$+2
	   mov	cx,countdown  ; default is 0x0000 (65536) (18.2 per sec)
				  ; interrupts when counter decrements to 0
	   mov	al,cl	      ; send LSB of timer count
	   out	40h,al
	   jmp	$+2
	   mov	al,ch	      ; send MSB of timer count
	   out	40h,al
	   jmp	$+2

Removing the Mystery from SEGMENT : OFFSET Addressing

Note:  Pulled from Wayback Machine, page no longer existed.  Copyright©2001, 2007 by Daniel B. Sedory 

This page may be freely copied for PERSONAL use ONLY !  ( It may NOT be used for ANY other purpose unless you have first contacted and received permission from the author! )

For information on using MS-DEBUG, see A Guide to DEBUG.

Section 1. Introduction, Definitions and Statistics
Section 2. Visualizing the Overlapping Segments

  • The Upper Memory Area (UMA)
  • The High Memory Area (HMA)

Section 3. Normalized Segment:Offset Notation
Section 4. Problems when Segment Register Values are not considered !

Introduction.

There are often many different Segment:Offset pairs which can be used to address the same location in your computer’s memory. This scheme is a relative way of viewing computer memory as opposed to a Linear or Absolute addressing scheme. When an Absolute addressing scheme is used, each memory location has its own unique designation; which is a much easier way for people to view things. So, why did anyone ever create this awkward “Segment:Offset scheme” for dealing with computer memory? As an answer, here’s a brief lesson on the 8086 CPU with an historical slant:

Segment:Offset addressing was introduced at a time when the largest register in a CPU was only 16-bits long which meant it could address only 65,536 bytes (64 KiB[1]) of memory, directly. But everyone was hungry for a way to run much larger programs! Rather than create a CPU with larger register sizes (as some CPU manufacturers had done), the designers at Intel decided to keep the 16-bit registers for their new 8086 CPU and added a different way to access more memory: They expanded the instruction set, so programs could tell the CPU to group  two 16-bit registers together whenever they needed to refer to an Absolute memory location beyond 64 KiB.

If the designers had allowed the CPU to combine two registers into a high and low pair of 32-bits, it could have referenced up to 4 GiB[2] of memory in a linear fashion! Keep in mind, however, this was at a time when many never dreamed we’d need a PC with more than 640 KiB of memory for user applications and data![3] So, instead of dealing with whatever problems a linear addressing scheme of 32-bits would have produced, they created the Segment:Offset scheme which allows a CPU to effectively address about 1 MiB of memory.[4]

The scheme works like this: The value in any register considered to be a Segment register is multiplied by 16 (or shifted one hexadecimal byte to the left; add an extra 0 to the end of the hex number) and then the value in an Offset register is added to it. So, the Absolute address for any combination of Segment and Offset pairs is found by using the formula:

Absolute
Memory
Location  

= (Segment value * 16) + Offset value

After working through some examples, this will become much clearer to understand: The Absolute or Linear address for the Segment:Offset pair, F000:FFFD can be computed quite easily in your mind by simply inserting a zero at the end of the Segment value ( which is the same as multiplying by 16 ) and then adding the Offset value:

F0000 + FFFD —— FFFFD or 1,048,573(decimal) Here’s another example: 923F:E2FF -> 923F0 + E2FF —— A06EF or 657,135(decimal)

Now let’s compute the Absolute Memory location for the largest value that can be expressed using a Segment:Offset reference:

FFFF0 + FFFF ——- 10FFEF or 1,114,095 (decimal)

In reality, it wasn’t until quite some time after the 8086, that such a large value actually corresponded to a real Memory location. Once it became common for PCs to have over 1MiB of memory, programmers developed ways to use it to their advantage and this last byte became part of what’s now called the HMA (High Memory Area). But until that time, if a program tried to use a Segment:Offset pair that exceeded a 20-bit Absolute address (1MiB), the CPU would truncate the highest bit (an 8086/8088 CPU has only 20 address lines), effectivelymapping any value over FFFFFh (1,048,575) to an address within the first Segment. Thus, 10FFEFh was mapped to FFEFh.[5]

One of the downsides in using Segment:Offset pairs (and likely what confuses most of you) is the fact that a large number of these pairs refer to the same exact memory locations. For example, every Segment:Offset pair below, refers to exactly the same location in memory:

0007:7B90 0008:7B80 0009:7B70 000A:7B60 000B:7B50 000C:7B40 0047:7790 0048:7780 0049:7770 004A:7760 004B:7750 004C:7740 0077:7490 0078:7480 0079:7470 007A:7460 007B:7450 007C:7440 01FF:5C10 0200:5C00 0201:5BF0 0202:5BE0 0203:5BD0 0204:5BC0 07BB:0050 07BC:0040 07BD:0030 07BE:0020 07BF:0010 07C0:0000

The Segment:Offset pairs listed above are only some of the many
ways one can refer to the single Absolute Memory location of:

7C00h (or 0000:7C00).

As a matter of fact there may be up to 4,096 different Segment:Offset pairs for addressing a single byte in Memory; depending upon its particular location. For Absolute addresses 0h through FFEFh ( 0 through 65,519 ), the number of different pairs can be computed as follows: Divide the Absolute address by 16 ( which shifts all the hex digits one place to the right ), then throw away any fractional remainder and add 1. This is the same thing as saying: Add 1 to the Segment number if the Offset is 000Fh (15) or less. For example, the byte in memory referenced by the Segment:Offset pair 0040:0000 has a total of 41h (or 65) different pairs that might be used. For the Absolute address 7C00h, which was mentioned above, there’s a total of: 7C00 / 10h –> 7C0 + 1 = 7C1 (or 1,985) relative ways to address this same memory location using Segment:Offset pairs. For the Absolute addresses from FFF0h (65,520) all the way through FFFFFh (1,048,575), there will always be 4,096 Segment:Offset pairs one could use to refer to these addresses! That’s a little over 88% of the memory that can be accessed using Segment:Offsets. The last 65,520 bytes that can be accessed by this method are collectively called the High Memory Area (HMA). For each 16 bytes higher in the HMA that we point to, there is one less Segment:Offset pair available to reference that paragraph.

Due to the sheer number of possible Segment:Offset pairs for each address, most programmers have agreed to use the same normalization method (see the note below on Normalized Notation) when writing about a particular location in Memory.

We’ve created some graphic illustrations to help you picture the boundaries between various areas of Memory:

Visualizing the Overlapping Segments

The following illustrations should help students visualize the artificial layout of the Segment boundaries in a system’s Memory.

SEGMENTS are more like a mental construct or a way of visualizing a computer’s Memory, rather than being closely tied to the physical hardware itself. In Figure 0, we’ve tried to show how each Segment of 65,536 bytes overlaps most of  the preceding Segment. As you can see, each Segment begins only 16 bytes (or a paragraph) after the preceding one. In computer terminology, a paragraph is used to refer to 16 consecutive bytes of Memory. For every 16 bytes higher in Memory that we point to, the number o
f overlapping Segments will increase by one until we arrive at the end of the first Segment. At that point, each successive paragraph of Memory (up to 1MiB) has a constant number of 4,096 overlapping Segments! Figure 0 also shows the Segment:Offset values for each of the four corners of the first five of Segments.

In Figure 1 (see below), the focus is on just the beginning of Segments 1, 2, 3 and so on, rather than the whole Segment. Notice how the first 16 bytes of memory appear in the Figure. There’s only one segment there: no other segments overlap these bytes. Therefore, the Segment:Offset pairs for each of the first 16 bytes in memory is actually unique! There’s only one way to refer to them: with the Segment value of 0000: and one of the 16 Offsets, 0000 through 000F hex. The next 16 bytes in memory (10h through 1Fh) will each have preciselytwo different Segment:Offset pairs that can be used to address them. For each of the first five Segments, the exact number of equivalent Segment:Offset pairs for the last byte in the paragraph has been shown in the aqua (light-blue) colored boxes.

(For comments on the part of Figure 1 under the BLUE line, see text below.)

The second part of Figure 1 above, shows what happens at the transition from a paragraph of memory that is still within the boundary of the first 64kb Segment (Absolute addresses FFF0h through FFFFh) to those paragraphs which are beyond its boundary (10000h and following). Note that the first paragraph of Segment 0FFF: (which is the same as the last 16 bytes within Segment 0000:) is the first paragraph in Memory to have a total of 4,096 different Segment:Offset pairs that could be used to reference its bytes.

Figure 2 shows that Segment 9000: is the last whole 64kb segment to lie within the bounds of what’s called ” Conventional Memory ” ( the first 640kb or 655,360 bytes). The first paragraph of Segment A000: is the beginning of the Upper Memory Area (UMA). The UMA contains a total of 384kb or 393,216 bytes. Segment F000: is the last whole segment that lies within the bounds of the UMA.

640 KiB + 384 KiB = 1024 KiB (or 1,048,576 bytes) = 1 Mebibyte.
(A long time ago, the UMA was called the ‘Reserved Area.’)

Another way of looking at the first 1MiB of Memory (and hopefully something that will help those who might still be a bit confused ) is the fact that each of these 1,048,576 bytes can be accessed by using one of just the following 16 Segment references ( none of which overlap any of the others): 0000:1000:2000:, … 9000: and A000: through F000: plus one of their 65,536 Offsets. Although it would really be nice if we could always refer to a particular byte in Memory using just these 16 Segments, that would be rather wasteful of memory resources: When it comes time for an OS like Windows to assign a full 64kb of free memory to an App such as DEBUG, it’s not simply a matter of convenience for it to use the very first 16-byte Segment reference of continuous memory that it can find. Moving up to the next even 1000h Segment would leave even more unused holes in Memory than there are already! (There is, however, an agreed upon convention called Normalized Addressing which has been very helpful.)

Figure 3 shows the end of the UMA and the beginning of the last Segment (Segment FFFF:) in the Segment:Offset scheme. When the 8086 was first created, there wasn’t even 640kb of memory in most PCs. And as you might recall from our history lesson above, addresses in this part of the Segment:Offset scheme were first mapped to bytes in Segment 0000. Later, the memory above 1MiB that could still be accessed using Segment:Offset pairs became known as The High Memory Area (HMA).

The High Memory Area (HMA) contains only one paragraph short of 64kb (or just 65,520 bytes). Segment FFFF: is the only segment that can reach the last 16 bytes of the HMA. Here’s a text file of a boring Table of HMA Segment:Offset pairs which shows how the number of pairs decreases to only one for the last 16 bytes of the HMA.

Normalized Segment:Offset Notation

Since there are so many different ways that a single byte in Memory might be referenced using Segment:Offset pairs, most programmers have agreed to use the same convention tonormalize all such pairs into values that will always be unique. These unique pairs are called a Normalized Address or Pointer.

By confining the Offset to just the Hex values 0h through Fh (16 hex digits); or a single paragraph and setting the Segment value accordingly, we have a unique way to reference all Segment:Offset Memory pair locations. To convert an arbitrary Segment:Offset pair into a normalized address or pointer is a two-step process that’s quite easy for an assembly programmer:

Convert the pairs into a single physical (linear) address.

Then simply insert the colon (:) between the last two hex digits!

For example, in order to normalize 1000:1B0F, the steps are:

1000:1B0F  11B0Fh  11B0:F (or 11B0:000F)

Since the normalized form will always have three leading zero bytes in its Offset, programmers often write it with just the digit that counts as shown here: 11B0:F (when you see an address like this, it’s almost a sure sign that the author is using this normalized notation).

How Segment:Offset notation can lead to Problems

The normalized notation for the first byte where all PC BIOS must place a floppy diskette’s boot strap code is: 07C0:0 (or 07C0:0000). A big problem for some PC manufacturers came about when some BIOS writer assumed that there’d be nothing wrong with jumping to the bootstrap code at that particular Segment:Offset pair, since it’s the same memory location as0000:7C00.
Somehow they never took into consideration the fact that the standard used by everyone else always set the SEGMENT values to ZERO. Therefore, a bootstrap code programmer could assume all Segment values (Code, Data, etc.) were zero and only have to deal with the Offset values in that Segment. Along comes this BIOS chip clone that sets the Code Segment to 07C0 (using a JMP 07C0:000 instruction), and suddenly there was a big problem getting most OS bootstrap code (including Microsoft® and IBM® OSs) to boot up in these computers! This is why some bootstrap code, such as that in the GRUB Boot Manager, will add extra instructions to make sure the Segment Registers have been set correctly! One of the authors of GRUB comments that his Long Jump code was necessary “because some bogus BIOSes jump to 07C0:0000 instead of 0000:7C00.”

Footnotes

1[Return to Text] KiB is the abbreviation for a kibibyte (a contraction of kilo binary byte) or binary kilobyte. It is equal to 2 to the 10th power (2^10) or 1024 bytes. Likewise, MiB is a mebibyte (mega binary byte); equal to 2 to the 20th power (2^20) or 1,048,576 bytes, and GiB is a gibibyte (giga binary byte); equal to 2
to the 30th power (2^30) or 1,073,741,824 bytes. In this document, which refers to memory in early IBM PCs (and the Intel 8086 and 80286 CPUs), we may at times refer to kibibytes using the abbreviation “kb” instead of KiB. (It is taking a long time for “kibi-“, “mebi-” and “gibi-” to be recognized by techs and computer sales departments as the proper way to refer to memory ; even though they have been in official standards organizations for many years. See, for example,  NIST: Prefixes for binary multiples, and  IEC: Prefixes for binary multiples.)

64 KiB is also equal to 2 to the 16th power [ (2^16) = (2^10) x (2^6) = (1024) x (64) = 65,536 bytes, and each of the two-byte (or 16-bit) registers in an 8086 CPU can contain a maximum value of: 1111 1111 1111 1111 in binary or FFFFh (hexadecimal). In decimal, that’s[(15 x 16^3) + (15 x 16^2) + (15 x 16^1) + 15] = [(15 x 4096) + (15 x 256) + (15 x 16) + 15] = 61,440 + 3,840 + 240 + 15 = 65,535. However, since memory always begins with zero (0) as its first location, that gives us 65,535 + 1 = 65,536 (or, 16^4) memory locations. 65,536 divided by 1024 per KiB = 64 KiB of memory. For more on the use of Hexadecimal in computers, see: What Is “Hexadecimal”?

2[Return to Text] This is 4 gibibytes (see Footnote #1) or times (2^30= 4,294,967,296 bytes.

3[Return to Text] We’ve often heard that Bill Gates said something to the effect: 640K of memory should be enough for anyone. Though many of us no longer believe he ever said those exact words (and he has finally made some public denials concerning this), he did, however, during a video interview with David Allison in 1993 for the National Museum of American History, Smithsonian Institution, say: I laid out memory so the bottom 640K was general purpose RAM and the upper 384 I reserved for video and ROM, and things like that. That is why they talk about the 640K limit. It is actually a limit, not of the software, in any way, shape, or form, it is the limit of the microprocessor. That thing generates addresses, 20-bits addresses, that only can address a megabyte of memory. And, therefore, all the applications are tied to that limit. It was ten times what we had before. But to my surprise, we ran out of that address base for applications within — oh five or six years people were complaining. (from  a trascript of the interview, under the “Microsoft and the Mouse” section). For a bit more info, see:  Did Bill Gates say the 640k line? and perhaps of more interest to others, here are some  verifiable quotes from Mr. Gates.

4[Return to Text] 1 MiB of memory is 1,048,576 bytes (2^20 bytes), but the Segment:Offset addressing scheme actually allows one to access up to 10FFEFh, plus one, bytes of memory, or 1,114,096 bytes. We’ll have more to say about this and the HMA (High Memory Area) shortly.

5[Return to Text] As we said above, until an IBM PC (or clone) actually had more than 1MiB of memory, it was expedient for the early IBM PCs to effectively wrap-around to the beginning of memory whenever programs tried to access an address past FFFFFh bytes.
[Sorry, this FOOTNOTE IS STILL UNDER CONSTRUCTION! It will soon have some links about the IBM PC AT model’s keyboard and the infamous A20 line!]

Last Revised: 15 OCT 2007 (15.10.2007).