OpenCores
URL https://opencores.org/ocsvn/yifive/yifive/trunk

Subversion Repositories yifive

[/] [yifive/] [trunk/] [caravel_yifive/] [verilog/] [rtl/] [syntacore/] [scr1/] [src/] [top/] [scr1_timer.sv] - Blame information for rev 21

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 11 dinesha
/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details
2
/// @file       
3
/// @brief      Memory-mapped Timer
4
///
5
 
6
`include "scr1_arch_description.svh"
7
`include "scr1_memif.svh"
8
 
9
module scr1_timer (
10
    // Common
11
    input   logic                                   rst_n,
12
    input   logic                                   clk,
13
    input   logic                                   rtc_clk,
14
 
15
    // Memory interface
16
    input   logic                                   dmem_req,
17 21 dinesha
    input   logic                                   dmem_cmd,
18
    input   logic [1:0]                             dmem_width,
19 11 dinesha
    input   logic [`SCR1_DMEM_AWIDTH-1:0]           dmem_addr,
20
    input   logic [`SCR1_DMEM_DWIDTH-1:0]           dmem_wdata,
21
    output  logic                                   dmem_req_ack,
22
    output  logic [`SCR1_DMEM_DWIDTH-1:0]           dmem_rdata,
23 21 dinesha
    output  logic [1:0]                             dmem_resp,
24 11 dinesha
 
25
    // Timer interface
26
    output  logic [63:0]                            timer_val,
27
    output  logic                                   timer_irq
28
);
29
 
30
//-------------------------------------------------------------------------------
31
// Local parameters declaration
32
//-------------------------------------------------------------------------------
33
localparam int unsigned SCR1_TIMER_ADDR_WIDTH                               = 5;
34
localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_CONTROL             = 5'h0;
35
localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_DIVIDER             = 5'h4;
36
localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_MTIMELO             = 5'h8;
37
localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_MTIMEHI             = 5'hC;
38
localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_MTIMECMPLO          = 5'h10;
39
localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_MTIMECMPHI          = 5'h14;
40
 
41
localparam int unsigned SCR1_TIMER_CONTROL_EN_OFFSET                        = 0;
42
localparam int unsigned SCR1_TIMER_CONTROL_CLKSRC_OFFSET                    = 1;
43
localparam int unsigned SCR1_TIMER_DIVIDER_WIDTH                            = 10;
44
 
45
//-------------------------------------------------------------------------------
46
// Local signals declaration
47
//-------------------------------------------------------------------------------
48
logic [63:0]                                        mtime_reg;
49
logic [63:0]                                        mtime_new;
50
logic [63:0]                                        mtimecmp_reg;
51
logic [63:0]                                        mtimecmp_new;
52
logic                                               timer_en;
53
logic                                               timer_clksrc_rtc;
54
logic [SCR1_TIMER_DIVIDER_WIDTH-1:0]                timer_div;
55
 
56
logic                                               control_up;
57
logic                                               divider_up;
58
logic                                               mtimelo_up;
59
logic                                               mtimehi_up;
60
logic                                               mtimecmplo_up;
61
logic                                               mtimecmphi_up;
62
 
63
logic                                               dmem_req_valid;
64
 
65
logic [3:0]                                         rtc_sync;
66
logic                                               rtc_ext_pulse;
67
logic [SCR1_TIMER_DIVIDER_WIDTH-1:0]                timeclk_cnt;
68
logic                                               timeclk_cnt_en;
69
logic                                               time_posedge;
70
logic                                               time_cmp_flag;
71
 
72
//-------------------------------------------------------------------------------
73
// Registers
74
//-------------------------------------------------------------------------------
75
 
76
// CONTROL
77
always_ff @(posedge clk, negedge rst_n) begin
78
    if (~rst_n) begin
79
        timer_en            <= 1'b1;
80
        timer_clksrc_rtc    <= 1'b0;
81
    end else begin
82
        if (control_up) begin
83
            timer_en            <= dmem_wdata[SCR1_TIMER_CONTROL_EN_OFFSET];
84
            timer_clksrc_rtc    <= dmem_wdata[SCR1_TIMER_CONTROL_CLKSRC_OFFSET];
85
        end
86
    end
87
end
88
 
89
// DIVIDER
90
always_ff @(posedge clk, negedge rst_n) begin
91
    if (~rst_n) begin
92
        timer_div   <= '0;
93
    end else begin
94
        if (divider_up) begin
95
            timer_div   <= dmem_wdata[SCR1_TIMER_DIVIDER_WIDTH-1:0];
96
        end
97
    end
98
end
99
 
100
// MTIME
101
assign time_posedge = (timeclk_cnt_en & (timeclk_cnt == 0));
102
 
103
always_comb begin
104
    mtime_new   = mtime_reg;
105
    if (time_posedge) begin
106
        mtime_new   = mtime_reg + 1'b1;
107
    end
108
    if (mtimelo_up) begin
109
        mtime_new[31:0]     = dmem_wdata;
110
    end
111
    if (mtimehi_up) begin
112
        mtime_new[63:32]    = dmem_wdata;
113
    end
114
end
115
 
116
always_ff @(posedge clk, negedge rst_n) begin
117
    if (~rst_n) begin
118
        mtime_reg   <= '0;
119
    end else begin
120
        if (time_posedge | mtimelo_up | mtimehi_up) begin
121
            mtime_reg   <= mtime_new;
122
        end
123
    end
124
end
125
 
126
// MTIMECMP
127
always_comb begin
128
    mtimecmp_new    = mtimecmp_reg;
129
    if (mtimecmplo_up) begin
130
        mtimecmp_new[31:0]  = dmem_wdata;
131
    end
132
    if (mtimecmphi_up) begin
133
        mtimecmp_new[63:32] = dmem_wdata;
134
    end
135
end
136
 
137
always_ff @(posedge clk, negedge rst_n) begin
138
    if (~rst_n) begin
139
        mtimecmp_reg    <= '0;
140
    end else begin
141
        if (mtimecmplo_up | mtimecmphi_up) begin
142
            mtimecmp_reg    <= mtimecmp_new;
143
        end
144
    end
145
end
146
 
147
//-------------------------------------------------------------------------------
148
// Interrupt pending
149
//-------------------------------------------------------------------------------
150
assign time_cmp_flag = (mtime_reg >= ((mtimecmplo_up | mtimecmphi_up) ? mtimecmp_new : mtimecmp_reg));
151
 
152
always_ff @(posedge clk, negedge rst_n) begin
153
    if (~rst_n) begin
154
        timer_irq   <= 1'b0;
155
    end else begin
156
        if (~timer_irq) begin
157
            timer_irq   <= time_cmp_flag;
158
        end else begin // 1'b1
159
            if (mtimecmplo_up | mtimecmphi_up) begin
160
                timer_irq   <= time_cmp_flag;
161
            end
162
        end
163
    end
164
end
165
 
166
//-------------------------------------------------------------------------------
167
// Timer divider
168
//-------------------------------------------------------------------------------
169
assign timeclk_cnt_en   = (~timer_clksrc_rtc ? 1'b1 : rtc_ext_pulse) & timer_en;
170
 
171
always_ff @(negedge rst_n, posedge clk) begin
172
    if (~rst_n) begin
173
        timeclk_cnt <= '0;
174
    end else begin
175
        case (1'b1)
176
            divider_up      : timeclk_cnt   <= dmem_wdata[SCR1_TIMER_DIVIDER_WIDTH-1:0];
177
            time_posedge    : timeclk_cnt   <= timer_div;
178
            timeclk_cnt_en  : timeclk_cnt   <= timeclk_cnt - 1'b1;
179
            default         : begin end
180
        endcase
181
    end
182
end
183
 
184
//-------------------------------------------------------------------------------
185
// RTC synchronization
186
//-------------------------------------------------------------------------------
187
assign rtc_ext_pulse    = rtc_sync[3] ^ rtc_sync[2];
188
 
189
always_ff @(negedge rst_n, posedge rtc_clk) begin
190
    if (~rst_n) begin
191
        rtc_sync[0] <= 1'b0;
192
    end else begin
193
        if (timer_clksrc_rtc) begin
194
            rtc_sync[0] <= ~rtc_sync[0];
195
        end
196
    end
197
end
198
 
199
always_ff @(negedge rst_n, posedge clk) begin
200
    if (~rst_n) begin
201
        rtc_sync[3:1]   <= '0;
202
    end else begin
203
        if (timer_clksrc_rtc) begin
204
            rtc_sync[3:1]   <= rtc_sync[2:0];
205
        end
206
    end
207
end
208
 
209
//-------------------------------------------------------------------------------
210
// Memory interface
211
//-------------------------------------------------------------------------------
212
assign dmem_req_valid   =   (dmem_width == SCR1_MEM_WIDTH_WORD) & (~|dmem_addr[1:0]) &
213
                            (dmem_addr[SCR1_TIMER_ADDR_WIDTH-1:2] <= SCR1_TIMER_MTIMECMPHI[SCR1_TIMER_ADDR_WIDTH-1:2]);
214
 
215
assign dmem_req_ack     = 1'b1;
216
 
217
always_ff @(negedge rst_n, posedge clk) begin
218
    if (~rst_n) begin
219
        dmem_resp   <= SCR1_MEM_RESP_NOTRDY;
220
        dmem_rdata  <= '0;
221
    end else begin
222
        if (dmem_req) begin
223
            if (dmem_req_valid) begin
224
                dmem_resp   <= SCR1_MEM_RESP_RDY_OK;
225
                if (dmem_cmd == SCR1_MEM_CMD_RD) begin
226
                    case (dmem_addr[SCR1_TIMER_ADDR_WIDTH-1:0])
227
                        SCR1_TIMER_CONTROL      : dmem_rdata    <= `SCR1_DMEM_DWIDTH'({timer_clksrc_rtc, timer_en});
228
                        SCR1_TIMER_DIVIDER      : dmem_rdata    <= `SCR1_DMEM_DWIDTH'(timer_div);
229
                        SCR1_TIMER_MTIMELO      : dmem_rdata    <= mtime_reg[31:0];
230
                        SCR1_TIMER_MTIMEHI      : dmem_rdata    <= mtime_reg[63:32];
231
                        SCR1_TIMER_MTIMECMPLO   : dmem_rdata    <= mtimecmp_reg[31:0];
232
                        SCR1_TIMER_MTIMECMPHI   : dmem_rdata    <= mtimecmp_reg[63:32];
233
                        default                 : begin end
234
                    endcase
235
                end
236
            end else begin
237
                dmem_resp   <= SCR1_MEM_RESP_RDY_ER;
238
            end
239
        end else begin
240
            dmem_resp   <= SCR1_MEM_RESP_NOTRDY;
241
            dmem_rdata  <= '0;
242
        end
243
    end
244
end
245
 
246
always_comb begin
247
    control_up      = 1'b0;
248
    divider_up      = 1'b0;
249
    mtimelo_up      = 1'b0;
250
    mtimehi_up      = 1'b0;
251
    mtimecmplo_up   = 1'b0;
252
    mtimecmphi_up   = 1'b0;
253
    if (dmem_req & dmem_req_valid & (dmem_cmd == SCR1_MEM_CMD_WR)) begin
254
        case (dmem_addr[SCR1_TIMER_ADDR_WIDTH-1:0])
255
            SCR1_TIMER_CONTROL      : control_up    = 1'b1;
256
            SCR1_TIMER_DIVIDER      : divider_up    = 1'b1;
257
            SCR1_TIMER_MTIMELO      : mtimelo_up    = 1'b1;
258
            SCR1_TIMER_MTIMEHI      : mtimehi_up    = 1'b1;
259
            SCR1_TIMER_MTIMECMPLO   : mtimecmplo_up = 1'b1;
260
            SCR1_TIMER_MTIMECMPHI   : mtimecmphi_up = 1'b1;
261
            default                 : begin end
262
        endcase
263
    end
264
end
265
 
266
//-------------------------------------------------------------------------------
267
// Timer interface
268
//-------------------------------------------------------------------------------
269
assign timer_val    = mtime_reg;
270
 
271 21 dinesha
endmodule : scr1_timer

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.