Module 6Módulo 6

Assembly and CEnsamblador y C

The same machine, two languages. How C compiles down to the instructions you already know. La misma máquina, dos lenguajes. Cómo C se compila a las instrucciones que ya conoces.

Santi Scagliusi, PhD

Two languages, one instruction setDos lenguajes, un solo juego de instrucciones

The compiler does not invent new operations. It emits the same MSP430 instructions you write by hand.El compilador no inventa operaciones nuevas. Emite las mismas instrucciones MSP430 que escribes a mano.

C sourceFuente en C
int add(int a, int b) { return a + b; }

A C compiler reads this and produces an assembly file.Un compilador de C lee esto y produce un archivo en ensamblador.

Assembly emittedEnsamblador emitido
ADD.W R13, R12 RET

Args arrive in R12 and R13. The sum stays in R12. The same instructions, fewer keystrokes.Los argumentos llegan en R12 y R13. La suma queda en R12. Las mismas instrucciones, menos tecleo.

file.c compilercompilador file.asm assemblerensamblador machine code in FRAMcódigo máquina en FRAM

C data types on a 16-bit coreTipos de datos de C en un núcleo de 16 bits

One word is 16 bits. A type that fits in a word is cheap. Anything wider costs extra instructions and memory accesses.Una palabra son 16 bits. Un tipo que cabe en una palabra es barato. Lo más ancho cuesta instrucciones y accesos a memoria extra.

Fits in a word or lessCabe en una palabra o menos
char1 B
short2 B
int2 B
pointerpuntero2 B

A pointer is 2 bytes: it holds a 16-bit address. One register, one instruction.Un puntero ocupa 2 bytes: guarda una dirección de 16 bits. Un registro, una instrucción.

Wider than a wordMás ancho que una palabra
long4 B
long long8 B
float4 B
double8 B

No floating-point hardware: float and double run as software library calls.Sin hardware de coma flotante: float y double se ejecutan con llamadas a librería.

Pick the smallest type that holds your value. The width you choose becomes the number of instructions.Elige el tipo más pequeño que contenga tu valor. El ancho que elijas se convierte en número de instrucciones.

The program skeletonEl esqueleto del programa

Every assembly program starts the same way: a code section, an entry label, stop the watchdog, set the stack, then run.Todo programa en ensamblador empieza igual: una sección de código, una etiqueta de entrada, parar el watchdog, fijar la pila y ejecutar.

.text ; code -> FRAM (0x4400) main: mov.w #WDTPW|WDTHOLD, &WDTCTL ; stop watchdog mov.w #0x2400, SP ; init stack pointer call #setup ; configure peripherals loop: ; ... main work ... jmp loop .intvec RESET_VECTOR, main ; 0xFFFE -> main

.text lands the code in FRAM at 0x4400..text coloca el código en FRAM en 0x4400.

Stop the watchdog first, or it resets the chip mid-run.Para el watchdog primero, o reinicia el chip a mitad.

.intvec writes main into 0xFFFE: where the CPU starts..intvec escribe main en 0xFFFE: donde arranca la CPU.

CALL pushes the return addressCALL apila la dirección de retorno

CALL saves the address of the next instruction on the stack, then jumps. RET pops it back into PC.CALL guarda en la pila la dirección de la siguiente instrucción y salta. RET la recupera en el PC.

CallerLlamador
0x4410 call #add
0x4414 mov.w R12, sum ; return here
PC
Subroutine + stackSubrutina + pila
add: add.w R13, R12
ret
0x23FE 0x4414 return addrdir. retorno

RET is just MOV @SP+, PC. The saved address goes straight back into the program counter.RET es simplemente MOV @SP+, PC. La dirección guardada vuelve directa al contador de programa.

The stack frame, balancedEl marco de pila, equilibrado

A subroutine that uses R6 must save and restore it. Every PUSH needs a matching POP before RET.Una subrutina que use R6 debe guardarlo y restaurarlo. Cada PUSH necesita su POP antes de RET.

