Gracias por los punteros, markt y chris-stratton. La opción de semihosting resultó ser bastante sencilla. Logré encontrar la fuente para un par de rutinas de registro simples que pueden enviar mensajes a la consola OpenOCD. Los publicaré aquí ya que (i) requirieron algunas modificaciones para funcionar y (ii) Creo que esta información no es muy fácil de encontrar para las personas que recién están comenzando.
Primero, el código D aquí se adapta fácilmente para proporcionar la siguiente función C:
void send_command(int command, void *message)
{
asm("mov r0, %[cmd];"
"mov r1, %[msg];"
"bkpt #0xAB"
:
: [cmd] "r" (command), [msg] "r" (message)
: "r0", "r1", "memory");
}
Ejemplo de llamar a send_command para escribir una cadena en la consola de OpenOCD:
const char s[] = "Hello world\n";
uint32_t m[] = { 2/*stderr*/, (uint32_t)s, sizeof(s)/sizeof(char) - 1 };
send_command(0x05/* some interrupt ID */, m);
En segundo lugar, la función putChar proporcionada en los comentarios aquí funciona bien, excepto que tuve que agregar un '#' antes de 0x03:
void put_char(char c)
{
asm (
"mov r0, #0x03\n" /* SYS_WRITEC */
"mov r1, %[msg]\n"
"bkpt #0xAB\n"
:
: [msg] "r" (&c)
: "r0", "r1"
);
}
Para ver la salida de estas funciones,
Primero inicio OpenOCD, luego conecto usando arm-none-eabi-gdb de la siguiente manera:
target remote localhost:3333
monitor arm semihosting enable
monitor reset halt
load code.elf
continue
Tenga en cuenta que los mensajes aparecen en la versión estándar del proceso de OpenOCD, no en la consola GDB.