diff --git a/README.md b/README.md index 41cf492d..09a59632 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This an example RISC-V SoC targeting the Arty-A7 FPGA board. It comprises the following features: * RISC-V debug support (using the [PULP RISC-V Debug Module](https://github.com/pulp-platform/riscv-dbg)) -* A UART (transmit only for now) +* A UART * GPIO (output only for now) * Timer @@ -15,7 +15,7 @@ probe is required. ## Software Requirements * Xilinx Vivado - https://www.xilinx.com/support/download.html -* rv32imc GCC toolchain - lowRISC provide one: +* rv32imc GCC toolchain - lowRISC provide one: https://github.com/lowRISC/lowrisc-toolchains/releases * cmake * python3 - Additional python dependencies in python-requirements.txt installed diff --git a/data/pins_artya7.xdc b/data/pins_artya7.xdc index 18a49035..b01a977f 100644 --- a/data/pins_artya7.xdc +++ b/data/pins_artya7.xdc @@ -88,7 +88,7 @@ set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { LED[3] ## USB-UART Interface set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { UART_TX }]; #IO_L19N_T3_VREF_16 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L14N_T2_SRCC_16 Sch=uart_txd_in +set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { UART_RX }]; #IO_L14N_T2_SRCC_16 Sch=uart_txd_in ## ChipKit Outer Digital Header #set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io0 }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0] diff --git a/python-requirements.txt b/python-requirements.txt index bdc8b27a..f33fa6e1 100644 --- a/python-requirements.txt +++ b/python-requirements.txt @@ -7,10 +7,10 @@ anytree mako pyyaml wheel +pyserial # Development version of edalize until all our changes are upstream git+https://github.com/lowRISC/edalize.git@ot # Development version with OT-specific changes git+https://github.com/lowRISC/fusesoc.git@ot - diff --git a/rtl/fpga/top_artya7.sv b/rtl/fpga/top_artya7.sv index 8cd9931f..4b14515b 100644 --- a/rtl/fpga/top_artya7.sv +++ b/rtl/fpga/top_artya7.sv @@ -7,6 +7,7 @@ module top_artya7 ( input IO_RST_N, output [3:0] LED, output [11:0] RGB_LED, + input UART_RX, output UART_TX ); parameter SRAMInitFile = ""; @@ -22,6 +23,7 @@ module top_artya7 ( .rst_sys_ni(rst_sys_n), .gp_o({LED, RGB_LED}), + .uart_rx_i(UART_RX), .uart_tx_o(UART_TX) ); diff --git a/rtl/system/ibex_demo_system.sv b/rtl/system/ibex_demo_system.sv index 9d9b8452..8e4a5638 100644 --- a/rtl/system/ibex_demo_system.sv +++ b/rtl/system/ibex_demo_system.sv @@ -10,6 +10,7 @@ module ibex_demo_system #( input logic rst_sys_ni, output logic [GpoWidth-1:0] gp_o, + input logic uart_rx_i, output logic uart_tx_o ); parameter logic [31:0] MEM_SIZE = 64 * 1024; // 64 kB @@ -97,6 +98,8 @@ module ibex_demo_system #( logic dbg_slave_rvalid; logic [31:0] dbg_slave_rdata; + logic uart_irq; + logic rst_core_n; logic ndmreset_req; logic dm_debug_req; @@ -218,7 +221,7 @@ module ibex_demo_system #( .irq_software_i (1'b0), .irq_timer_i (timer_irq), .irq_external_i (1'b0), - .irq_fast_i (15'b0), + .irq_fast_i ({14'b0, uart_irq}), .irq_nm_i (1'b0), .debug_req_i (dm_debug_req), @@ -286,6 +289,8 @@ module ibex_demo_system #( .device_rvalid_o(device_rvalid[Uart]), .device_rdata_o (device_rdata[Uart]), + .uart_rx_i, + .uart_irq_o (uart_irq), .uart_tx_o ); diff --git a/rtl/system/uart.sv b/rtl/system/uart.sv index e0faea63..887bdeca 100644 --- a/rtl/system/uart.sv +++ b/rtl/system/uart.sv @@ -4,7 +4,9 @@ module uart #( parameter int unsigned ClockFrequency = 50_000_000, - parameter int unsigned BaudRate = 115_200 + parameter int unsigned BaudRate = 115_200, + parameter int unsigned RxFifoDepth = 128, + parameter int unsigned TxFifoDepth = 128 ) ( input logic clk_i, input logic rst_ni, @@ -17,52 +19,219 @@ module uart #( output logic device_rvalid_o, output logic [31:0] device_rdata_o, + input logic uart_rx_i, + output logic uart_irq_o, output logic uart_tx_o ); localparam int unsigned ClocksPerBaud = ClockFrequency / BaudRate; + localparam int unsigned UART_RX_REG = 32'h0; + localparam int unsigned UART_TX_REG = 32'h4; + localparam int unsigned UART_STATUS_REG = 32'h8; - logic [$clog2(ClocksPerBaud)-1:0] baud_counter_q, baud_counter_d; - logic baud_tick; - - localparam int unsigned UART_TX_REG = 32'h0; - localparam int unsigned UART_STATUS_REG = 32'h4; + logic [11:0] reg_addr; typedef enum logic[1:0] { IDLE, START, - SEND, + PROC, STOP } uart_state_t; - uart_state_t state_q, state_d; - logic [2:0] bit_counter_q, bit_counter_d; - logic [7:0] current_byte_q, current_byte_d; - logic next_tx_byte; - logic read_status_q, read_status_d; - logic req; + logic [31:0] device_rdata_d, device_rdata_q; + logic device_rvalid_d, device_rvalid_q; - logic [11:0] reg_addr; + logic [$clog2(RxFifoDepth+1)-1:0] rx_fifo_depth; + logic [$clog2(ClocksPerBaud)-1:0] rx_baud_counter_q, rx_baud_counter_d; + logic rx_baud_tick; + + uart_state_t rx_state_q, rx_state_d; + logic [2:0] rx_bit_counter_q, rx_bit_counter_d; + logic [7:0] rx_current_byte_q, rx_current_byte_d; + logic [2:0] rx_q; + logic rx_start, rx_valid; + + logic rx_fifo_wvalid; + logic rx_fifo_rready; + logic [7:0] rx_fifo_rdata; + logic rx_fifo_empty; - logic tx_fifo_wvalid; - logic tx_fifo_rvalid, tx_fifo_rready; - logic [7:0] tx_fifo_rdata; - logic tx_fifo_full; + logic [$clog2(ClocksPerBaud)-1:0] tx_baud_counter_q, tx_baud_counter_d; + logic tx_baud_tick; + + logic write_req; + + uart_state_t tx_state_q, tx_state_d; + logic [2:0] tx_bit_counter_q, tx_bit_counter_d; + logic [7:0] tx_current_byte_q, tx_current_byte_d; + logic tx_next_byte; + + logic tx_fifo_wvalid; + logic tx_fifo_rvalid, tx_fifo_rready; + logic [7:0] tx_fifo_rdata; + logic tx_fifo_full; assign reg_addr = device_addr_i[11:0]; - assign tx_fifo_wvalid = (device_req_i & (reg_addr == UART_TX_REG) & device_be_i[0] & device_we_i); - assign tx_fifo_rready = baud_tick & next_tx_byte; + always_comb begin + device_rdata_d = '0; + device_rvalid_d = 1'b0; + rx_fifo_rready = 1'b0; + + if (device_req_i) begin + device_rvalid_d = 1'b1; + + if (device_be_i[0] & ~device_we_i) begin + case (reg_addr) + UART_RX_REG: begin + device_rdata_d = {24'b0, rx_fifo_rdata}; + rx_fifo_rready = 1'b1; + end + UART_TX_REG: begin + device_rdata_d = '0; + end + UART_STATUS_REG: begin + device_rdata_d = {30'b0, tx_fifo_full, rx_fifo_empty}; + end + default: begin + device_rdata_d = '0; + end + endcase + end + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + device_rdata_q <= '0; + device_rvalid_q <= 1'b0; + end else begin + device_rdata_q <= device_rdata_d; + device_rvalid_q <= device_rvalid_d; + end + end + + assign device_rdata_o = device_rdata_q; + assign device_rvalid_o = device_rvalid_q; + + assign rx_fifo_wvalid = rx_baud_tick & rx_valid; + assign rx_fifo_empty = (rx_fifo_depth == '0); + + // Set the rx_baud_counter half-way on rx_start to ensure sampling the bits 'in the middle' + assign rx_baud_counter_d = rx_baud_tick ? '0 : + rx_start ? $bits(rx_baud_counter_q)'(ClocksPerBaud >> 1) : + rx_baud_counter_q + 1'b1; + + assign rx_baud_tick = rx_baud_counter_q == $bits(rx_baud_counter_q)'(ClocksPerBaud - 1); + + prim_fifo_sync #( + .Width(8), + .Pass(1'b0), + .Depth(RxFifoDepth) + ) u_rx_fifo ( + .clk_i, + .rst_ni, + .clr_i(1'b0), + + .wvalid_i(rx_fifo_wvalid), + .wready_o(), + .wdata_i(rx_current_byte_q), + + .rvalid_o(), + .rready_i(rx_fifo_rready), + .rdata_o(rx_fifo_rdata), + + .full_o(), + .depth_o(rx_fifo_depth) + ); + + assign uart_irq_o = !rx_fifo_empty; + + // Synchronize RX and derive rx_start signal + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rx_q <= '0; + end else begin + rx_q <= {rx_q[1:0], uart_rx_i}; + end + end + + assign rx_start = !rx_q[1] & rx_q[2] & (rx_state_q == IDLE); + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rx_baud_counter_q <= '0; + end else begin + rx_baud_counter_q <= rx_baud_counter_d; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rx_state_q <= IDLE; + rx_bit_counter_q <= '0; + rx_current_byte_q <= '0; + // Transition the rx state on both rx_start and an rx_baud_tick + end else if (rx_start || rx_baud_tick) begin + rx_state_q <= rx_state_d; + rx_bit_counter_q <= rx_bit_counter_d; + rx_current_byte_q <= rx_current_byte_d; + end + end + + always_comb begin + rx_valid = 0; + rx_bit_counter_d = rx_bit_counter_q; + rx_current_byte_d = rx_current_byte_q; + rx_state_d = rx_state_q; + + case (rx_state_q) + IDLE: begin + + if (rx_start) begin + rx_state_d = START; + end + end + START: begin + rx_current_byte_d = '0; + rx_bit_counter_d = '0; + + if (!rx_q[2]) begin + rx_state_d = PROC; + end else begin + rx_state_d = IDLE; + end + end + PROC: begin + rx_current_byte_d = {rx_q[2], rx_current_byte_q[7:1]}; + + if (rx_bit_counter_q == 3'd7) begin + rx_state_d = STOP; + end else begin + rx_bit_counter_d = rx_bit_counter_q + 3'd1; + end + end + STOP: begin + if (rx_q[2]) begin + rx_valid = 1; + end + rx_state_d = IDLE; + end + endcase + end + + assign write_req = (device_req_i & device_be_i[0] & device_we_i); - assign read_status_d = (device_req_i & (reg_addr == UART_STATUS_REG) & device_be_i[0] & ~device_we_i); + assign tx_fifo_wvalid = (reg_addr == UART_TX_REG) & write_req; + assign tx_fifo_rready = tx_baud_tick & tx_next_byte; - assign device_rdata_o = read_status_q ? {31'b0, tx_fifo_full} : 32'b0; - assign device_rvalid_o = req; + assign tx_baud_counter_d = tx_baud_tick ? '0 : tx_baud_counter_q + 1'b1; + assign tx_baud_tick = tx_baud_counter_q == $bits(tx_baud_counter_q)'(ClocksPerBaud - 1); prim_fifo_sync #( .Width(8), .Pass(1'b0), - .Depth(128) + .Depth(TxFifoDepth) ) u_tx_fifo ( .clk_i, .rst_ni, @@ -80,73 +249,68 @@ module uart #( .depth_o() ); - assign baud_counter_d = baud_tick ? '0 : baud_counter_q + 1'b1; - assign baud_tick = baud_counter_q == (ClocksPerBaud - 1); - always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin - read_status_q <= 0; - req <= 0; - baud_counter_q <= '0; + tx_baud_counter_q <= '0; end else begin - read_status_q <= read_status_d; - req <= device_req_i; - baud_counter_q <= baud_counter_d; + tx_baud_counter_q <= tx_baud_counter_d; end end always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin - state_q <= IDLE; - bit_counter_q <= '0; - current_byte_q <= '0; - end else if (baud_tick) begin - state_q <= state_d; - bit_counter_q <= bit_counter_d; - current_byte_q <= current_byte_d; + tx_state_q <= IDLE; + tx_bit_counter_q <= '0; + tx_current_byte_q <= '0; + end else if (tx_baud_tick) begin + tx_state_q <= tx_state_d; + tx_bit_counter_q <= tx_bit_counter_d; + tx_current_byte_q <= tx_current_byte_d; end end + always_comb begin - uart_tx_o = 1'b0; - bit_counter_d = bit_counter_q; - current_byte_d = current_byte_q; - next_tx_byte = 1'b0; - state_d = state_q; + uart_tx_o = 1'b0; + tx_bit_counter_d = tx_bit_counter_q; + tx_current_byte_d = tx_current_byte_q; + tx_next_byte = 1'b0; + tx_state_d = tx_state_q; - case (state_q) + case (tx_state_q) IDLE: begin uart_tx_o = 1'b1; if (tx_fifo_rvalid) begin - state_d = START; + tx_state_d = START; end end START: begin - uart_tx_o = 1'b0; - state_d = SEND; - bit_counter_d = 3'd0; - current_byte_d = tx_fifo_rdata; - next_tx_byte = 1'b1; + uart_tx_o = 1'b0; + tx_state_d = PROC; + tx_bit_counter_d = 3'd0; + tx_current_byte_d = tx_fifo_rdata; + tx_next_byte = 1'b1; end - SEND: begin - uart_tx_o = current_byte_q[0]; + PROC: begin + uart_tx_o = tx_current_byte_q[0]; - current_byte_d = {1'b0, current_byte_q[7:1]}; - if (bit_counter_q == 3'd7) begin - state_d = STOP; + tx_current_byte_d = {1'b0, tx_current_byte_q[7:1]}; + if (tx_bit_counter_q == 3'd7) begin + tx_state_d = STOP; end else begin - bit_counter_d = bit_counter_q + 3'd1; + tx_bit_counter_d = tx_bit_counter_q + 3'd1; end end STOP: begin uart_tx_o = 1'b1; if (tx_fifo_rvalid) begin - state_d = START; + tx_state_d = START; end else begin - state_d = IDLE; + tx_state_d = IDLE; end end endcase end + endmodule diff --git a/sw/common/demo_system.c b/sw/common/demo_system.c index 906067f1..20bb293f 100644 --- a/sw/common/demo_system.c +++ b/sw/common/demo_system.c @@ -15,6 +15,10 @@ int putchar(int c) { return c; } +int getchar(void) { + return uart_in(DEFAULT_UART); +} + int puts(const char *str) { while (*str) { putchar(*str++); @@ -81,6 +85,22 @@ int install_exception_handler(uint32_t vector_num, void(*handler_fn)(void)) { return 0; } +void enable_interrupts(uint32_t enable_mask) { + asm volatile("csrs mie, %0\n" : : "r"(enable_mask)); +} + +void disable_interrupts(uint32_t disable_mask) { + asm volatile("csrc mie, %0\n" : : "r"(disable_mask)); +} + +void set_global_interrupt_enable(uint32_t enable) { + if (enable) { + asm volatile("csrs mstatus, %0\n" : : "r"(1<<3)); + } else { + asm volatile("csrc mstatus, %0\n" : : "r"(1<<3)); + } +} + void simple_exc_handler(void) { puts("EXCEPTION!!!\n"); puts("============\n"); diff --git a/sw/common/demo_system.h b/sw/common/demo_system.h index 62c566ca..ab554192 100644 --- a/sw/common/demo_system.h +++ b/sw/common/demo_system.h @@ -11,12 +11,14 @@ #include "gpio.h" #define UART0_BASE 0x80001000 +#define UART_IRQ (1 << 16) #define DEFAULT_UART UART_FROM_BASE_ADDR(UART0_BASE) #define GPIO0_BASE 0x80000000 #define GPIO0 GPIO_FROM_BASE_ADDR(GPIO0_BASE) #define TIMER_BASE 0x80002000 +#define TIMER_IRQ (1 << 7) /** * Writes character to default UART. Signature matches c stdlib function @@ -27,6 +29,14 @@ */ int putchar(int c); +/** + * Reads character from default UART. Signature matches c stdlib function + * of the same name. + * + * @returns Character from the uart rx fifo + */ +int getchar(void); + /** * Writes string to default UART. Signature matches c stdlib function of * the same name. @@ -43,10 +53,50 @@ int puts(const char *str); */ void puthex(uint32_t h); +/** + * Install an exception handler by writing a `j` instruction to the handler in + * at the appropriate address given the `vector_num`. + * + * @param vector_num Which IRQ the handler is for, must be less than 32. All + * non-interrupt exceptions are handled at vector 0. + * + * @param handle_fn Function pointer to the handler function. The function is + * responsible for interrupt prolog and epilog, such as saving and restoring + * register to the stack and executing `mret` at the end. + * + * @return 0 on success, 1 if `vector_num` out of range, 2 if the address of + * `handler_fn` is too far from the exception handler base to use with a `j` + * instruction. + */ int install_exception_handler(uint32_t vector_num, void(*handler_fn)(void)); +/** + * Set per-interrupt enables (`mie` CSR) + * + * @param enable_mask Any set bit is set in `mie`, enabling the interrupt. Bits + * not set in `enable_mask` aren't changed. + */ +void enable_interrupts(uint32_t enable_mask); + +/** + * Clear per-interrupt enables (`mie` CSR) + * + * @param enable_mask Any set bit is cleared in `mie`, disabling the interrupt. + * Bits not set in `enable_mask` aren't changed. + */ +void disable_interrupts(uint32_t disable_mask); + +/** + * Set the global interrupt enable (the `mie` field of `mstatus`). This enables + * or disable all interrupts at once. + * + * @param enable Enable interrupts if set, otherwise disabled + */ +void set_global_interrupt_enable(uint32_t enable); + unsigned int get_mepc(); unsigned int get_mcause(); unsigned int get_mtval(); + #endif diff --git a/sw/common/timer.c b/sw/common/timer.c index ad288ade..f69c7b8c 100644 --- a/sw/common/timer.c +++ b/sw/common/timer.c @@ -51,10 +51,8 @@ void timer_enable(uint64_t time_base) { time_increment = time_base; // Set timer values increment_timecmp(time_base); - // enable timer interrupt - asm volatile("csrs mie, %0\n" : : "r"(0x80)); - // enable global interrupt - asm volatile("csrs mstatus, %0\n" : : "r"(0x8)); + enable_interrupts(TIMER_IRQ); + set_global_interrupt_enable(1); } void timer_disable(void) { asm volatile("csrc mie, %0\n" : : "r"(0x80)); } diff --git a/sw/common/uart.c b/sw/common/uart.c index a44c17bc..19edf7ef 100644 --- a/sw/common/uart.c +++ b/sw/common/uart.c @@ -4,9 +4,25 @@ #include "uart.h" #include "dev_access.h" +#include "demo_system.h" -void uart_out(void* uart_ptr, char c) { - while(DEV_READ(uart_ptr + UART_STATUS_REG) & UART_STATUS_TX_FULL); +void uart_enable_rx_int(void) { + enable_interrupts(UART_IRQ); + set_global_interrupt_enable(1); +} + +int uart_in(uart_t uart) { + int res = UART_EOF; + + if (!(DEV_READ(uart + UART_STATUS_REG) & UART_STATUS_RX_EMPTY)) { + res = DEV_READ(uart + UART_RX_REG); + } + + return res; +} + +void uart_out(uart_t uart, char c) { + while(DEV_READ(uart + UART_STATUS_REG) & UART_STATUS_TX_FULL); - DEV_WRITE(uart_ptr + UART_TX_REG, c); + DEV_WRITE(uart + UART_TX_REG, c); } diff --git a/sw/common/uart.h b/sw/common/uart.h index 6211da3f..319433f4 100644 --- a/sw/common/uart.h +++ b/sw/common/uart.h @@ -5,15 +5,21 @@ #ifndef UART_H__ #define UART_H__ -#define UART_TX_REG 0 -#define UART_STATUS_REG 4 +#define UART_RX_REG 0 +#define UART_TX_REG 4 +#define UART_STATUS_REG 8 -#define UART_STATUS_TX_FULL 1 +#define UART_STATUS_RX_EMPTY 1 +#define UART_STATUS_TX_FULL 2 + +#define UART_EOF -1 typedef void* uart_t; #define UART_FROM_BASE_ADDR(addr)((uart_t)(addr)) +void uart_enable_rx_int(void); +int uart_in(uart_t uart); void uart_out(uart_t uart, char c); #endif // UART_H__ diff --git a/sw/demo/main.c b/sw/demo/main.c index 8eda891e..375af15a 100644 --- a/sw/demo/main.c +++ b/sw/demo/main.c @@ -2,7 +2,22 @@ #include "timer.h" #include "gpio.h" +void test_uart_irq_handler(void) __attribute__((interrupt)); + +void test_uart_irq_handler(void) { + int uart_in_char; + + while ((uart_in_char = uart_in(DEFAULT_UART)) != -1) { + uart_out(DEFAULT_UART, uart_in_char); + uart_out(DEFAULT_UART, '\r'); + uart_out(DEFAULT_UART, '\n'); + } +} + int main(void) { + uart_enable_rx_int(); + install_exception_handler(UART_IRQ, &test_uart_irq_handler); + timer_init(); timer_enable(50000000); @@ -17,9 +32,16 @@ int main(void) { if (cur_time != last_elapsed_time) { last_elapsed_time = cur_time; + // Disable interrupts whilst outputting to prevent output for RX IRQ + // happening in the middle + set_global_interrupt_enable(0); + puts("Hello World! "); puthex(last_elapsed_time); putchar('\n'); + + // Re-enable interrupts with output complete + set_global_interrupt_enable(1); set_output_bit(GPIO0, cur_output_bit_index, cur_output_bit); cur_output_bit_index++; diff --git a/util/arty-a7-openocd-cfg.tcl b/util/arty-a7-openocd-cfg.tcl index cb8d03c6..7fba26b0 100644 --- a/util/arty-a7-openocd-cfg.tcl +++ b/util/arty-a7-openocd-cfg.tcl @@ -2,7 +2,7 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -interface ftdi +adapter driver ftdi transport select jtag ftdi_device_desc "Digilent USB Device" @@ -14,7 +14,13 @@ reset_config none # Configure JTAG chain and the target processor set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 6 -expected-id 0x0362D093 -ignore-version +# Configure JTAG expected ID +# arty-a7-35t +set _EXPECTED_ID 0x0362D093 +# arty-a7-100t +# set _EXPECTED_ID 0x13631093 + +jtag newtap $_CHIPNAME cpu -irlen 6 -expected-id $_EXPECTED_ID -ignore-version set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME @@ -22,7 +28,7 @@ riscv set_ir idcode 0x09 riscv set_ir dtmcs 0x22 riscv set_ir dmi 0x23 -adapter_khz 10000 +adapter speed 10000 riscv set_prefer_sba on gdb_report_data_abort enable