Why does 8086 segment addressing not overflow? - x86-16

I know that the 8086 addressing mode is a left shift of the segment register by four bits then add an offset. But will the information of significant bit not be lost after shifting the 16-bit register?
For example, the segment register stores 0x1000, will it not become 0x0000 after shifting four bits to the left?

Address calculation happens with 20-bit math. Or more on later CPUs. Not the same width as the inputs. The CPU doesn't shift inside the segment reg!
In CPUs that don't support other modes (like protected mode where the base comes from the GDT), I assume the selected segment register is just hard-wired to bits [20:4] of an adder in the AGU, so the "shift" is just built-in to the wiring. Not like when you run a shift instruction and the result goes back into the destination.
(Actual 8086 didn't have an AGU separate from its ALU, so presumably that's what happens when using that block of logic to do address math instead of 16-bit normal integer math. It also supports a mul instruction which produces a 32-bit product, that has to get split across DX:AX when it's done, but internally the ALU has to shift and add numbers across 16-bit boundaries for multiply to work.)

Related

Question about memory space in microprocessor

My teacher has given me the question to differentiate the maximum memory space of 1MB and 4GB microprocessor. Does anyone know how to answer this question apart from size mentioned difference ?
https://i.stack.imgur.com/Q4Ih7.png
A 32-bit microprocessor can address up to 4 GB of memory, because its registers can contain an address that is 32 bits in size. (A 32-bit number ranges from 0 to 4,294,967,295‬). Each of those values can represent a unique memory location.
The 16-bit 8086, on the other hand, has 16-bit registers which only range from 0 to 65,535. However, the 8086 has a trick up its sleeve- it can use memory segments to increase this range up to one megabyte (20 bits). There are segment registers whose values are automatically bit-shifted left by 4 then added to the regular registers to form the final address.
For example, let's look at video mode 13h on the 8086. This is the 256-color VGA standard with a resolution of 320x200 pixels. Each pixel is represented by a single byte and the desired color is stored in that byte. The video memory is located at address 0xA0000, but since this value is greater than 16 bits, typically the programmer will load 0xA000 into a segment register like ds or es, then load 0000 into si or di. Once that is done, the program can read from [ds:si] and write to [es:di] to access the video memory. It's important to keep in mind that with this memory addressing scheme, not all combinations of segment and offset represent a unique memory location. Having es = A100/di = 0000 is the same as es=A000/di=1000.

Generating address of a instruction using Code Segment and Instruction Pointer

Consider the Code Segment Address to be FE00 and Instruction Pointer to be ABBE. Shifting the Code Segment by 4 bits and Adding the Instruction pointer leads to an additional carry. How do we represent the generated address?
Consider the Code Segment Address to be FE00 and Instruction Pointer to be ABBE. How do we represent the generated address?
Either you represent the address as
0FE00h:0ABBEh, its segmented form using two 16-bit numbers separated by a colon and always (segment - colon - offset)
00108BBEh, its linear form using one 32-bit number
No matter your choice it will always require 2 word sized registers on 8086.
"The instruction pointer is an offset in the 64KB memory segment that starts at the linear address obtained from multiplying the value in the CS code segment register by 16 (same as shifting left 4 times)."
Calculating the linear address could be done inefficiently (but easy to understand) like this:
mov ax, 0FE00h ; The code segment
mov dx, 16
mul dx ; "shifting the code segment by 4 bits"
add ax, 0ABBEh ; "adding the instruction pointer"
adc dx, 0 ; Taking care of the additional carry
This linear address 00108BBEh uses 2 registers AX and DX. The AX register will hold the least significant part 8BBEh and the DX register will hold the most significant part 0010h. If you need to refer to the whole pair of registers you do it like DX:AX. So highWord - colon - lowWord.
Unlike with seg:off notation, this is just one 32-bit number split over 2 registers, no overlapping place values. The low bit of the high half has place value 2^16 when we're talking about a flat 32-bit (or 20-bit) number, not a seg:off address.

Why is the register length static in any CPU

Why is the register length (in bits) that a CPU operates on not dynamically/manually/arbitrarily adjustable? Would it make the computer slower if it was adjustable this way?
Imagine you had an 8-bit integer. If you could adjust the CPU register length to 8 bits, the CPU would only have to go through the first 8 bits instead of extending the 8-bit integer to 64 bits and then going through all 64 bits.
At first I thought you were asking if it was possible to have a CPU with no definitive register size. That make no sense since the number and size of the registers is a physical property of the hardware and cannot be changed.
However some architecture let the programmer work on a smaller part of a register or to pair registers.
The x86 does both for example, with add al, 9 (uses only 8 bits of the 64-bit rax) and div rbx (pairs rdx:rax to form a 128-bit register).
The reason this scheme is not so diffuse is that it comes with a lot of trade-offs.
More registers means more bits needed to address them, simply put: longer instructions.
Longer instructions mean less code density, more complex decoders and less performance.
Furthermore most elementary operations, like the logic ones, addition and subtraction are already implemented as operating on a full register in a single cycle.
Finally, one execution unit can handle only one instruction at a time, we cannot issue eight 8-bit additions in a 64-bit ALU at the same time.
So there wouldn't be any improvement, nor in the latency nor in the throughput.
Accessing partial registers is useful for the programmer to fan-out the number of available registers, so for example if an algorithm works with 16-bit data, the programmer could use a single physical 64-bit register to store four items and operate on them independently (but not in parallel).
The ISAs that have variable length instructions can also benefit from using partial register because that usually means smaller immediate values, for example and instruction that set a register to a specific value usually have an immediate operand that matches the size of register being loaded (though RISC usually sign-extends or zero-extends it).
Architectures like ARM (presumably others as well) supports half precision floats. The idea is to do what you were speculating and #Margaret explained. With half precision floats, you can pack two float values in a single register, thereby introducing less bandwidth at a cost of reduced accuracy.
Reference:
[1] ARM
[2] GCC

Why 8051 don't have R0 to R32

In 8051 memory bank (00h to 1Fh), 8051 provide 32 registers as 8 registers(R0 t0 R7) to each of 4 banks.
Why these registers are not given as R0 to R31?
Thanks in Advance..
Many instruction opcodes are only 8 bits long; if all 32 registers were accessible in one of these instructions then there would be only 3 bits left to encode the instruction length and the operation. Similarly, two byte instructions often use the second byte to encode a full 8-bit operand (eg., an address), and have effectively the same constraint.
In many instances it is possible to refer to the register you need by its absolute address, using a longer instruction, but if you will access it frequently then it may be better to change the active bank so that you can use more short opcodes.
As far as I remember you can access only 8 of those register at a time. To access one of the other groups you need to switch the bank. I guess it has something to do with a instruction operand being only 3 bits long (and not 5 bits).

Why do segments begin on paragraph boundaries?

In real mode segmented memory model, a segment always begins on a paragraph boundary. A paragraph is 16 bytes in size so the segment address is always divisible by 16. What is the reason/benefit of having segments on paragraph boundaries?
It's not so much a benefit as an axiom - the 8086's real mode segmentation model is designed at the hardware level such that a segment register specifies a paragraph boundary.
The segment register specified the base address of the upper 16 bits of the 8086's 20 bit address space, the lower 4 bits of that base address were in essence forced to zero.
The segmented architecture was one way to have the 8086's 16-bit register architecture be able to address a full megabyte(!) of address space (which requires 20 bits of addressing).
For a little more history, the next step that Intel took in the x86 architecture was to abstract the segment registers from directly defining the base address. That was the 286 protected mode, where the segment register held a 'selector' that instead of defining the bits for a physical base address was an index into a a set of descriptor tables that held information about the physical address, permissions for access to the physical memory, and other things.
The segment registers in modern 32-bit or larger x86 processors still do that. But with the address offsets being able to specify a full 32-bits of addressing (or 64-bits on the x64 processors) and page tables able to provide virtual memory semantics within the segment defined by a selector, the programming model essentially does away with having to manipulate segment registers at the application level. For the most part, the OS sets the segment registers up once, and nothing else needs to deal with them. So programmers generally don't even need to know they exist anymore.
The 8086 had 20 address lines. The segment was mapped to the top 16, leaving an offset of the bottom 4 lines, or 16 addresses.
The Segment register stores the address of the memory location where that segment starts. But Segment registers stores 16 bit information. This 16 bit is converted to 20 bits by appending 4 bits of 0 to the right end of the address. If a segment register contains 1000H then it is left shifted to get 10000H. Now it is 20 bits.
While converting we added 4 bits of 0 to the end of the address. So every segment in memory must begin with memory location where the last 4 bits are 0.
For ex:
If a segment starts at 10001H memory location, we cannot access it because the last 4 bits are not 0.
Any address in segment register will be appended with 4 bits in right end to convert to 20bits. So there is no way of accessing such an address.

Resources