diff --git a/.github/workflows/sim-apps-job/test_apps.py b/.github/workflows/sim-apps-job/test_apps.py index d22b876bd..b7e178f8e 100755 --- a/.github/workflows/sim-apps-job/test_apps.py +++ b/.github/workflows/sim-apps-job/test_apps.py @@ -24,7 +24,7 @@ class BColors: # Define parameters for the test_apps.py script SIMULATOR = "verilator" -SIM_TIMEOUT_S = 600 +SIM_TIMEOUT_S = 600000 LINKER = "on_chip" COMPILER = "gcc" @@ -33,6 +33,40 @@ class BColors: "example_spi_read", "example_spidma_powergate", "example_spi_write", + "coremark", + "example_ams_peripheral", + "example_asm", + "example_cpp", + "example_data_processing_from_flash", + "example_dma", + "example_dma_2d", + "example_dma_external", + "example_dma_multichannel", + "example_dma_sdk", + "example_dma_subaddressing", + "example_ext_memory", + "example_fft", + "example_freertos_blinky", + "example_gpio_intr", + "example_gpio_toggle", + "example_i2s", + "example_iffifo", + "example_im2col", + "example_matadd", + "example_matadd_interleaved", + "example_matfadd", + "example_matmul", + "example_pdm2pcm", + "example_sdk_spi_flash", + "example_simple_accelerator", + "example_spi_read", + "example_spi_write", + "example_spidma_powergate", + "example_tensor_format_conv", + "example_timer_sdk", + "hello_world", + "memtest", + "minver" ] app_list = [app for app in os.listdir("sw/applications")] diff --git a/core-v-mini-mcu.core b/core-v-mini-mcu.core index aef1f20e2..e07824be3 100644 --- a/core-v-mini-mcu.core +++ b/core-v-mini-mcu.core @@ -339,6 +339,7 @@ targets: vsim_options: - -sv_lib ../../../hw/vendor/lowrisc_opentitan/hw/dv/dpi/uartdpi/uartdpi - -sv_lib ../../../hw/vendor/pulp_platform_pulpissimo/rtl/tb/remote_bitbang/librbs + - -voptargs=+acc=npr vcs: vcs_options: - -override_timescale=1ns/1ps diff --git a/hw/ip/dma/data/dma.hjson b/hw/ip/dma/data/dma.hjson index 4f144c612..cad7588e8 100644 --- a/hw/ip/dma/data/dma.hjson +++ b/hw/ip/dma/data/dma.hjson @@ -186,12 +186,13 @@ hwaccess: "hro", resval: 0, fields: [ - { bits: "1:0", name: "MODE", + { bits: "2:0", name: "MODE", desc: "DMA operation mode", enum: [ { value: "0", name: "LINEAR_MODE", desc: "Transfers data linearly"}, { value: "1", name: "CIRCULAR_MODE", desc: "Transfers data in circular mode"}, { value: "2", name: "ADDRESS_MODE" , desc: "Transfers data using as destination address the data from ADD_PTR"}, + { value: "3", name: "SUBADDRESS_MODE" , desc: "Implements transferrin of data when SRC_PTR is fixed and related to a peripheral"}, ] } ] diff --git a/hw/ip/dma/rtl/dma.sv b/hw/ip/dma/rtl/dma.sv index 923b5a1fa..ebf2b9e79 100644 --- a/hw/ip/dma/rtl/dma.sv +++ b/hw/ip/dma/rtl/dma.sv @@ -105,15 +105,17 @@ module dma #( logic dma_window_intr_n; /* FIFO signals */ - logic [Addr_Fifo_Depth-1:0] read_fifo_usage; + logic [3:0][Addr_Fifo_Depth-1:0] read_fifo_usage; logic [Addr_Fifo_Depth-1:0] read_addr_fifo_usage; logic [Addr_Fifo_Depth-1:0] write_fifo_usage; logic fifo_flush; - logic read_fifo_full; - logic read_fifo_empty; + logic [3:0] read_fifo_full; + logic [3:0] read_fifo_empty; logic read_fifo_alm_full; - logic read_fifo_pop; + logic read_fifo_pop_pad; + logic [3:0] read_fifo_pop; + logic [3:0] read_fifo_pop_act; logic [31:0] read_fifo_input; logic [31:0] read_fifo_output; @@ -126,9 +128,11 @@ module dma #( logic write_fifo_empty; logic write_fifo_alm_full; logic write_fifo_push; + logic write_fifo_push_act; logic write_fifo_pop; logic [31:0] write_fifo_input; logic [31:0] write_fifo_output; + logic [31:0] write_fifo_input_act; /* Trigger signals */ logic wait_for_rx; @@ -151,8 +155,11 @@ module dma #( } dma_state_q, dma_state_d; + dma_data_type_t src_data_type; + logic circular_mode; logic address_mode; + logic subaddressing_mode; logic dma_start_pending; @@ -181,27 +188,88 @@ module dma #( assign clk_cg = clk_i & clk_gate_en_ni; `endif + fifo_v3 #( + .DEPTH(FIFO_DEPTH), + .FALL_THROUGH(1'b1), + .DATA_WIDTH(8) + ) dma_read_fifo_0_i ( + .clk_i(clk_cg), + .rst_ni, + .flush_i(fifo_flush), + .testmode_i(1'b0), + // status flags + .full_o(read_fifo_full[0]), + .empty_o(read_fifo_empty[0]), + .usage_o(read_fifo_usage[0]), + // as long as the queue is not full we can push new data + .data_i(read_fifo_input[7:0]), + .push_i(data_in_rvalid), + // as long as the queue is not empty we can pop new elements + .data_o(read_fifo_output[7:0]), + .pop_i(read_fifo_pop_act[0]) + ); + fifo_v3 #( + .DEPTH(FIFO_DEPTH), + .FALL_THROUGH(1'b1), + .DATA_WIDTH(8) + ) dma_read_fifo_1_i ( + .clk_i(clk_cg), + .rst_ni, + .flush_i(fifo_flush), + .testmode_i(1'b0), + // status flags + .full_o(read_fifo_full[1]), + .empty_o(read_fifo_empty[1]), + .usage_o(read_fifo_usage[1]), + // as long as the queue is not full we can push new data + .data_i(read_fifo_input[15:8]), + .push_i(data_in_rvalid), + // as long as the queue is not empty we can pop new elements + .data_o(read_fifo_output[15:8]), + .pop_i(read_fifo_pop_act[1]) + ); - /* Read FIFO */ fifo_v3 #( .DEPTH(FIFO_DEPTH), - .FALL_THROUGH(1'b1) - ) dma_read_fifo_i ( + .FALL_THROUGH(1'b1), + .DATA_WIDTH(8) + ) dma_read_fifo_2_i ( + .clk_i(clk_cg), + .rst_ni, + .flush_i(fifo_flush), + .testmode_i(1'b0), + // status flags + .full_o(read_fifo_full[2]), + .empty_o(read_fifo_empty[2]), + .usage_o(read_fifo_usage[2]), + // as long as the queue is not full we can push new data + .data_i(read_fifo_input[23:16]), + .push_i(data_in_rvalid), + // as long as the queue is not empty we can pop new elements + .data_o(read_fifo_output[23:16]), + .pop_i(read_fifo_pop_act[2]) + ); + + fifo_v3 #( + .DEPTH(FIFO_DEPTH), + .FALL_THROUGH(1'b1), + .DATA_WIDTH(8) + ) dma_read_fifo_3_i ( .clk_i(clk_cg), .rst_ni, .flush_i(fifo_flush), .testmode_i(1'b0), // status flags - .full_o(read_fifo_full), - .empty_o(read_fifo_empty), - .usage_o(read_fifo_usage), + .full_o(read_fifo_full[3]), + .empty_o(read_fifo_empty[3]), + .usage_o(read_fifo_usage[3]), // as long as the queue is not full we can push new data - .data_i(read_fifo_input), + .data_i(read_fifo_input[31:24]), .push_i(data_in_rvalid), // as long as the queue is not empty we can pop new elements - .data_o(read_fifo_output), - .pop_i(read_fifo_pop) + .data_o(read_fifo_output[31:24]), + .pop_i(read_fifo_pop_act[3]) ); /* Read address mode FIFO */ @@ -239,8 +307,8 @@ module dma #( .empty_o(write_fifo_empty), .usage_o(write_fifo_usage), // as long as the queue is not full we can push new data - .data_i(write_fifo_input), - .push_i(write_fifo_push), + .data_i(write_fifo_input_act), + .push_i(write_fifo_push_act), // as long as the queue is not empty we can pop new elements .data_o(write_fifo_output), .pop_i(write_fifo_pop) @@ -267,7 +335,7 @@ module dma #( .dma_start_i(dma_start), .dma_done_i(dma_done), .ext_dma_stop_i, - .read_fifo_full_i(read_fifo_full), + .read_fifo_full_i(|read_fifo_full), .read_fifo_alm_full_i(read_fifo_alm_full), .wait_for_rx_i(wait_for_rx), .data_in_gnt_i(data_in_gnt), @@ -305,13 +373,13 @@ module dma #( .reg2hw_i(reg2hw), .dma_padding_fsm_on_i(dma_padding_fsm_on), .dma_start_i(dma_start), - .read_fifo_empty_i(read_fifo_empty), + .read_fifo_empty_i(&(read_fifo_empty)), .write_fifo_full_i(write_fifo_full), .write_fifo_alm_full_i(write_fifo_alm_full), .data_read_i(read_fifo_output), .padding_fsm_done_o(padding_fsm_done), .write_fifo_push_o(write_fifo_push), - .read_fifo_pop_o(read_fifo_pop), + .read_fifo_pop_o(read_fifo_pop_pad), .data_write_o(write_fifo_input) ); @@ -495,6 +563,117 @@ module dma #( end end + // Subaddressing mode controlling logic + + always_ff @(posedge clk_cg, negedge rst_ni) begin + if (~rst_ni) begin + read_fifo_pop <= 4'b0000; + end else begin + if (subaddressing_mode == 1'b1) begin + case (src_data_type) + DMA_DATA_TYPE_HALF_WORD: begin + + if (dma_start == 1'b1) begin + read_fifo_pop <= 4'b0011; + end else if (read_fifo_pop_pad == 1'b1) begin + if (read_fifo_pop == 4'b1100) begin + read_fifo_pop <= 4'b0011; + end else begin + read_fifo_pop <= read_fifo_pop << 2; + end + end + end + + DMA_DATA_TYPE_BYTE: begin + + if (dma_start == 1'b1) begin + read_fifo_pop <= 4'b0001; + end else if (read_fifo_pop_pad == 1'b1) begin + if (read_fifo_pop == 4'b1000) begin + read_fifo_pop <= 4'b0001; + end else begin + read_fifo_pop <= read_fifo_pop << 1; + end + end + end + + default: read_fifo_pop <= {4{read_fifo_pop_pad}}; + + endcase + end else begin + read_fifo_pop <= {4{read_fifo_pop_pad}}; + end + end + end + + always_comb begin + if (subaddressing_mode == 1'b1) begin + if (read_fifo_pop_pad == 1'b1) begin + case (src_data_type) + DMA_DATA_TYPE_HALF_WORD: begin + + read_fifo_pop_act = read_fifo_pop; + + if (read_fifo_pop == 4'b0000) begin + write_fifo_input_act = '0; + write_fifo_push_act = 1'b0; + end else if (read_fifo_pop == 4'b1100) begin + write_fifo_input_act = {{16{1'b0}}, write_fifo_input[31:16]}; + write_fifo_push_act = 1'b1; + end else if (read_fifo_pop == 4'b0011) begin + write_fifo_input_act = {{16{1'b0}}, write_fifo_input[15:0]}; + write_fifo_push_act = 1'b1; + end else begin + write_fifo_input_act = write_fifo_input; + write_fifo_push_act = write_fifo_push; + end + + end + + DMA_DATA_TYPE_BYTE: begin + + read_fifo_pop_act = read_fifo_pop; + + if (read_fifo_pop == 4'b0000) begin + write_fifo_input_act = '0; + write_fifo_push_act = 1'b0; + end else if (read_fifo_pop == 4'b1000) begin + write_fifo_input_act = {{24{1'b0}}, write_fifo_input[31:24]}; + write_fifo_push_act = 1'b1; + end else if (read_fifo_pop == 4'b0100) begin + write_fifo_input_act = {{24{1'b0}}, write_fifo_input[23:16]}; + write_fifo_push_act = 1'b1; + end else if (read_fifo_pop == 4'b0010) begin + write_fifo_input_act = {{24{1'b0}}, write_fifo_input[15:8]}; + write_fifo_push_act = 1'b1; + end else if (read_fifo_pop == 4'b0001) begin + write_fifo_input_act = {{24{1'b0}}, write_fifo_input[7:0]}; + write_fifo_push_act = 1'b1; + end else begin + write_fifo_input_act = write_fifo_input; + write_fifo_push_act = write_fifo_push; + end + + end + + default: begin + write_fifo_input_act = write_fifo_input; + write_fifo_push_act = write_fifo_push; + read_fifo_pop_act = {4{read_fifo_pop_pad}}; + end + + endcase + end else begin + write_fifo_input_act = '0; + write_fifo_push_act = 1'b0; + read_fifo_pop_act = {4{read_fifo_pop_pad}}; + end + end else begin + write_fifo_input_act = write_fifo_input; + write_fifo_push_act = write_fifo_push; + read_fifo_pop_act = {4{read_fifo_pop_pad}}; + end + end /*_________________________________________________________________________________________________________________________________ */ @@ -550,11 +729,15 @@ module dma #( assign circular_mode = reg2hw.mode.q == 1; assign address_mode = reg2hw.mode.q == 2; + assign subaddressing_mode = reg2hw.mode.q == 4; assign wait_for_rx = |(reg2hw.slot.rx_trigger_slot.q[SLOT_NUM-1:0] & (~trigger_slot_i)); assign wait_for_tx = |(reg2hw.slot.tx_trigger_slot.q[SLOT_NUM-1:0] & (~trigger_slot_i)); - assign read_fifo_alm_full = (read_fifo_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); + assign read_fifo_alm_full = (read_fifo_usage[0] == LastFifoUsage[Addr_Fifo_Depth-1:0]) & + (read_fifo_usage[1] == LastFifoUsage[Addr_Fifo_Depth-1:0]) & + (read_fifo_usage[2] == LastFifoUsage[Addr_Fifo_Depth-1:0]) & + (read_fifo_usage[3] == LastFifoUsage[Addr_Fifo_Depth-1:0]); assign read_addr_fifo_alm_full = (read_addr_fifo_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); assign write_fifo_alm_full = (write_fifo_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); @@ -563,4 +746,7 @@ module dma #( // Count gnt write transaction and generate event pulse if WINDOW_SIZE is reached assign dma_window_event = |reg2hw.window_size.q & data_out_gnt & (window_counter + 'h1 >= {19'h0, reg2hw.window_size.q}); + + assign src_data_type = dma_data_type_t'(reg2hw.src_data_type.q); + endmodule : dma diff --git a/hw/ip/dma/rtl/dma_reg_pkg.sv b/hw/ip/dma/rtl/dma_reg_pkg.sv index 4e98968c2..36fb3cc24 100644 --- a/hw/ip/dma/rtl/dma_reg_pkg.sv +++ b/hw/ip/dma/rtl/dma_reg_pkg.sv @@ -56,7 +56,7 @@ package dma_reg_pkg; typedef struct packed {logic q;} dma_reg2hw_sign_ext_reg_t; - typedef struct packed {logic [1:0] q;} dma_reg2hw_mode_reg_t; + typedef struct packed {logic [2:0] q;} dma_reg2hw_mode_reg_t; typedef struct packed {logic q;} dma_reg2hw_dim_config_reg_t; @@ -105,21 +105,21 @@ package dma_reg_pkg; // Register -> HW type typedef struct packed { - dma_reg2hw_src_ptr_reg_t src_ptr; // [282:251] - dma_reg2hw_dst_ptr_reg_t dst_ptr; // [250:219] - dma_reg2hw_addr_ptr_reg_t addr_ptr; // [218:187] - dma_reg2hw_size_d1_reg_t size_d1; // [186:170] - dma_reg2hw_size_d2_reg_t size_d2; // [169:154] - dma_reg2hw_status_reg_t status; // [153:150] - dma_reg2hw_src_ptr_inc_d1_reg_t src_ptr_inc_d1; // [149:144] - dma_reg2hw_src_ptr_inc_d2_reg_t src_ptr_inc_d2; // [143:121] - dma_reg2hw_dst_ptr_inc_d1_reg_t dst_ptr_inc_d1; // [120:115] - dma_reg2hw_dst_ptr_inc_d2_reg_t dst_ptr_inc_d2; // [114:92] - dma_reg2hw_slot_reg_t slot; // [91:60] - dma_reg2hw_src_data_type_reg_t src_data_type; // [59:58] - dma_reg2hw_dst_data_type_reg_t dst_data_type; // [57:56] - dma_reg2hw_sign_ext_reg_t sign_ext; // [55:55] - dma_reg2hw_mode_reg_t mode; // [54:53] + dma_reg2hw_src_ptr_reg_t src_ptr; // [283:252] + dma_reg2hw_dst_ptr_reg_t dst_ptr; // [251:220] + dma_reg2hw_addr_ptr_reg_t addr_ptr; // [219:188] + dma_reg2hw_size_d1_reg_t size_d1; // [187:171] + dma_reg2hw_size_d2_reg_t size_d2; // [170:155] + dma_reg2hw_status_reg_t status; // [154:151] + dma_reg2hw_src_ptr_inc_d1_reg_t src_ptr_inc_d1; // [150:145] + dma_reg2hw_src_ptr_inc_d2_reg_t src_ptr_inc_d2; // [144:122] + dma_reg2hw_dst_ptr_inc_d1_reg_t dst_ptr_inc_d1; // [121:116] + dma_reg2hw_dst_ptr_inc_d2_reg_t dst_ptr_inc_d2; // [115:93] + dma_reg2hw_slot_reg_t slot; // [92:61] + dma_reg2hw_src_data_type_reg_t src_data_type; // [60:59] + dma_reg2hw_dst_data_type_reg_t dst_data_type; // [58:57] + dma_reg2hw_sign_ext_reg_t sign_ext; // [56:56] + dma_reg2hw_mode_reg_t mode; // [55:53] dma_reg2hw_dim_config_reg_t dim_config; // [52:52] dma_reg2hw_dim_inv_reg_t dim_inv; // [51:51] dma_reg2hw_pad_top_reg_t pad_top; // [50:45] diff --git a/hw/ip/dma/rtl/dma_reg_top.sv b/hw/ip/dma/rtl/dma_reg_top.sv index ea7897c00..728a7c469 100644 --- a/hw/ip/dma/rtl/dma_reg_top.sv +++ b/hw/ip/dma/rtl/dma_reg_top.sv @@ -114,8 +114,8 @@ module dma_reg_top #( logic sign_ext_qs; logic sign_ext_wd; logic sign_ext_we; - logic [1:0] mode_qs; - logic [1:0] mode_wd; + logic [2:0] mode_qs; + logic [2:0] mode_wd; logic mode_we; logic dim_config_qs; logic dim_config_wd; @@ -564,9 +564,9 @@ module dma_reg_top #( // R[mode]: V(False) prim_subreg #( - .DW (2), + .DW (3), .SWACCESS("RW"), - .RESVAL (2'h0) + .RESVAL (3'h0) ) u_mode ( .clk_i (clk_i), .rst_ni(rst_ni), @@ -1002,7 +1002,7 @@ module dma_reg_top #( assign sign_ext_wd = reg_wdata[0]; assign mode_we = addr_hit[14] & reg_we & !reg_error; - assign mode_wd = reg_wdata[1:0]; + assign mode_wd = reg_wdata[2:0]; assign dim_config_we = addr_hit[15] & reg_we & !reg_error; assign dim_config_wd = reg_wdata[0]; @@ -1098,7 +1098,7 @@ module dma_reg_top #( end addr_hit[14]: begin - reg_rdata_next[1:0] = mode_qs; + reg_rdata_next[2:0] = mode_qs; end addr_hit[15]: begin diff --git a/sw/applications/example_dma_subaddressing/buffer.h b/sw/applications/example_dma_subaddressing/buffer.h new file mode 100644 index 000000000..66d8b1734 --- /dev/null +++ b/sw/applications/example_dma_subaddressing/buffer.h @@ -0,0 +1,67 @@ + uint32_t flash_original_128B[32] = { + 0x76543211, 0xfedcba99, 0x579a6f91, 0x657d5bef, 0x758ee420, 0x01234568, 0xfedbca97, 0x89abde00, + 0x76543212, 0xfedcba9a, 0x579a6f92, 0x657d5bf0, 0x758ee421, 0x01234569, 0xfedbca98, 0x89abde01, + 0x76543213, 0xfedcba9b, 0x579a6f93, 0x657d5bf1, 0x758ee422, 0x0123456a, 0xfedbca99, 0x89abde02, + 0x76543214, 0xfedcba9c, 0x579a6f94, 0x657d5bf2, 0x758ee423, 0x0123456b, 0xfedbca9a, 0x89abde03 +}; + +uint32_t test_flash_se_half_words[64] = { + 0x00003211, 0x00007654, 0xffffba99, 0xfffffedc, 0x00006f91, 0x0000579a, 0x00005bef, 0x0000657d, + 0xffffe420, 0x0000758e, 0x00004568, 0x00000123, 0xffffca97, 0xfffffedb, 0xffffde00, 0xffff89ab, + 0x00003212, 0x00007654, 0xffffba9a, 0xfffffedc, 0x00006f92, 0x0000579a, 0x00005bf0, 0x0000657d, + 0xffffe421, 0x0000758e, 0x00004569, 0x00000123, 0xffffca98, 0xfffffedb, 0xffffde01, 0xffff89ab, + 0x00003213, 0x00007654, 0xffffba9b, 0xfffffedc, 0x00006f93, 0x0000579a, 0x00005bf1, 0x0000657d, + 0xffffe422, 0x0000758e, 0x0000456a, 0x00000123, 0xffffca99, 0xfffffedb, 0xffffde02, 0xffff89ab, + 0x00003214, 0x00007654, 0xffffba9c, 0xfffffedc, 0x00006f94, 0x0000579a, 0x00005bf2, 0x0000657d, + 0xffffe423, 0x0000758e, 0x0000456b, 0x00000123, 0xffffca9a, 0xfffffedb, 0xffffde03, 0xffff89ab +}; + +uint32_t test_flash_half_words[64] = { + 0x00003211, 0x00007654, 0x0000ba99, 0x0000fedc, 0x00006f91, 0x0000579a, 0x00005bef, 0x0000657d, + 0x0000e420, 0x0000758e, 0x00004568, 0x00000123, 0x0000ca97, 0x0000fedb, 0x0000de00, 0x000089ab, + 0x00003212, 0x00007654, 0x0000ba9a, 0x0000fedc, 0x00006f92, 0x0000579a, 0x00005bf0, 0x0000657d, + 0x0000e421, 0x0000758e, 0x00004569, 0x00000123, 0x0000ca98, 0x0000fedb, 0x0000de01, 0x000089ab, + 0x00003213, 0x00007654, 0x0000ba9b, 0x0000fedc, 0x00006f93, 0x0000579a, 0x00005bf1, 0x0000657d, + 0x0000e422, 0x0000758e, 0x0000456a, 0x00000123, 0x0000ca99, 0x0000fedb, 0x0000de02, 0x000089ab, + 0x00003214, 0x00007654, 0x0000ba9c, 0x0000fedc, 0x00006f94, 0x0000579a, 0x00005bf2, 0x0000657d, + 0x0000e423, 0x0000758e, 0x0000456b, 0x00000123, 0x0000ca9a, 0x0000fedb, 0x0000de03, 0x000089ab +}; + +uint32_t test_flash_se_bytes[128] = { + 0x00000011, 0x00000032, 0x00000054, 0x00000076, 0xffffff99, 0xffffffba, 0xffffffdc, 0xfffffffe, + 0xffffff91, 0x0000006f, 0xffffff9a, 0x00000057, 0xffffffef, 0x0000005b, 0x0000007d, 0x00000065, + 0x00000020, 0xffffffe4, 0xffffff8e, 0x00000075, 0x00000068, 0x00000045, 0x00000023, 0x00000001, + 0xffffff97, 0xffffffca, 0xffffffdb, 0xfffffffe, 0x00000000, 0xffffffde, 0xffffffab, 0xffffff89, + 0x00000012, 0x00000032, 0x00000054, 0x00000076, 0xffffff9a, 0xffffffba, 0xffffffdc, 0xfffffffe, + 0xffffff92, 0x0000006f, 0xffffff9a, 0x00000057, 0xfffffff0, 0x0000005b, 0x0000007d, 0x00000065, + 0x00000021, 0xffffffe4, 0xffffff8e, 0x00000075, 0x00000069, 0x00000045, 0x00000023, 0x00000001, + 0xffffff98, 0xffffffca, 0xffffffdb, 0xfffffffe, 0x00000001, 0xffffffde, 0xffffffab, 0xffffff89, + 0x00000013, 0x00000032, 0x00000054, 0x00000076, 0xffffff9b, 0xffffffba, 0xffffffdc, 0xfffffffe, + 0xffffff93, 0x0000006f, 0xffffff9a, 0x00000057, 0xfffffff1, 0x0000005b, 0x0000007d, 0x00000065, + 0x00000022, 0xffffffe4, 0xffffff8e, 0x00000075, 0x0000006a, 0x00000045, 0x00000023, 0x00000001, + 0xffffff99, 0xffffffca, 0xffffffdb, 0xfffffffe, 0x00000002, 0xffffffde, 0xffffffab, 0xffffff89, + 0x00000014, 0x00000032, 0x00000054, 0x00000076, 0xffffff9c, 0xffffffba, 0xffffffdc, 0xfffffffe, + 0xffffff94, 0x0000006f, 0xffffff9a, 0x00000057, 0xfffffff2, 0x0000005b, 0x0000007d, 0x00000065, + 0x00000023, 0xffffffe4, 0xffffff8e, 0x00000075, 0x0000006b, 0x00000045, 0x00000023, 0x00000001, + 0xffffff9a, 0xffffffca, 0xffffffdb, 0xfffffffe, 0x00000003, 0xffffffde, 0xffffffab, 0xffffff89 +}; + +uint32_t test_flash_bytes[128] = { + 0x00000011, 0x00000032, 0x00000054, 0x00000076, 0x00000099, 0x000000ba, 0x000000dc, 0x000000fe, + 0x00000091, 0x0000006f, 0x0000009a, 0x00000057, 0x000000ef, 0x0000005b, 0x0000007d, 0x00000065, + 0x00000020, 0x000000e4, 0x0000008e, 0x00000075, 0x00000068, 0x00000045, 0x00000023, 0x00000001, + 0x00000097, 0x000000ca, 0x000000db, 0x000000fe, 0x00000000, 0x000000de, 0x000000ab, 0x00000089, + 0x00000012, 0x00000032, 0x00000054, 0x00000076, 0x0000009a, 0x000000ba, 0x000000dc, 0x000000fe, + 0x00000092, 0x0000006f, 0x0000009a, 0x00000057, 0x000000f0, 0x0000005b, 0x0000007d, 0x00000065, + 0x00000021, 0x000000e4, 0x0000008e, 0x00000075, 0x00000069, 0x00000045, 0x00000023, 0x00000001, + 0x00000098, 0x000000ca, 0x000000db, 0x000000fe, 0x00000001, 0x000000de, 0x000000ab, 0x00000089, + 0x00000013, 0x00000032, 0x00000054, 0x00000076, 0x0000009b, 0x000000ba, 0x000000dc, 0x000000fe, + 0x00000093, 0x0000006f, 0x0000009a, 0x00000057, 0x000000f1, 0x0000005b, 0x0000007d, 0x00000065, + 0x00000022, 0x000000e4, 0x0000008e, 0x00000075, 0x0000006a, 0x00000045, 0x00000023, 0x00000001, + 0x00000099, 0x000000ca, 0x000000db, 0x000000fe, 0x00000002, 0x000000de, 0x000000ab, 0x00000089, + 0x00000014, 0x00000032, 0x00000054, 0x00000076, 0x0000009c, 0x000000ba, 0x000000dc, 0x000000fe, + 0x00000094, 0x0000006f, 0x0000009a, 0x00000057, 0x000000f2, 0x0000005b, 0x0000007d, 0x00000065, + 0x00000023, 0x000000e4, 0x0000008e, 0x00000075, 0x0000006b, 0x00000045, 0x00000023, 0x00000001, + 0x0000009a, 0x000000ca, 0x000000db, 0x000000fe, 0x00000003, 0x000000de, 0x000000ab, 0x00000089 +}; + diff --git a/sw/applications/example_dma_subaddressing/main.c b/sw/applications/example_dma_subaddressing/main.c new file mode 100644 index 000000000..14ed76ee0 --- /dev/null +++ b/sw/applications/example_dma_subaddressing/main.c @@ -0,0 +1,296 @@ +/** + * @file main.c + * @brief Simple spi write example using BSP + * + * Simple example that writes a 1kB buffer to flash memory at a specific address + * and then read it back to check if the data was written correctly. + * +*/ + +#include +#include +#include + +/* To get TX and RX FIFO depth */ +#include "spi_host_regs.h" +/* To get SPI functions */ +#include "spi_host.h" + +#include "x-heep.h" +#include "w25q128jw.h" +#include "dma.h" + +/* By default, PRINTFs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 0 +#define PRINTF_IN_SIM 1 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#if defined(TARGET_PYNQ_Z2) || defined(TARGET_ZCU104) || defined(TARGET_NEXYS_A7_100T) + #define USE_SPI_FLASH +#endif + +#ifndef TARGET_SIM +#define USE_SPI_FLASH +#endif + +// Start buffers (the original data) +#include "buffer.h" +// End buffer (where what is read is stored) +uint32_t flash_data[256]; + +#define TEST_BUFFER_WORDS flash_original_128B +#define TEST_BUFFER_SE_HALF_WORDS test_flash_se_half_words +#define TEST_BUFFER_SE_BYTES test_flash_se_bytes +#define TEST_BUFFER_HALF_WORDS test_flash_half_words +#define TEST_BUFFER_BYTES test_flash_bytes +#define LENGTH 128 + +typedef enum { + TYPE_WORD = 2, + TYPE_HALF_WORD = 1, + TYPE_BYTE = 0 +} dma_trans_data_t; + +// Test functions +uint32_t test_read_dma(uint32_t *test_buffer, uint32_t len, dma_trans_data_t dma_data_type, uint8_t sign_extend); +uint32_t test_read_quad_dma(uint32_t *test_buffer, uint32_t len, dma_trans_data_t dma_data_type, uint8_t sign_extend); + +// Check function +uint32_t check_result(uint32_t *test_buffer, uint32_t len, dma_trans_data_t dma_data_type, uint32_t sign_extend); + +// Define global status variable +w25q_error_codes_t global_status; + +int main(int argc, char *argv[]) { + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) { + PRINTF("This application cannot work with the memory mapped SPI FLASH" + "module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; + } + + // Pick the correct spi device based on simulation type + spi_host_t* spi; + #ifndef USE_SPI_FLASH + spi = spi_host1; + #else + spi = spi_flash; + #endif + + // Define status variable + int32_t errors = 0; + + // Init SPI host and SPI<->Flash bridge parameters + if (w25q128jw_init(spi) != FLASH_OK) return EXIT_FAILURE; + + // DMA transaction data type + dma_trans_data_t dma_data_type; + + // Test simple read with DMA + PRINTF("Testing read with DMA in SUBADDRESS mode...\n"); + + dma_data_type = TYPE_WORD; + errors += test_read_dma(TEST_BUFFER_WORDS, LENGTH, dma_data_type, 0); + dma_data_type = TYPE_HALF_WORD; + errors += test_read_dma(TEST_BUFFER_HALF_WORDS, LENGTH, dma_data_type, 0); + errors += test_read_dma(TEST_BUFFER_SE_HALF_WORDS, LENGTH, dma_data_type, 1); + dma_data_type = TYPE_BYTE; + errors += test_read_dma(TEST_BUFFER_BYTES, LENGTH, dma_data_type, 0); + errors += test_read_dma(TEST_BUFFER_SE_BYTES, LENGTH, dma_data_type, 1); + + // Test quad read with DMA + dma_data_type = TYPE_WORD; + errors += test_read_quad_dma(TEST_BUFFER_WORDS, LENGTH, dma_data_type, 0); + dma_data_type = TYPE_HALF_WORD; + errors += test_read_quad_dma(TEST_BUFFER_HALF_WORDS, LENGTH, dma_data_type, 0); + errors += test_read_quad_dma(TEST_BUFFER_SE_HALF_WORDS, LENGTH, dma_data_type, 1); + dma_data_type = TYPE_BYTE; + errors += test_read_quad_dma(TEST_BUFFER_BYTES, LENGTH, dma_data_type, 0); + errors += test_read_quad_dma(TEST_BUFFER_SE_BYTES, LENGTH, dma_data_type, 1); + + PRINTF("\n--------TEST FINISHED--------\n"); + if (errors == 0) { + PRINTF("All tests passed!\n"); + return EXIT_SUCCESS; + } else { + PRINTF("Some tests failed!\n"); + return EXIT_FAILURE; + } + +} + +uint32_t test_read_dma(uint32_t *test_buffer, uint32_t len, dma_trans_data_t dma_data_type, uint8_t sign_extend) { + + dma_data_type_t dma_trans_data_type; + + switch (dma_data_type) { + case TYPE_WORD: + dma_trans_data_type = DMA_DATA_TYPE_WORD; + break; + case TYPE_HALF_WORD: + dma_trans_data_type = DMA_DATA_TYPE_HALF_WORD; + break; + case TYPE_BYTE: + dma_trans_data_type = DMA_DATA_TYPE_BYTE; + break; + default: + break; + } + + dma_init(NULL); + + // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal + #ifndef USE_SPI_FLASH + uint8_t slot = DMA_TRIG_SLOT_SPI_RX; + #else + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX; + #endif + + // Set up DMA source target + dma_target_t tgt_src = { + .inc_d1_du = 0, // Target is peripheral, no increment + .type = dma_trans_data_type, + }; + // Target is SPI RX FIFO + tgt_src.ptr = (uint8_t*) (w25q128jw_read_standard_setup((uint32_t*)(TEST_BUFFER_WORDS), flash_data, len)); + // Trigger to control the data flow + tgt_src.trig = slot; + + // Set up DMA destination target + dma_target_t tgt_dst = { + .inc_d1_du = 1, // Increment by 1 data unit (word) + .type = DMA_DATA_TYPE_WORD, + .trig = DMA_TRIG_MEMORY, // Read-write operation to memory + }; + tgt_dst.ptr = (uint8_t*)flash_data; // Target is the data buffer + + // Set up DMA transaction + dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .end = DMA_TRANS_END_POLLING, + .mode = DMA_TRANS_MODE_SUBADDRESS, + .sign_ext = sign_extend, + }; + + // Size is in data units (words in this case) + trans.size_d1_du = len >> (dma_data_type); + + // Validate, load and launch DMA transaction + dma_config_flags_t res; + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + res = dma_load_transaction(&trans); + res = dma_launch(&trans); + + // Wait for DMA to finish transaction + while(!dma_is_ready(0)); + + uint32_t result = check_result(test_buffer, len, dma_data_type, sign_extend); + + // Reset the flash data buffer + memset(flash_data, 0, len * sizeof(uint8_t)); + + return result; +} + +uint32_t test_read_quad_dma(uint32_t *test_buffer, uint32_t len, dma_trans_data_t dma_data_type, uint8_t sign_extend) { + + dma_data_type_t dma_trans_data_type; + + switch (dma_data_type) { + case TYPE_WORD: + dma_trans_data_type = DMA_DATA_TYPE_WORD; + break; + case TYPE_HALF_WORD: + dma_trans_data_type = DMA_DATA_TYPE_HALF_WORD; + break; + case TYPE_BYTE: + dma_trans_data_type = DMA_DATA_TYPE_BYTE; + break; + default: + break; + } + + dma_init(NULL); + + // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal + #ifndef USE_SPI_FLASH + uint8_t slot = DMA_TRIG_SLOT_SPI_RX; + #else + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX; + #endif + + // Set up DMA source target + dma_target_t tgt_src = { + .inc_d1_du = 0, // Target is peripheral, no increment + .type = dma_trans_data_type, + }; + // Target is SPI RX FIFO + tgt_src.ptr = (uint8_t*) (w25q128jw_read_quad_setup((uint32_t*)(TEST_BUFFER_WORDS), flash_data, len)); + // Trigger to control the data flow + tgt_src.trig = slot; + + // Set up DMA destination target + dma_target_t tgt_dst = { + .inc_d1_du = 1, // Increment by 1 data unit (word) + .type = DMA_DATA_TYPE_WORD, + .trig = DMA_TRIG_MEMORY, // Read-write operation to memory + }; + tgt_dst.ptr = (uint8_t*)flash_data; // Target is the data buffer + + // Set up DMA transaction + dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .end = DMA_TRANS_END_POLLING, + .mode = DMA_TRANS_MODE_SUBADDRESS, + .sign_ext = sign_extend, + }; + + // Size is in data units (words in this case) + trans.size_d1_du = len >> (dma_data_type); + + // Validate, load and launch DMA transaction + dma_config_flags_t res; + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + res = dma_load_transaction(&trans); + res = dma_launch(&trans); + + // Wait for DMA to finish transaction + while(!dma_is_ready(0)); + + uint32_t result = check_result(test_buffer, len, dma_data_type, sign_extend); + + // Reset the flash data buffer + memset(flash_data, 0, len * sizeof(uint8_t)); + + return result; +} + +uint32_t check_result(uint32_t *test_buffer, uint32_t len, dma_trans_data_t dma_data_type, uint32_t sign_extend) { + uint32_t errors = 0; + + for (uint32_t i = 0; i < len>>dma_data_type; i += 1) { + if (test_buffer[i] != flash_data[i]) { + PRINTF("Error in transfer %d %d at position %d: expected %x, got %x\n", dma_data_type, sign_extend, i, test_buffer[i], flash_data[i]); + errors++; + } + } + + if (errors == 0) { + PRINTF("success!\n"); + } else { + PRINTF("failure, %d errors!\n", errors); + } + + return errors; +} diff --git a/sw/applications/example_power_manager/main.c b/sw/applications/example_power_manager/main.c index e1fe60e90..7e07ce2d2 100644 --- a/sw/applications/example_power_manager/main.c +++ b/sw/applications/example_power_manager/main.c @@ -26,7 +26,7 @@ /* By default, printfs are activated for FPGA and disabled for simulation. */ #define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 +#define PRINTF_IN_SIM 1 #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) @@ -460,4 +460,4 @@ int main(int argc, char *argv[]) #endif return EXIT_SUCCESS; -} +} \ No newline at end of file diff --git a/sw/device/bsp/w25q/w25q.c b/sw/device/bsp/w25q/w25q.c index f6a3ac990..eb5a5b623 100644 --- a/sw/device/bsp/w25q/w25q.c +++ b/sw/device/bsp/w25q/w25q.c @@ -319,6 +319,54 @@ w25q_error_codes_t w25q128jw_write(uint32_t addr, void *data, uint32_t length, u return status; } +uint32_t* w25q128jw_read_standard_setup(uint32_t addr, void *data, uint32_t length) { + + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return NULL; + + // Take into account the extra bytes (if any) + if (length % 4 != 0) { + //only multiple of 4 bytes are supported in this function + return NULL; + } + + /* + * SET UP DMA + */ + // SPI and SPI_FLASH are the same IP so same register map + uint32_t *fifo_ptr_rx = (uint32_t *)((uintptr_t)spi + SPI_HOST_RXDATA_REG_OFFSET); + + // Address + Read command + uint32_t read_byte_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_RD); + // Load command to TX FIFO + spi_write_word(spi, read_byte_cmd); + spi_wait_for_ready(spi); + + // Set up segment parameters -> send command and address + const uint32_t cmd_read_1 = spi_create_command((spi_command_t){ + .len = 3, // 4 Bytes + .csaat = true, // Command not finished + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only + }); + // Load segment parameters to COMMAND register + spi_set_command(spi, cmd_read_1); + spi_wait_for_ready(spi); + + // Set up segment parameters -> read length bytes + const uint32_t cmd_read_2 = spi_create_command((spi_command_t){ + .len = length-1, // len bytes + .csaat = false, // End command + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_RX_ONLY // Read only + }); + spi_set_command(spi, cmd_read_2); + spi_wait_for_ready(spi); + + + return fifo_ptr_rx; +} + w25q_error_codes_t w25q128jw_read_standard(uint32_t addr, void* data, uint32_t length) { // Sanity checks if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; @@ -440,7 +488,6 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard(uint32_t addr, void* data, } - w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length, uint8_t no_wait_init_dma, uint8_t no_sanity_checks) { // Sanity checks @@ -540,6 +587,7 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 return FLASH_OK; } + w25q_error_codes_t w25q128jw_read_standard_dma_async(uint32_t addr, void *data, uint32_t length) { // Sanity checks @@ -679,6 +727,67 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard_dma(uint32_t addr, void* d } +uint32_t* w25q128jw_read_quad_setup(uint32_t addr, void *data, uint32_t length) { + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return NULL; + + // Send quad read command at standard speed + uint32_t cmd_read_quadIO = FC_RDQIO; + spi_write_word(spi, cmd_read_quadIO); + const uint32_t cmd_read = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only + }); + spi_set_command(spi, cmd_read); + spi_wait_for_ready(spi); + + /* + * Send address at quad speed. + * Last byte is Fxh (here FFh) required by W25Q128JW + */ + uint32_t read_byte_cmd = (REVERT_24b_ADDR(addr) | (0xFF << 24)); + spi_write_word(spi, read_byte_cmd); + const uint32_t cmd_address = spi_create_command((spi_command_t){ + .len = 3, // 3 Byte + .csaat = true, // Command not finished + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_TX_ONLY // Write only + }); + spi_set_command(spi, cmd_address); + spi_wait_for_ready(spi); + + // Quad read requires dummy clocks + const uint32_t dummy_clocks_cmd = spi_create_command((spi_command_t){ + #ifndef TARGET_SIM + .len = DUMMY_CLOCKS_FAST_READ_QUAD_IO-1, // W25Q128JW flash needs 4 dummy cycles + #else + .len = DUMMY_CLOCKS_SIM-1, // SPI flash simulation model needs 8 dummy cycles + #endif + .csaat = true, // Command not finished + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_DUMMY // Dummy + }); + spi_set_command(spi, dummy_clocks_cmd); + spi_wait_for_ready(spi); + + // Read back the requested data at quad speed + const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ + .len = length-1, // length bytes + .csaat = false, // End command + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_RX_ONLY // Read only + }); + spi_set_command(spi, cmd_read_rx); + spi_wait_for_ready(spi); + + /* COMMAND FINISHED */ + + // SPI and SPI_FLASH are the same IP so same register map + return (uint32_t *)((uintptr_t)spi + SPI_HOST_RXDATA_REG_OFFSET); + +} w25q_error_codes_t w25q128jw_read_quad(uint32_t addr, void *data, uint32_t length) { // Sanity checks diff --git a/sw/device/bsp/w25q/w25q128jw.h b/sw/device/bsp/w25q/w25q128jw.h index 501f69c60..21449455d 100644 --- a/sw/device/bsp/w25q/w25q128jw.h +++ b/sw/device/bsp/w25q/w25q128jw.h @@ -224,6 +224,16 @@ w25q_error_codes_t w25q128jw_read(uint32_t addr, void* data, uint32_t length); */ w25q_error_codes_t w25q128jw_write(uint32_t addr, void* data, uint32_t length, uint8_t erase_before_write); +/** + * @brief Setup SPI to read from flash at standard speed. (NEEDS TO BE FOLLOWED BY MANUAL SETUP OF THE DMA) + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return ptr to SPI data register. +*/ +uint32_t* w25q128jw_read_standard_setup(uint32_t addr, void *data, uint32_t length); + /** * @brief Read from flash at standard speed. * @@ -309,6 +319,16 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard_dma(uint32_t addr, void* d */ w25q_error_codes_t w25q128jw_read_quad(uint32_t addr, void* data, uint32_t length); +/** + * @brief Setup SPI to read from flash at quad speed. (NEEDS TO BE FOLLOWED BY MANUAL SETUP OF THE DMA) + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return ptr to SPI data register. +*/ +uint32_t* w25q128jw_read_quad_setup(uint32_t addr, void *data, uint32_t length); + /** * @brief Write to flash at quad speed. Use this function only to write to unitialized data * diff --git a/sw/device/lib/drivers/dma/dma.c b/sw/device/lib/drivers/dma/dma.c index 3d1023143..6c0921722 100644 --- a/sw/device/lib/drivers/dma/dma.c +++ b/sw/device/lib/drivers/dma/dma.c @@ -60,7 +60,7 @@ extern "C" /** * Returns the mask to enable/disable DMA interrupts. */ -#define DMA_CSR_REG_MIE_MASK (( 1 << 19 ) | (1 << 11 ) ) // @ToDo Add definitions for this 19 and 11 +#define DMA_CSR_REG_MIE_MASK (( 1 << 19 )) // 19 is DMA fast interrupt bit in MIE CSR /** * Mask to determine if an address is multiple of 4 (Word aligned). diff --git a/sw/device/lib/drivers/dma/dma.h b/sw/device/lib/drivers/dma/dma.h index 98a4f0f4b..d4b996200 100644 --- a/sw/device/lib/drivers/dma/dma.h +++ b/sw/device/lib/drivers/dma/dma.h @@ -227,7 +227,7 @@ typedef enum parameters. This generates a circular mode in the source and/or destination pointing to memory. */ DMA_TRANS_MODE_ADDRESS = DMA_MODE_MODE_VALUE_ADDRESS_MODE, /*!< In this mode, the destination address is read from the address port! */ - + DMA_TRANS_MODE_SUBADDRESS = 4, DMA_TRANS_MODE__size, /*!< Not used, only for sanity checks. */ } dma_trans_mode_t; diff --git a/sw/device/lib/drivers/dma/dma_regs.h b/sw/device/lib/drivers/dma/dma_regs.h index c0ef3797a..6500f3bd3 100644 --- a/sw/device/lib/drivers/dma/dma_regs.h +++ b/sw/device/lib/drivers/dma/dma_regs.h @@ -114,13 +114,14 @@ extern "C" { // Set the operational mode of the DMA #define DMA_MODE_REG_OFFSET 0x38 -#define DMA_MODE_MODE_MASK 0x3 +#define DMA_MODE_MODE_MASK 0x7 #define DMA_MODE_MODE_OFFSET 0 #define DMA_MODE_MODE_FIELD \ ((bitfield_field32_t) { .mask = DMA_MODE_MODE_MASK, .index = DMA_MODE_MODE_OFFSET }) #define DMA_MODE_MODE_VALUE_LINEAR_MODE 0x0 #define DMA_MODE_MODE_VALUE_CIRCULAR_MODE 0x1 #define DMA_MODE_MODE_VALUE_ADDRESS_MODE 0x2 +#define DMA_MODE_MODE_VALUE_SUBADDRESS_MODE 0x3 // Set the dimensionality of the DMA #define DMA_DIM_CONFIG_REG_OFFSET 0x3c