work: push.w R6 ; save R6 mov.w #0, R6 ; use it ; ... body ... pop.w R6 ; restore R6 ret ; SP balanced

When RET runs, the top of the stack must hold the return address, not your saved R6. PUSH and POP keep SP balanced.Cuando se ejecuta RET, la cima de la pila debe contener la dirección de retorno, no tu R6 guardado. PUSH y POP mantienen el SP equilibrado.

Inside work, after PUSHDentro de work, tras PUSH grows upcrece hacia arriba
0x2400 -- -- callerllamador
0x23FE 0x4414 return addrdir. retorno
0x23FC old R6 ← SP

Low address at the bottom, near SP. CALL wrote 0x4414; PUSH put old R6 below it.Dirección baja abajo, junto a SP. CALL escribió 0x4414; PUSH puso el R6 antiguo debajo.

The calling conventionLa convención de llamada

A shared contract so C and assembly can call each other. The TI and GCC compilers both follow the MSP430 EABI.Un contrato común para que C y ensamblador se llamen entre sí. Los compiladores de TI y GCC siguen el EABI del MSP430.

R12 arg 1arg 1 + return+ retorno
R13 arg 2arg 2
R14 arg 3arg 3
R15 arg 4arg 4
arg 5, 6, …arg 5, 6, … pushed on the stackse apilan en la pila

Args fill R12→R15 in order. The result comes back in R12: same register, dual role. Los argumentos llenan R12→R15 en orden. El resultado vuelve en R12: el mismo registro, doble función.

; C: result = add(x, y); mov.w x, R12 ; arg 1 -> R12 mov.w y, R13 ; arg 2 -> R13 call #add ; run the subroutine mov.w R12, result ; result <- R12

Who saves which registerQuién guarda cada registro

The convention splits the working registers in two, so neither side saves more than it must.La convención divide los registros de trabajo en dos, para que ningún lado guarde más de lo necesario.

R0
R1
R2
R3
R4
R5
R6
R7
R8
R9
R10
R11
R12
R13
R14
R15
specialespeciales
callee-saved · the subroutine restoressalva la subrutina · ella los restaura
caller-savedsalva el llamador
Caller protects R12–R15El llamador protege R12–R15
push.w R14 ; before the call call #sub pop.w R14 ; after, R14 back
Callee protects R4–R11La subrutina protege R4–R11
sub: push.w R6 ; save on entry ; ... use R6 ... pop.w R6 ; restore ret

What the compiler emitsLo que emite el compilador

A tiny C function and the assembly a compiler produces from it. Read it line by line, it is instructions you know.Una función pequeña en C y el ensamblador que un compilador genera de ella. Léela línea a línea, son instrucciones que conoces.

C functionFunción en C
int max(int a, int b) { if (a > b) return a; return b; }
AssemblyEnsamblador
max: cmp.w R13, R12 ; a - b jge done ; a >= b: keep R12 mov.w R13, R12 ; else b done: ret ; result in R12

Arguments a and b were already in R12 and R13. The compiler only needed a compare, a jump, and a return.Los argumentos a y b ya estaban en R12 y R13. El compilador solo necesitó una comparación, un salto y un retorno.

Control flow is compare plus jumpEl flujo de control es comparar y saltar

Every C control structure becomes the same two-instruction idea: set the flags, then a conditional jump.Toda estructura de control de C se vuelve la misma idea de dos instrucciones: fija los flags y luego salta condicionalmente.

while
wloop: cmp.b R12, R13 jeq wend ; exit when equal ; ... body ... jmp wloop wend:
for (i = 0; i < n; i++)
clr.b R12 ; i = 0 floop: cmp.b #n, R12 jhs fend ; exit when i >= n ; ... body ... inc.b R12 jmp floop fend:

if-else, do-while, every loop: the same shape. Only the condition and the jump change.if-else, do-while, cualquier bucle: la misma forma. Solo cambian la condición y el salto.

Count down, not upCuenta hacia abajo, no hacia arriba

Counting toward zero drops the compare entirely. DEC already sets the Zero flag.Contar hacia cero elimina la comparación por completo. DEC ya fija el flag Zero.

