/* * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #include "pico/stdio/driver.h" #include "pico/stdio_semihosting.h" #include "pico/binary_info.h" static void stdio_semihosting_out_chars(const char *buf, int length) { // must be volatile or the buffer gets put in registers & optimized away volatile struct { // https://developer.arm.com/documentation/dui0375/g/What-is-Semihosting-/SYS-WRITE--0x05- // arguments, in order: // word 0 = file handle (1 = stdout) // word 1 = pointer to buffer // word 2 = length of buffer size_t fd; const char *buf; size_t len; } args; args.fd = 1; // 1 = stdout args.buf = buf; args.len = length; pico_default_asm ( #ifdef __riscv // a0 encodes the semihosting call number, 0x05 = SYS_WRITE "li a0, 0x05\n" // a1 points to the arguments "mv a1, %[args]\n" // Magic three-instruction sequence, containing a breakpoint. Note the // RISC-V unpriv spec implies the final instruction might encode the // call number (passed in a1) but openocd source shows this is just a // constant value of 0x07. These instructions must be uncompressed: ".option push\n" ".option norvc\n" "slli x0, x0, 0x1f\n" "ebreak\n" "srai x0, x0, 0x07\n" ".option pop\n" : : [args] "r" (&args) : "a0", "a1" #else // r1 must contain a pointer to the arguments "movs r1, %[args]\n" // semihosting call number 0x05 = SYS_WRITE "movs r0, #5\n" // make the semihosting call: https://developer.arm.com/documentation/dui0375/g/What-is-Semihosting-/The-semihosting-interface "bkpt 0xab\n" : : [args] "r" (&args) : "r0", "r1", "cc", "memory" #endif ); } stdio_driver_t stdio_semihosting = { .out_chars = stdio_semihosting_out_chars, #if PICO_STDIO_ENABLE_CRLF_SUPPORT .crlf_enabled = PICO_STDIO_SEMIHOSTING_DEFAULT_CRLF #endif }; void stdio_semihosting_init(void) { #if !PICO_NO_BI_STDIO_SEMIHOSTING bi_decl_if_func_used(bi_program_feature("semihosting stdout")); #endif stdio_set_driver_enabled(&stdio_semihosting, true); } void stdio_semihosting_deinit(void) { stdio_set_driver_enabled(&stdio_semihosting, false); }