Remember we are in 16 bit mode. That means the size of every register is 16 bit only. So how much memory can we access using a 16-bit address? 2^16 = 65,536 Bytes that’s only 64 KB.

But 64 KB was not sufficient as the complexity of the software grows the demand for memory also increased with it.

Intel solution to this was using a 20 bit address line instead of 16 bit. This would increase the memory accessible from 64 KB to 1 MB.

2^20 = 10,48,576 that would be 1 MB.

How did Intel did that?

They introduced a new category of a register called segment register.

  • DS (Data Segment)
  • CS (Code Segment)
  • SS (Stack Segment)
  • ES
  • FS
  • GS

Side note: Among these CS always contains the segment currently code is executing and you can’t set it using MOV instruction. This register contains the segment address.

Now all the addresses are represented using a segment address pair like DS:DI where DS defines the start of the segment and the final address is calculated by adding both the address. Just one trick here. segement register(DS in this case)is left shifted by 4 bit before adding it to DI

  • Orange area is the current segement.
  • The number on the top and bottom of the segment is the start and end address of the segment.
  • DS:DI arrow point the address within the segment.
  • Two or more segments can overlap with each other.
  • Images are not to scale

Calculate physical address

Let’s take the example of DS:DI. We would be using the below formula to calculate the physical address.

physical address = (DS * 0xF) + DI 

Few more things about segment register

You can’t use any register with any segment register.

Segement Offset registers Description
CS IP Code pointer
DS BX, DI, SI Data pointer
SS SP, BP Stack pointer
ES BX, DI, SI Used as destination address

Table source

Time to revisit the hello world program!

Let’s now clear the segment address that I skipped in the previous post. Link to the post

Bootloader memory layout

(Image not to scale)

Our message Hello world is present in the section highlighted using blue. To access it we can follow two-approach either set segment register at 0 or set the segment register at 0x7C00

We’re going to cover both the approach.

When segment register is set to 0x0

First, we need to tell our assembler to calculate all the address from 0x7C00 using ORG command and set the offset register to start of our string address.

BITS 16
ORG 0x7C00

main:
  MOV AX, 0
  MOV DS, AX
  MOV SI, msg
  CALL print_string

msg DB "Hello World", 0

(Removed print_string and other bootstrap code for simplicity)

Can you guess, What is the address in the SI register?

  1. MOV SI, 0x7c16
  2. MOV SI, 0x16

When segment register is set to 0x7C00

BITS 16
ORG 0

main:
  MOV AX, 0x7C0
  MOV DS, AX
  MOV SI, msg
  CALL print_string

msg DB "Hello World", 0

(Removed print_string and other bootstrap code for simplicity)

DS register is 0x7C0, not 0x7C00 because the segment register is left sift by 4 bit before added.

References