Count upContar hacia arriba CMP each passCMP en cada vuelta
clr.b R12 up: cmp.b #4, R12 ; extra compare jhs done ; ... body ... inc.b R12 jmp up
Count downContar hacia abajo no CMPsin CMP
mov.b #4, R12 dn: ; ... body ... dec.b R12 ; sets Z jnz dn ; loop if not 0

DEC updates the flags as a side effect, so JNZ reads them directly.DEC actualiza los flags como efecto secundario, así que JNZ los lee directamente.

Mixing C and assemblyMezclar C y ensamblador

Write most code in C. Drop to assembly only where it pays off, and let the convention join the two.Escribe la mayoría en C. Baja a ensamblador solo donde compensa, y deja que la convención una ambos.

~80% C: loops, decisions, setupC: bucles, decisiones, configuración
~20% ASM: hot spotASM: punto crítico

Assembly only where the compiler cannot match hand work: a tight loop, an ISR, exact timing.Ensamblador solo donde el compilador no iguala el trabajo manual: un bucle apretado, una ISR, temporización exacta.

C sideLado C
extern int max(int,int); int t = max(a, b);
a→R12 · b→R13
R12→t
conventionconvención
Assembly sideLado ensamblador
max: cmp.w R13,R12 jge .done mov.w R13,R12 .done: ret

A pointer is indirect addressingUn puntero es direccionamiento indirecto

Dereferencing a C pointer and the indirect register mode are the same mechanism: a register holds the address.Desreferenciar un puntero de C y el modo registro indirecto son el mismo mecanismo: un registro guarda la dirección.

C with a pointerC con un puntero
int *p = &value; // an address int x = *p; // read via p *p = 0; // write via p
Assembly with @RnEnsamblador con @Rn
mov.w #value, R5 ; an address mov.w @R5, R6 ; read via R5 clr.w @R5 ; write via R5
p++ → @R5+

Walking an array in C is autoincrement mode: R5 advances by the element size.Recorrer un array en C es el modo autoincremento: R5 avanza el tamaño del elemento.

arr[i] → X(Rn)

An indexed access in C is indexed addressing: base register plus a constant offset.Un acceso indexado en C es direccionamiento indexado: registro base más un desplazamiento constante.

Arrays and tables in linear memoryArrays y tablas en memoria lineal

A 2-D table is stored row by row. The element address is a small offset calculation.Una tabla 2-D se guarda fila por fila. La dirección del elemento es un cálculo de desplazamiento pequeño.

offset = (i × M + j) × element_sizedesplazamiento = (i × M + j) × tamaño_elemento
; table[1][2], M = 4 cols, int = 2 B mov.w #1, R12 ; i mov.w #2, R13 ; j rla.w R12 ; i * 2 rla.w R12 ; i * 4 (= i * M) add.w R13, R12 ; i*M + j rla.w R12 ; * 2 bytes -> 12 mov.w table(R12), R14 ; load element
byte offset of each celldesplazamiento en bytes de cada celda
+0
+2
+4
+6
+8
+10
+12
+14
+16
+18
+20
+22

Row 1, column 2 lands at byte +12: exactly what the arithmetic gives.Fila 1, columna 2 cae en el byte +12: justo lo que da la aritmética.

Three ideas to take with youTres ideas para llevarte

C and assembly share one machine and one contract.C y ensamblador comparten una máquina y un contrato.

C → ASM

Same instruction setEl mismo juego de instrucciones

The compiler emits MOV, ADD, CMP, jumps. Nothing you have not seen.El compilador emite MOV, ADD, CMP, saltos. Nada que no hayas visto.

R12–R15

Arguments and returnArgumentos y retorno

The calling convention lets C and assembly call each other safely.La convención de llamada permite que C y ensamblador se llamen con seguridad.

@Rn

Pointers are addressesLos punteros son direcciones

A C pointer is a register holding an address: indirect addressing.Un puntero de C es un registro con una dirección: direccionamiento indirecto.