Básicamente los segmentos no son más que definiciones que emplea el linker para colocar el código ensamblado. Esto, por ejemplo, en un VIC20, es muy necesario, porque la configuración que tiene de memoria no es continua y no puedes colocar lo que te dé la gana donde quieras.
Por ejemplo, si generas ejecutables para un VIC-20 expandido (con 8Kb por ejemplo), los segmentos se emplean para especificar cómodamente qué código va en la RAM principal, dónde se ubica la memoria de color y la de caracteres, y qué código va en la ram expandida.
Por ejemplo, en la configuración de memoria que uso para VIC-20 (bueno, que uso es un decir, porque la "usé" para hacer pruebas pero, por falta de tiempo, lo tengo bastante abandonado), primero se define el mapa de memoria:
MEMORY {
RAM0: start = $0400, size = $0C00, type = rw;
RAM: start = $11FF, size = $0201, type = rw, fill = yes;
SCR: start = $1400, size = $0400, type = ro, fill = yes;
BUF: start = $1800, size = $0400, type = rw, fill = yes;
CHAR: start = $1C00, size = $0400, type = rw, fill = yes;
RAM1: start = $2000, size = $2000, type = rw;
RAM2: start = $4000, size = $2000, type = rw;
RAM3: start = $6000, size = $2000, type = rw;
RAM4: start = $8000, size = $2000, type = rw;
ROM1: start = $A000, size = $1000, type = ro;
ROM2: start = $B000, size = $1000, type = ro;
}
Básicamente especifica qué tipo de memoria hay en cada intervalo, cuanto ocupa, y si es de escritura, o de sólo lectura, etc. Luego, sobre ese mapa de memoria, ubicamos nuestros segmentos:
SEGMENTS {
BASIC: load = RAM, type = ro, define = yes, optional = no;
STARTUP: load = RAM, type = ro, define = yes, optional = no;
MYCHAR: load = CHAR, type = rw, define = yes, optional = no;
CODE: load = RAM1, type = ro, define = yes, optional = no;
}
Se definen cuatro segmentos: el segmento BASIC y STARTUP se definen en la RAM principal. El segmento MYCHAR, donde irá la definición de mi set de caracteres, se coloca en la zona CHAR. Por último, el segmento CODE se coloca en la ram expandida, o sea, RAM1 del mapa de memoria.
Por último, se define el punto de entrada del autoejecutable:
FEATURES {
STARTADDRESS: default = $11FF;
}
Como véis, apunta al principio de la zona RAM.
Luego, en tu código, sólo indicas en qué segmento estás colocando cada cosa. Primero se define lo que hay en el segmento "BASIC", que es código BASIC a pelo. Este código llama al programa en ML:
.segment "BASIC"
.word RUN ; load address
RUN: .word END ; next line link
.word 2010 ; line number
.byte $9E ; BASIC token: SYS
.byte <(MAIN / 1000 .mod 10) + $30
.byte <(MAIN / 100 .mod 10) + $30
.byte <(MAIN / 10 .mod 10) + $30
.byte <(MAIN / 1 .mod 10) + $30
.byte 0 ; end of line
END: .word 0 ; end of program
La directivao .segment "BASIC" lo que hará será ensamblar el código que venga debajo en la zona de RAM donde esté definido dicho segmento.
A continuación se define el código que va en el segmento "STARTUP", que lo que hace es iniciar el VIC y saltar al programa principal, que está en la RAM expandida:
.segment "STARTUP"
MAIN:
LDA #$00+$16 ; set for videoram @ $1400 with 22-columns
STA VIC+$02 ; video matrix address + columns
LDA #%10101110 ; 8x8 height + 23-rows
STA VIC+$03 ; rows / character height
LDA #$DF ; set video @ $1400 and char table @ $1C00
STA VIC+$05
LDA #%01101111 ; Programmer's Reference Guide: Appendix B
STA VIC+$0F
LDA #$FF
STA VIC+$0E
.global MTMYSTART ; useful symbol for MAP and hotkey restarting
JMP MTMYSTART ; the entry point into your program
Luego defino mi set de carácteres, en el segmento MYCHAR, que se colocará, tal y como hemos definido, en el lugar correcto:
.segment "MYCHAR"
SP_PL_R_1:
.byte %00000000
.byte %00001010
.byte %00101010
.byte %00101010
.byte %00101010
.byte %10101001
.byte %10100100
.byte %00101100
.byte %00000000
.byte %10100000
.byte %10101000
.byte %10101000
.byte %10101000
.byte %01010100
.byte %01000100
.byte %11001100
(etcétera)
Y, por último, poblamos el segmento CODE, situado en la RAM expandida, con el código del juego:
.segment "CODE"
MTMYSTART:
JSR CLEARSCREEN
LDA #2
STA TX
STA TY
LDA #0
STA TN
JSR VIC_PSPRITE
(etcétera)
Al ensamblar todo esto, los cachos de código objeto se colocarán en las ubicaciones correctas y todo irá como la seda. Es una forma muy cómoda de organizar la memoria sin tener que hacerlo manualmente generando varios binarios y toda la pesca.
Para un C64 será algo parecido, teniendo en cuenta el mapa de memoria de este sistema.
Haciendo una "adivinación valiente", yo diría que, para el ejemplo del que trata este hilo, bastaría con modificar el fuente para que se pareciese a:
.segment STARTUP
inc $D020
jmp $2000
.segment ZPSAVE
Supongo que ZPSAVE (con ZP = ZERO PAGE) será para dar de un plumazo valor a todas las direcciones importantes de la ZP.