diff --git a/rtl/soc/hydrogensoc/HydrogenSoC.v b/rtl/soc/hydrogensoc/HydrogenSoC.v index cf93e65e..b501dfad 100644 --- a/rtl/soc/hydrogensoc/HydrogenSoC.v +++ b/rtl/soc/hydrogensoc/HydrogenSoC.v @@ -108,7 +108,7 @@ module HydrogenSoC( `ifdef EN_EXCEPT , .irq_i (1'b0), - .timer_int_i (1'b0) + .timer_int_i (timer_int_o) `endif // EN_EXCEPT ); @@ -182,7 +182,7 @@ module HydrogenSoC( // ******************** Crossbar ******************** - Crossbar5_wb #( + Crossbar6_wb #( .DATA_WIDTH (32), .ADDR_WIDTH (32), .DEVICE0_ADDR (`BOOTROM_ADDR), @@ -194,7 +194,9 @@ module HydrogenSoC( .DEVICE3_ADDR (`GPIO_ADDR), .DEVICE3_MASK (`size_to_mask32(`GPIO_SIZE)), .DEVICE4_ADDR (`SPI_ADDR), - .DEVICE4_MASK (`size_to_mask32(`SPI_SIZE)) + .DEVICE4_MASK (`size_to_mask32(`SPI_SIZE)), + .DEVICE5_ADDR (`TIMER_ADDR), + .DEVICE5_MASK (`size_to_mask32(`TIMER_SIZE)) ) xbar ( .wbs_adr_i (arb_wb_adr_o), .wbs_dat_i (arb_wb_dat_o), @@ -256,7 +258,17 @@ module HydrogenSoC( .wbm4_cyc_o (spi_wb_cyc_i), .wbm4_stb_o (spi_wb_stb_i), .wbm4_ack_i (spi_wb_ack_o), - .wbm4_err_i (1'b0) + .wbm4_err_i (1'b0), + + .wbm5_adr_o (timer_wb_adr_i), + .wbm5_dat_i (timer_wb_dat_o), + .wbm5_dat_o (timer_wb_dat_i), + .wbm5_we_o (timer_wb_we_i), + .wbm5_sel_o (timer_wb_sel_i), + .wbm5_cyc_o (timer_wb_cyc_i), + .wbm5_stb_o (timer_wb_stb_i), + .wbm5_ack_i (timer_wb_ack_o), + .wbm5_err_i (1'b0) ); @@ -410,6 +422,34 @@ module HydrogenSoC( .miso_i (spi_miso_i), .mosi_o (spi_mosi_o), .cs_o (spi_cs_o) + ); + + // ******************* TIMER ******************* + /* verilator lint_off UNUSEDSIGNAL */ + wire [31:0] timer_wb_adr_i; + /* verilator lint_on UNUSEDSIGNAL */ + wire [31:0] timer_wb_dat_o; + wire [31:0] timer_wb_dat_i; + wire timer_wb_we_i; + wire [3:0] timer_wb_sel_i; + wire timer_wb_cyc_i; + wire timer_wb_stb_i; + wire timer_wb_ack_o; + wire timer_int_o; + + Timer_wb timer ( + .wb_clk_i (wb_clk_i), + .wb_rst_i (wb_rst_i), + + .wb_adr_i (timer_wb_adr_i[3:2]), + .wb_dat_o (timer_wb_dat_o), + .wb_dat_i (timer_wb_dat_i), + .wb_we_i (timer_wb_we_i), + .wb_sel_i (timer_wb_sel_i), + .wb_stb_i (timer_wb_stb_i & timer_wb_cyc_i), + .wb_ack_o (timer_wb_ack_o), + + .int_o (timer_int_o) ); diff --git a/rtl/soc/hydrogensoc/HydrogenSoC_Config.vh b/rtl/soc/hydrogensoc/HydrogenSoC_Config.vh index cc808815..2a05745f 100644 --- a/rtl/soc/hydrogensoc/HydrogenSoC_Config.vh +++ b/rtl/soc/hydrogensoc/HydrogenSoC_Config.vh @@ -87,5 +87,9 @@ `define SPI_ADDR 32'h4000_3000 `define SPI_SIZE 32 // 32 bytes (8 words) +// TIMER +`define TIMER_ADDR 32'h4000_4000 +`define TIMER_SIZE 16 // 32 bytes (4 words) + `endif // __HYDROGENSOC_CONFIG_VH__ diff --git a/rtl/uncore/timer/README.md b/rtl/uncore/timer/README.md new file mode 100644 index 00000000..26a4a7f5 --- /dev/null +++ b/rtl/uncore/timer/README.md @@ -0,0 +1,21 @@ +# Wishbone Timer +Timer IP with Wishbone B-4 Interface. + +## Register MAP + +| **Offset** | **Name** | **Description** +|------------|------------|----------------------------------- +| 0x00 | MTIME | Machine mode time register [31:0] +| 0x04 | MTIME_H | Machine mode time register [63:32] +| 0x08 | MTIMECMP | Machine mode time compare register [31:0] +| 0x0c | MTIMECMP_H | Machine mode time compare register [63:32] + +> Timer interrupt (`mti`) is generated whenever `mtimecmp` >= `mtime`. The `mti` interrupt does not repeat, so the ISR needs to reset the timer compare register (`mtimecmp`) at each timeout. + +## Logic Utilization +Yosys was used to analyze Logic utilization for Xilinx 7 series FPGAs + +| **Design** | **LUTS** | +|---------------|----------| +| SPI_core | 322 | +| SPI_wb | 530 | diff --git a/rtl/uncore/timer/Timer_wb.v b/rtl/uncore/timer/Timer_wb.v new file mode 100644 index 00000000..d3cad72b --- /dev/null +++ b/rtl/uncore/timer/Timer_wb.v @@ -0,0 +1,104 @@ +//////////////////////////////////////////////////////////////////// +// File : GPIO.v +// Author : Saurabh Singh (saurabh.s99100@gmail.com) +// Description : GPIO IP with Wishbone B-4 Interface. +// +// MIT License +// +// Copyright (c) 2021 Saurabh Singh +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//////////////////////////////////////////////////////////////////// + +`default_nettype none +`include "Utils.vh" + +module Timer_wb( + // Wishbone Interface + input wire wb_clk_i, + input wire wb_rst_i, + + input wire [3:2] wb_adr_i, + output reg [31:0] wb_dat_o, + input wire [31:0] wb_dat_i, + input wire wb_we_i, + input wire [3:0] wb_sel_i, + input wire wb_stb_i, + output reg wb_ack_o, + + output wire int_o +); + +// Set Ack_o +always @(posedge wb_clk_i) begin + if (wb_rst_i) + wb_ack_o <= 1'b0; + else + wb_ack_o <= wb_stb_i & !wb_ack_o; +end + +wire [3:0] we = {4{wb_we_i & wb_stb_i}} & wb_sel_i; + + +reg [63:0] mtime; +reg [63:0] mtimecmp; + +assign int_o = mtime >= mtimecmp; + +// Writes +always @(posedge wb_clk_i) begin + if(wb_rst_i) begin + mtime <= 'd0; + mtimecmp <= 'd0; + end + else begin + case(wb_adr_i) + 2'b10: begin // mtimecmp + if (we[0]) mtimecmp[7:0] <= wb_dat_i[7:0]; + if (we[1]) mtimecmp[15:8] <= wb_dat_i[15:8]; + if (we[2]) mtimecmp[23:16] <= wb_dat_i[23:16]; + if (we[3]) mtimecmp[31:24] <= wb_dat_i[31:24]; + end + 2'b11: begin // mtimecmp_h + if (we[0]) mtimecmp[39:32] <= wb_dat_i[7:0]; + if (we[1]) mtimecmp[47:40] <= wb_dat_i[15:8]; + if (we[2]) mtimecmp[55:48] <= wb_dat_i[23:16]; + if (we[3]) mtimecmp[63:56] <= wb_dat_i[31:24]; + end + default: begin // INC (NOT IMPLEMENTED) + end + endcase + mtime <= mtime + 'd1; + end +end + + +// READS +always @(*) /* COMBINATORIAL */ begin + case(wb_adr_i) + 2'b00: /* mtime */ wb_dat_o = mtime[31:0]; + 2'b01: /* mtime_h */ wb_dat_o = mtime[63:32]; + 2'b10: /* mtimecmp */ wb_dat_o = mtimecmp[31:0]; + 2'b11: /* mtimecmp_h */ wb_dat_o = mtimecmp[63:32]; + default: + wb_dat_o = 'dx; + endcase +end + +endmodule