Es que el tema resulta trivial...
Sea el caso del procesador 8086, el bus de datos es de 16bits, en tanto que el bus de direcciones es de 20bits.
Mientras que 16 bits direccionan 65.536 posiciones de memoria, 4 bits más (es decir 20bits), direccionan 1Mb.
Si divides 1Mb. entre los 64kb. tienes 16, que son el número de páginas que tiene 1Mb. 16 páginas son precisamente los valores que codifican 4bits.
Asi a las direcciones se les antepone el código de página:
pagina: Dirección16bits
0000:0000.0000-0000.0000
Y ya con los 20 bits se obtiene la dirección absoluta.
La dirección de 16bits, es relativa en la página, es decir, va desde 0 hasta 65.535.
Pongamos que la página es la 5 y pongamos que la dirección en la pagina es 22.222,
la dirección real se calcula como::
nºpagina x 65.536 + direccion relativa
Y que por tanto, para el jemplo será:
5*65.536 + 22.222 = 327.680 + 22.222 = 349.902
Igualmente puede ponerse en binario (por ejemplo en la calculadora) y luego pasarlo a decimal
página 5: Dir relativa; 22.222
0101:0101.0110-1100.1110 = 349.902
Esto sería como tener un mazo de 16 cartas, donde cada una de ellas representara 64kb.
Esto de más arriba, sin embargo es la explicación ideal...
...es decir la entrada para poder empezar a entender como es realmente.
A la página se le llama segmento y a la dirección relativa, desplazamiento..
Puesto que los registros en el 8086, son de 16 bits, incluído el registro IP.
La solución adoptada, aunque ingeniosa estuvo limitando la accesibilidad a la memoria, dejando en hándicap al PC frente a otros procesadores... y así se crearon los llamados registros de segmento.
La dirección física se compone realmente de dos registros:
El de segmento, y uno de propósito general que formaliza el 'offset' (desplazmaiento dentro del segmento).
En la explicación ideal, si se mira bien, si se repara lo suficiente, presenta un problema y es que como toma 64kb.
exige que un bloque de un programa tenga que coincidir alojado exactamente en un segmento. Es decir resulta un problema si parte de un programa cae en un bloque y parte en otro, pués un único segmento no basta para acceder al programa.
Aprovechando que también los registros de segmento eran igualmente de 16 bits, se eligió otro modelo, y es el que explico a continuación:
El de segmento queda desplazado 4 posiciones hacia arriba (es como si fuera de 20, donde los 4 bits de menor peso estuvieren a 0), pero naturalmente el resto de los bits de ese registro pueden tener un valor arbitrario (no solo los 4 bits de menor peso).
Esto permite que pueda ubicarse en cualquier punto de la memoria (congruente con 16) el comienzo del bloque de 64kb.
Pero ahora en vez de haber 16 páginas de 64kb. ahora hay 64k.páginas de 16 bytes.
Esto permite que haya muchos pares segmento:desplazamiento (4096 exactamente, 65536/16=4096) que apunten a una misma dirección de memoria.
Ejemplo:
A - Registro de segmento:
1000.0010-0011.0101 = 33.333
1000.0010-0011.0101*16= 533.328
1000.0010-0011.0101-0000 nótese el desplazamiento a la izquierda de 4 bits.
B - desplazamiento:
0101.0110-1100.1110 = 22.222
C - Dirección física: 533.328 + 22.222 = 555.550
1000.0010-0011.0101-0000
------0101.0110-1100.1110
-----------------------------------
1000-0111.1010-0001.1110 = 555.550
Haz si quieres las cuentas en hexadecinal que cada nibble es una cifra, y se ve mejor...
Y si lo has seguido hasta aquí, te invito a que pongas los bits altos del registro de segmento a 1 y verifiques a qué dirección de memoria estaríamos accediendo???
Por lo demás el cálculo real sigue siendo el explicado en el razonamiento ideal...
En fin, no hace falta mucho código, simplemente un array y un par de 'registros'... y alguna funcionalidad de lectura y/o escritura...
Envió antes que caduque la sesión y me edito luego... con algo de código de ejemplo.
' El integer de VB6 no es 'unsigned', así que lo emulamos...
Private Type UInteger
Bajo As Byte ' bits 0-7 ' podría acederse de este modo fácilmente a AH y AL, etc...
Alto As Byte ' bits 8-15
End Type
Private Const c_MegaByte = (2 ^ 20) ' 1Mb.
Private Const c_Pagina = (2 ^ 16) ' 64Kb.
' 1Mb. de memoria.
Private s_Memoria(0 To c_MegaByte - 1) As Byte
Private s_DirFisica As Long
Private p_RegAX As UInteger ' registros de 16 bits.
Private p_RegIP As UInteger
Private p_RegCS As UInteger
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Property Get Segmento() As UInteger
Segmento = p_RegCS
End Property
Private Property Let Segmento(ByRef X As UInteger)
p_RegCS = X
Call CalculaDireccionFisica
End Property
Private Property Get IP() As UInteger
IP = p_RegIP
End Property
Private Property Let IP(ByRef X As UInteger)
p_RegIP = X
Call CalculaDireccionFisica
End Property
Private Property Get AX() As UInteger
AX = p_RegAX
End Property
Private Property Let AX(ByRef X As UInteger)
p_RegAX = X
End Property
Private Property Get DireccionFisica() As Long
DireccionFisica = s_DirFisica
End Property
Private Sub CalculaDireccionFisica()
Dim X As Long
s_DirFisica = 0 ' al tener 4 bytes, primero los borramos todos...
Call CopyMemory(s_DirFisica, ByVal VarPtr(p_RegCS), 2)
Call CopyMemory(X, ByVal VarPtr(p_RegIP), 2)
s_DirFisica = ((s_DirFisica * 16) + X)
End Sub
Private Function StringToUInteger(ByRef Txt As String) As UInteger
Dim v As UInteger
Dim k As Long
k = Val(Txt)
v.Bajo = (k And 255)
v.Alto = (k \ 256)
StringToUInteger = v
End Function
Private Sub Command1_Click()
Segmento = StringToUInteger(Text1.Text)
IP = StringToUInteger(Text2.Text)
Text3.Text = DireccionFisica
End Sub
Private Sub Command2_Click()
Dim v As UInteger
AX = StringToUInteger(Text4.Text)
s_Memoria(s_DirFisica) = AX.Bajo
s_Memoria(s_DirFisica + 1) = AX.Alto
End Sub
Añade 3 textbox, con sendos labels, el textbox1 será el de 'segmento' y sí poner en el label, eñ textbox 2, será el desplazamiento, para el eejemplo la dirección IP, el tercer textbox, la dirección física.
Añade un bótón, introduce de entrada los valores de más arriba que puse d eejmplo: Segmento: 33.333 y desplazamiento 22.222, y a la vuelta en el textbox 3 tendrás el valor de la dirección física real.
Usa ese valor como índice en el array s_Memoria...
Solo resta indicar que si bien la memoria del 8086 son direcciones de 16bits... y el array está declarado en bytes... debemos acceder individualmente a cada byte (como señala el código dle 2º botón, o bien usar copymemory).
Añade un segundo boitón y un 4º textbox... con su label 'Valor', introduce un valor en el rango 0-65535 en el textbox4, y pulsa el botón 2, escribirá en la memoria dicho valor...
Puedes si quieres al iniciar el formulario, relenar con valores al azar el array y añadir un botón para leer de la memoria actual, el valor que contiene...
Podrías también añadir un avance del registro IP en 2 posiciones ...
En fin, como has sido parco en palabras, no he podido orientar el código convenientemente... si tratas de hacer algún emulador, ya tienes por donde tomarlo...