From aa467fd07d8c0f4b4452cd0b123812e8bae9125c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Sun, 7 Dec 2025 01:05:31 +0100 Subject: [PATCH] Integrate a memory mapped timer --- CMakeLists.txt | 7 +- config/pinout.lpf | 32 +++---- firmware/helloworld.S | 47 +++++++++- src/ecap5_dsoc.sv | 100 ++++++++++++++++++--- tests/benches/ecap5_dsoc/tb_ecap5_dsoc.cpp | 2 +- tests/benches/ecap5_dsoc/tb_ecap5_dsoc.sv | 11 ++- 6 files changed, 167 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1421050..581c2f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,10 @@ add_dependency( GIT ecap5/ecap5-dwbmem-bram TAG release/v1.0.0) +add_dependency( + GIT ecap5/ecap5-dwbtimer + TAG release/v1.0.0) + # Define an interface library add_library(ecap5_dsoc INTERFACE) target_sources(ecap5_dsoc INTERFACE @@ -85,6 +89,7 @@ target_link_libraries(ecap5_dsoc INTERFACE ecap5_dproc ecap5_dwbuart ecap5_dwbmem_bram + ecap5_dwbtimer ) if(PROJECT_IS_TOP_LEVEL) @@ -111,7 +116,7 @@ if(PROJECT_IS_TOP_LEVEL) TARGET_FPGA ecp5 OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/synth.json DEPENDS helloworld - DEFINES BOOTLOADER_PATH=\\\"${CMAKE_CURRENT_BINARY_DIR}/firmware/helloworld.dump\\\") + DEFINES BOOTLOADER_PATH=\\\"${CMAKE_CURRENT_BINARY_DIR}/firmware/helloworld.load\\\") add_place_and_route_target( INPUT ${CMAKE_CURRENT_BINARY_DIR}/synth.json diff --git a/config/pinout.lpf b/config/pinout.lpf index 43509c6..f661597 100644 --- a/config/pinout.lpf +++ b/config/pinout.lpf @@ -74,13 +74,13 @@ # SRAM - Control signals -# LOCATE COMP "sram_ce_n" SITE "A28"; + LOCATE COMP "sram_ce_n" SITE "A28"; # LOCATE COMP "sram_oe_n" SITE "C20"; # LOCATE COMP "sram_lb_n" SITE "D20"; # LOCATE COMP "sram_ub_n" SITE "C22"; # LOCATE COMP "sram_we_n" SITE "F24"; # -# PORT "sram_ce_n" IO_TYPE=LVCMOS33; + PORT "sram_ce_n" IO_TYPE=LVCMOS33; # PORT "sram_oe_n" IO_TYPE=LVCMOS33; # PORT "sram_lb_n" IO_TYPE=LVCMOS33; # PORT "sram_ub_n" IO_TYPE=LVCMOS33; @@ -160,17 +160,17 @@ # SDRAM0 - Control signals -# LOCATE COMP "sdram0_cs_n" SITE "B3"; + LOCATE COMP "sdram0_cs_n" SITE "B3"; # LOCATE COMP "sdram0_we_n" SITE "B4"; -# LOCATE COMP "sdram0_cke" SITE "A2"; + LOCATE COMP "sdram0_cke" SITE "A2"; # LOCATE COMP "sdram0_cas_n" SITE "A3"; # LOCATE COMP "sdram0_ras_n" SITE "A4"; # LOCATE COMP "sdram0_dqml" SITE "A5"; # LOCATE COMP "sdram0_dqmh" SITE "A8"; # -# PORT "sdram0_cs_n" IO_TYPE=LVCMOS33; + PORT "sdram0_cs_n" IO_TYPE=LVCMOS33; # PORT "sdram0_we_n" IO_TYPE=LVCMOS33; -# PORT "sdram0_cke" IO_TYPE=LVCMOS33; + PORT "sdram0_cke" IO_TYPE=LVCMOS33; # PORT "sdram0_cas_n" IO_TYPE=LVCMOS33; # PORT "sdram0_ras_n" IO_TYPE=LVCMOS33; # PORT "sdram0_dqml" IO_TYPE=LVCMOS33; @@ -214,17 +214,17 @@ # SDRAM1 - Control signals -# LOCATE COMP "sdram1_cs_n" SITE "A10"; + LOCATE COMP "sdram1_cs_n" SITE "A10"; # LOCATE COMP "sdram1_we_n" SITE "A13"; -# LOCATE COMP "sdram1_cke" SITE "A9"; + LOCATE COMP "sdram1_cke" SITE "A9"; # LOCATE COMP "sdram1_cas_n" SITE "A11"; # LOCATE COMP "sdram1_ras_n" SITE "A14"; # LOCATE COMP "sdram1_dqml" SITE "A15"; # LOCATE COMP "sdram1_dqmh" SITE "A16"; # -# PORT "sdram1_cs_n" IO_TYPE=LVCMOS33; + PORT "sdram1_cs_n" IO_TYPE=LVCMOS33; # PORT "sdram1_we_n" IO_TYPE=LVCMOS33; -# PORT "sdram1_cke" IO_TYPE=LVCMOS33; + PORT "sdram1_cke" IO_TYPE=LVCMOS33; # PORT "sdram1_cas_n" IO_TYPE=LVCMOS33; # PORT "sdram1_ras_n" IO_TYPE=LVCMOS33; # PORT "sdram1_dqml" IO_TYPE=LVCMOS33; @@ -306,19 +306,19 @@ # DDR2 - Control signals -# LOCATE COMP "ddr2_cs_n" SITE "F3"; + LOCATE COMP "ddr2_cs_n" SITE "F3"; # LOCATE COMP "ddr2_odt" SITE "E3"; # LOCATE COMP "ddr2_cas_n" SITE "H1"; # LOCATE COMP "ddr2_ras_n" SITE "H2"; -# LOCATE COMP "ddr2_cke" SITE "J3"; + LOCATE COMP "ddr2_cke" SITE "J3"; # LOCATE COMP "ddr2_we_n" SITE "J1"; # LOCATE COMP "ddr2_ck" SITE "H6"; # LOCATE COMP "ddr2_dm" SITE "K6"; # LOCATE COMP "ddr2_dqs" SITE "N3"; # -# PORT "ddr2_cs_n" IO_TYPE=SSTL18_I; + PORT "ddr2_cs_n" IO_TYPE=SSTL18_I; # PORT "ddr2_ck" IO_TYPE=SSTL18D_I; -# PORT "ddr2_cke" IO_TYPE=SSTL18_I; + PORT "ddr2_cke" IO_TYPE=SSTL18_I; # PORT "ddr2_odt" IO_TYPE=SSTL18_I; # PORT "ddr2_cas_n" IO_TYPE=SSTL18_I; # PORT "ddr2_ras_n" IO_TYPE=SSTL18_I; @@ -352,12 +352,12 @@ # LOCATE COMP "emmc_cmd" SITE "B1"; # LOCATE COMP "emmc_ds" SITE "D3"; # LOCATE COMP "emmc_clk" SITE "C2"; -# LOCATE COMP "emmc_rst_n" SITE "C1"; + LOCATE COMP "emmc_rst_n" SITE "C1"; # # PORT "emmc_cmd" IO_TYPE=LVCMOS18; # PORT "emmc_ds" IO_TYPE=LVCMOS18; # PORT "emmc_clk" IO_TYPE=LVCMOS18; -# PORT "emmc_rst_n" IO_TYPE=LVCMOS18; + PORT "emmc_rst_n" IO_TYPE=LVCMOS18; # eMMC - IO signals diff --git a/firmware/helloworld.S b/firmware/helloworld.S index 03fc23b..f42096d 100644 --- a/firmware/helloworld.S +++ b/firmware/helloworld.S @@ -33,6 +33,10 @@ .equ UART_ACC_INCR, 26 .equ UART_DS, 1 +.equ TIMER_BASE, 0x8000 +.equ TIMER_TIMEBASE_LOW, 0x0 +.equ TIMER_TIMEBASE_HIGH, 0x1 + .section .text .global _start _start: @@ -64,8 +68,8 @@ _send_char: # Load the char to send lb x1, 0(x11) - # Loop if end of string - beq x1, x0, _send_string + # If the string is fully sent, wait 1s + beq x1, x0, _wait_1s # Give the char to the UART peripheral sb x1, UART_TXDR(x10) @@ -75,6 +79,45 @@ _send_char: j _check_send_ready +_wait_1s: + # x12 = ms counter + li x12, 1000 + # x13 = TIMER_BASE + li x13, TIMER_BASE + +_read_timebase: + lw x1, TIMER_TIMEBASE_HIGH(x13) + lw x2, TIMER_TIMEBASE_LOW(x13) + lw x3, TIMER_TIMEBASE_HIGH(x13) + + # If the two HIGH's are not equal, loop + bne x1, x3, _read_timebase + +_compare_timebase: + lw x4, TIMER_TIMEBASE_HIGH(x13) + lw x5, TIMER_TIMEBASE_LOW(x13) + lw x6, TIMER_TIMEBASE_HIGH(x13) + + # If the two HIGH's are not equal, loop + bne x4, x6, _compare_timebase + + # If the two are equal + bne x2, x5, _decrement + bne x3, x6, _decrement + + # If equal, we wait more + j _compare_timebase + +_decrement: + # Decrement the counter + addi x12, x12, -1 + + # Check if zero + bne x0, x12, _read_timebase + + # Send the next string + j _send_string + .align 4 msg: diff --git a/src/ecap5_dsoc.sv b/src/ecap5_dsoc.sv index 00df809..3410b36 100644 --- a/src/ecap5_dsoc.sv +++ b/src/ecap5_dsoc.sv @@ -39,7 +39,16 @@ module ecap5_dsoc ( // Buttons interface input logic button0_i, - input logic button1_i + input logic button1_i, + + output logic sram_ce_n, + output logic sdram0_cs_n, + output logic sdram0_cke, + output logic sdram1_cs_n, + output logic sdram1_cke, + output logic ddr2_cs_n, + output logic ddr2_cke, + output logic emmc_rst_n ); // poweron-reset @@ -78,6 +87,17 @@ logic bram_wb_ack_o; logic bram_wb_cyc_i; logic bram_wb_stall_o; +// timer slave memory bus +logic[31:0] timer_wb_adr_i; +logic[31:0] timer_wb_dat_o; +logic[31:0] timer_wb_dat_i; +logic timer_wb_we_i; +logic[3:0] timer_wb_sel_i; +logic timer_wb_stb_i; +logic timer_wb_ack_o; +logic timer_wb_cyc_i; +logic timer_wb_stall_o; + poweron_reset por_inst ( .clk_i (clk_i), .rst_o (por_rst) @@ -136,17 +156,61 @@ ecap5_dwbmem_bram #( .wb_stall_o (bram_wb_stall_o) ); -always_comb begin : memory_mapping - // 00000000 -> 00004000 = BRAM - // 00004000 -> 00008000 = UART - bram_wb_cyc_i = core_wb_cyc_o & ~core_wb_adr_o[14]; - bram_wb_adr_i = core_wb_adr_o; - uart_wb_cyc_i = core_wb_cyc_o & core_wb_adr_o[14]; - uart_wb_adr_i = {core_wb_adr_o[31:15], 1'b0, core_wb_adr_o[13:0]}; +ecap5_dwbtimer #( + .CLK_FREQ (24000000) +) timer_inst ( + .clk_i (clk_i), + .rst_i (por_rst), - core_wb_dat_i = core_wb_adr_o[14] ? uart_wb_dat_o : bram_wb_dat_o; - core_wb_ack_i = core_wb_adr_o[14] ? uart_wb_ack_o : bram_wb_ack_o; - core_wb_stall_i = core_wb_adr_o[14] ? uart_wb_stall_o : bram_wb_stall_o; + .wb_adr_i (timer_wb_adr_i), + .wb_dat_o (timer_wb_dat_o), + .wb_dat_i (timer_wb_dat_i), + .wb_sel_i (timer_wb_sel_i), + .wb_we_i (timer_wb_we_i), + .wb_stb_i (timer_wb_stb_i), + .wb_ack_o (timer_wb_ack_o), + .wb_cyc_i (timer_wb_cyc_i), + .wb_stall_o (timer_wb_stall_o) +); + +always_comb begin : memory_mapping + bram_wb_cyc_i = '0; + bram_wb_adr_i = '0; + uart_wb_cyc_i = '0; + uart_wb_adr_i = '0; + timer_wb_cyc_i = '0; + timer_wb_adr_i = '0; + core_wb_dat_i = '0; + core_wb_ack_i = '0; + core_wb_stall_i = '0; + + // 00000000 -> 00003FFF = BRAM + // 00004000 -> 00007FFF = UART + // 00008000 -> 0000FFFF = TIMER + case(core_wb_adr_o[15:14]) + 2'h0: begin + bram_wb_cyc_i = core_wb_cyc_o; + bram_wb_adr_i = core_wb_adr_o; + core_wb_dat_i = bram_wb_dat_o; + core_wb_ack_i = bram_wb_ack_o; + core_wb_stall_i = bram_wb_stall_o; + end + 2'h1: begin + uart_wb_cyc_i = core_wb_cyc_o; + uart_wb_adr_i = {18'b0, core_wb_adr_o[13:0]}; + core_wb_dat_i = uart_wb_dat_o; + core_wb_ack_i = uart_wb_ack_o; + core_wb_stall_i = uart_wb_stall_o; + end + 2'h2: begin + timer_wb_cyc_i = core_wb_cyc_o; + timer_wb_adr_i = {18'b0, core_wb_adr_o[13:0]}; + core_wb_dat_i = timer_wb_dat_o; + core_wb_ack_i = timer_wb_ack_o; + core_wb_stall_i = timer_wb_stall_o; + end + default: begin end + endcase uart_wb_dat_i = core_wb_dat_o; uart_wb_sel_i = core_wb_sel_o; @@ -157,8 +221,22 @@ always_comb begin : memory_mapping bram_wb_sel_i = core_wb_sel_o; bram_wb_we_i = core_wb_we_o; bram_wb_stb_i = core_wb_stb_o; + + timer_wb_dat_i = core_wb_dat_o; + timer_wb_sel_i = core_wb_sel_o; + timer_wb_we_i = core_wb_we_o; + timer_wb_stb_i = core_wb_stb_o; end // TODO: add GPIO peripheral for LED/button interface +assign sram_ce_n = 1; +assign sdram0_cs_n = 1; +assign sdram0_cke = 0; +assign sdram1_cs_n = 1; +assign sdram1_cke = 0; +assign ddr2_cs_n = 1; +assign ddr2_cke = 0; +assign emmc_rst_n = 0; + endmodule // ecap5_dsoc diff --git a/tests/benches/ecap5_dsoc/tb_ecap5_dsoc.cpp b/tests/benches/ecap5_dsoc/tb_ecap5_dsoc.cpp index 1f56d20..180ef8c 100644 --- a/tests/benches/ecap5_dsoc/tb_ecap5_dsoc.cpp +++ b/tests/benches/ecap5_dsoc/tb_ecap5_dsoc.cpp @@ -68,7 +68,7 @@ int main(int argc, char ** argv, char ** env) { /************************************************************/ tb->reset(); - tb->n_tick(65535); + tb->n_tick(200000); /************************************************************/ diff --git a/tests/benches/ecap5_dsoc/tb_ecap5_dsoc.sv b/tests/benches/ecap5_dsoc/tb_ecap5_dsoc.sv index c0209b0..12f2006 100644 --- a/tests/benches/ecap5_dsoc/tb_ecap5_dsoc.sv +++ b/tests/benches/ecap5_dsoc/tb_ecap5_dsoc.sv @@ -52,7 +52,16 @@ ecap5_dsoc dut ( .led1_o (led1_o), .button0_i (button0_i), - .button1_i (button1_i) + .button1_i (button1_i), + + .sram_ce_n (), + .sdram0_cs_n (), + .sdram0_cke (), + .sdram1_cs_n (), + .sdram1_cke (), + .ddr2_cs_n (), + .ddr2_cke (), + .emmc_rst_n () ); endmodule // tb_ecap5_dsoc