Estoy tratando de escribir el código más pequeño posible para extraer el firmware del microcontrolador XMC4500 de Infineon .
El código debe caber en un búfer de 30 bytes que me permite tener 15 instrucciones de máquina usando el conjunto de instrucciones de 16 bits de Thumb.
Comenzando con C, mi intento es volcar la memoria flash a través de un solo pin GPIO (ver pregunta original) siguiendo este ingenioso truco.
Básicamente lo que estoy haciendo es:
EDITAR:
#include "XMC4500.h"
void main() {
// start dumping at memory address 0x00000000
unsigned int* p = (uint32_t *)(0x0u);
// configure port1 output (push-pull)
PORT1->IOCR0 = 0x8080u;
for(;;) {
int i = 32;
int data = *(p++);
do {
// clock low
PORT1->OUT = 0x0;
// clock high with data bits
PORT1->OUT = 0x2u | data;
data >>= 1;
} while (--i > 0);
}
}
main:
; PORT1->IOCR0 = 0x8080UL
ldr r1, =0x48028100 ; load port1 base address to R1
movw r2, #0x8080 ; move 0x8080 to R2
str r2, [r1, #0x10]
main_1:
; start copying at address 0x00000000
; R12 is known to be zeroed
ldr.w r2, [r12], #0x4 ; int data = *(p++)
movs r3, #32 ; int i = 32
main_2:
; PORT1->OUT = 0x0
; clock low
; R12 is known to be zeroed
str r12, [r1]
; PORT1->OUT = 0x2 | data
; clock high with data bits
orr r4, r2, #0x2
str r4, [r1]
asrs r2, r2, #0x1 ; data >>= 1
subs r3, r3, #0x1 ; i--
bne.n main_2 ; while (--i > 0)
b.n main_1 ; while(true)
Sin embargo, el tamaño del código sigue siendo demasiado grande para cumplir con mis requisitos.
¿Hay algo que pueda hacer para reducir aún más mi código? ¿Algo que se pueda optimizar o dejar de lado?
No estoy acostumbrado a programar para procesadores ARM y no sé qué compilador usas, así que tal vez los cambios propuestos no hagan nada en absoluto, pero bueno, ¡al menos intentémoslo!
1-Inline sus funciones:
Un buen compilador ya debería alinear una función si las optimizaciones están bien establecidas, pero vale la pena alinearlo para eliminar las llamadas y los ret.
2-Evitar la ramificación:
En algunas arquitecturas un IF se puede traducir en: cargar, probar, bifurcar, tres instrucciones, si puede hacerlo sin bifurcar puede usar menos instrucciones.
Entonces, el código propuesto es:
int main()
{
// start dumping at memory address 0x08000000
unsigned int *p;
int i;
p = (uint32_t *)(0x08000000u);
// configure pin 1.0 and pin 1.1 as output (push-pull)
PORT1->IOCR0 = 0x8080UL;
do
{
for (i = 0; i < 32; i++)
{
// set pin 1.1 to low (SPI clock)
PORT1->OUT &= (~0x2UL);
PORT1->OUT = (PORT1->OUT & 0xFFFE) | (data & 0x01)
PORT1->OUT |= 0x2UL;
data >>= 1;
}
}while(p++)
}
Pruébalo y comenta los resultados.
Esto supone que su programa de 32 bytes es el único código disponible en el chip. No se permiten llamadas externas.
Una preocupación con su código C sería la inclusión y el uso del encabezado "XMC4500.h". A pesar de que solo está utilizando la estructura "PORT1" para que el resto se optimice / se optimizará, sigo pensando que puede obtener un acceso de registro GPIO más eficiente que eso.
En segundo lugar, por su ausencia de información sobre la "configuración del proyecto", asumo que no ha tomado ninguna medida para obligar a su enlazador a comprimir su código en una ubicación específica, omitir la tabla de interrupciones, el código de inicialización, etc. Es posible que desee echar un vistazo aquí . Básicamente, lo que dice es que al modificar los archivos .ld/.lds puede obligar al enlazador a colocar secciones específicas de código en direcciones específicas.
Tal script podría verse así:
SECTIONS {
. = YOUR_DESIRED_ADDRESS;
.text : { * (.text); }
}
Editaré la respuesta a medida que surjan nuevas ideas.
and.w r4, r2, #0x1, add.w r4, r4, #0xFF00
EDITAR : Lo siento, mi error (y & agregar)
Dzarda
david tweed
scott seidman
Kaz
usuario3696425
Dzarda
usuario3696425