OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [src_processor/] [mor1kx-3.1/] [rtl/] [verilog/] [mor1kx_dmmu.v] - Blame information for rev 38

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 38 alirezamon
/******************************************************************************
2
 This Source Code Form is subject to the terms of the
3
 Open Hardware Description License, v. 1.0. If a copy
4
 of the OHDL was not distributed with this file, You
5
 can obtain one at http://juliusbaxter.net/ohdl/ohdl.txt
6
 
7
 Description: Data MMU implementation
8
 
9
 Copyright (C) 2013 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
10
 
11
 ******************************************************************************/
12
 
13
`include "mor1kx-defines.v"
14
 
15
module mor1kx_dmmu
16
  #(
17
    parameter FEATURE_DMMU_HW_TLB_RELOAD = "NONE",
18
    parameter OPTION_OPERAND_WIDTH = 32,
19
    parameter OPTION_DMMU_SET_WIDTH = 6,
20
    parameter OPTION_DMMU_WAYS = 1
21
    )
22
   (
23
    input                                 clk,
24
    input                                 rst,
25
 
26
    input                                 enable_i,
27
    input [OPTION_OPERAND_WIDTH-1:0]       virt_addr_i,
28
    input [OPTION_OPERAND_WIDTH-1:0]       virt_addr_match_i,
29
    output [OPTION_OPERAND_WIDTH-1:0]      phys_addr_o,
30
    output                                cache_inhibit_o,
31
 
32
    input                                 op_store_i,
33
    input                                 op_load_i,
34
    input                                 supervisor_mode_i,
35
 
36
    output                                tlb_miss_o,
37
    output                                pagefault_o,
38
 
39
    output reg                            tlb_reload_req_o,
40
    output                                tlb_reload_busy_o,
41
    input                                 tlb_reload_ack_i,
42
    output reg [OPTION_OPERAND_WIDTH-1:0] tlb_reload_addr_o,
43
    input [OPTION_OPERAND_WIDTH-1:0]       tlb_reload_data_i,
44
    output                                tlb_reload_pagefault_o,
45
    input                                 tlb_reload_pagefault_clear_i,
46
 
47
    // SPR interface
48
    input [15:0]                           spr_bus_addr_i,
49
    input                                 spr_bus_we_i,
50
    input                                 spr_bus_stb_i,
51
    input [OPTION_OPERAND_WIDTH-1:0]       spr_bus_dat_i,
52
 
53
    output [OPTION_OPERAND_WIDTH-1:0]      spr_bus_dat_o,
54
    output                                spr_bus_ack_o
55
    );
56
 
57
   wire [OPTION_OPERAND_WIDTH-1:0]    dtlb_match_dout;
58
   wire [OPTION_DMMU_SET_WIDTH-1:0]   dtlb_match_addr;
59
   wire                               dtlb_match_we;
60
   wire [OPTION_OPERAND_WIDTH-1:0]    dtlb_match_din;
61
 
62
   wire [OPTION_OPERAND_WIDTH-1:0]    dtlb_match_huge_dout;
63
   wire [OPTION_DMMU_SET_WIDTH-1:0]   dtlb_match_huge_addr;
64
   wire                               dtlb_match_huge_we;
65
 
66
   wire [OPTION_OPERAND_WIDTH-1:0]    dtlb_trans_dout;
67
   wire [OPTION_DMMU_SET_WIDTH-1:0]   dtlb_trans_addr;
68
   wire                               dtlb_trans_we;
69
   wire [OPTION_OPERAND_WIDTH-1:0]    dtlb_trans_din;
70
 
71
   wire [OPTION_OPERAND_WIDTH-1:0]    dtlb_trans_huge_dout;
72
   wire [OPTION_DMMU_SET_WIDTH-1:0]   dtlb_trans_huge_addr;
73
   wire                               dtlb_trans_huge_we;
74
 
75
   reg                                dtlb_match_reload_we;
76
   reg [OPTION_OPERAND_WIDTH-1:0]     dtlb_match_reload_din;
77
 
78
   reg                                dtlb_trans_reload_we;
79
   reg [OPTION_OPERAND_WIDTH-1:0]     dtlb_trans_reload_din;
80
 
81
   wire                               dtlb_match_spr_cs;
82
   reg                                dtlb_match_spr_cs_r;
83
   wire                               dtlb_trans_spr_cs;
84
   reg                                dtlb_trans_spr_cs_r;
85
 
86
   wire                               dmmucr_spr_cs;
87
   reg                                dmmucr_spr_cs_r;
88
   reg [OPTION_OPERAND_WIDTH-1:0]     dmmucr;
89
 
90
   wire                               tlb_huge;
91
 
92
   wire                               tlb_miss;
93
   wire                               tlb_huge_miss;
94
 
95
   reg                                tlb_reload_pagefault;
96
   reg                                tlb_reload_huge;
97
 
98
   // ure: user read enable
99
   // uwe: user write enable
100
   // sre: supervisor read enable
101
   // swe: supervisor write enable
102
   wire                               ure;
103
   wire                               uwe;
104
   wire                               sre;
105
   wire                               swe;
106
 
107
   reg                                spr_bus_ack;
108
 
109
   always @(posedge clk `OR_ASYNC_RST)
110
     if (rst)
111
       spr_bus_ack <= 0;
112
     else if (spr_bus_stb_i & spr_bus_addr_i[15:11] == 5'd1)
113
       spr_bus_ack <= 1;
114
     else
115
       spr_bus_ack <= 0;
116
 
117
   assign spr_bus_ack_o = spr_bus_ack & spr_bus_stb_i &
118
                          spr_bus_addr_i[15:11] == 5'd1;
119
 
120
   assign cache_inhibit_o = tlb_huge ? dtlb_trans_huge_dout[1] :
121
                             dtlb_trans_dout[1];
122
   assign ure = tlb_huge ? dtlb_trans_huge_dout[6] : dtlb_trans_dout[6];
123
   assign uwe = tlb_huge ? dtlb_trans_huge_dout[7] : dtlb_trans_dout[7];
124
   assign sre = tlb_huge ? dtlb_trans_huge_dout[8] : dtlb_trans_dout[8];
125
   assign swe = tlb_huge ? dtlb_trans_huge_dout[9] : dtlb_trans_dout[9];
126
 
127
   assign pagefault_o = (supervisor_mode_i ?
128
                        !swe & op_store_i || !sre & op_load_i :
129
                        !uwe & op_store_i || !ure & op_load_i) &
130
                        !tlb_reload_busy_o;
131
 
132
   always @(posedge clk `OR_ASYNC_RST)
133
     if (rst) begin
134
        dtlb_match_spr_cs_r <= 0;
135
        dtlb_trans_spr_cs_r <= 0;
136
        dmmucr_spr_cs_r <= 0;
137
     end else begin
138
        dtlb_match_spr_cs_r <= dtlb_match_spr_cs;
139
        dtlb_trans_spr_cs_r <= dtlb_trans_spr_cs;
140
        dmmucr_spr_cs_r <= dmmucr_spr_cs;
141
     end
142
 
143
generate /* verilator lint_off WIDTH */
144
if (FEATURE_DMMU_HW_TLB_RELOAD == "ENABLED") begin
145
/* verilator lint_on WIDTH */
146
   assign dmmucr_spr_cs = spr_bus_stb_i &
147
                          spr_bus_addr_i == `OR1K_SPR_DMMUCR_ADDR;
148
 
149
   always @(posedge clk `OR_ASYNC_RST)
150
     if (rst)
151
       dmmucr <= 0;
152
     else if (dmmucr_spr_cs & spr_bus_we_i)
153
       dmmucr <= spr_bus_dat_i;
154
 
155
end else begin
156
   assign dmmucr_spr_cs = 0;
157
   always @(posedge clk)
158
     dmmucr <= 0;
159
end
160
endgenerate
161
 
162
   // TODO: optimize this
163
   assign dtlb_match_spr_cs = spr_bus_stb_i &
164
                              (spr_bus_addr_i >= `OR1K_SPR_DTLBW0MR0_ADDR) &
165
                              (spr_bus_addr_i < `OR1K_SPR_DTLBW0TR0_ADDR);
166
   assign dtlb_trans_spr_cs = spr_bus_stb_i &
167
                              (spr_bus_addr_i >= `OR1K_SPR_DTLBW0TR0_ADDR) &
168
                              (spr_bus_addr_i < `OR1K_SPR_DTLBW1MR0_ADDR);
169
 
170
   assign dtlb_match_addr = dtlb_match_spr_cs ?
171
                            spr_bus_addr_i[OPTION_DMMU_SET_WIDTH-1:0] :
172
                            virt_addr_i[13+(OPTION_DMMU_SET_WIDTH-1):13];
173
   assign dtlb_trans_addr = dtlb_trans_spr_cs ?
174
                            spr_bus_addr_i[OPTION_DMMU_SET_WIDTH-1:0] :
175
                            virt_addr_i[13+(OPTION_DMMU_SET_WIDTH-1):13];
176
 
177
   assign dtlb_match_we = dtlb_match_spr_cs & spr_bus_we_i |
178
                          dtlb_match_reload_we;
179
   assign dtlb_trans_we = dtlb_trans_spr_cs & spr_bus_we_i |
180
                          dtlb_trans_reload_we;
181
 
182
   assign dtlb_match_din = dtlb_match_reload_we ? dtlb_match_reload_din :
183
                           spr_bus_dat_i;
184
   assign dtlb_trans_din = dtlb_trans_reload_we ? dtlb_trans_reload_din :
185
                           spr_bus_dat_i;
186
 
187
   assign dtlb_match_huge_addr = virt_addr_i[24+(OPTION_DMMU_SET_WIDTH-1):24];
188
   assign dtlb_trans_huge_addr = virt_addr_i[24+(OPTION_DMMU_SET_WIDTH-1):24];
189
 
190
   assign dtlb_match_huge_we = dtlb_match_reload_we & tlb_reload_huge;
191
   assign dtlb_trans_huge_we = dtlb_trans_reload_we & tlb_reload_huge;
192
 
193
   assign spr_bus_dat_o = dtlb_match_spr_cs_r ? dtlb_match_dout :
194
                          dtlb_trans_spr_cs_r ? dtlb_trans_dout :
195
                          dmmucr_spr_cs_r ? dmmucr : 0;
196
 
197
   assign tlb_huge = &dtlb_match_huge_dout[1:0]; // huge & valid
198
 
199
   assign tlb_miss = dtlb_match_dout[31:13] != virt_addr_match_i[31:13] |
200
                     !dtlb_match_dout[0];  // valid bit
201
 
202
   assign tlb_huge_miss = dtlb_match_huge_dout[31:24] !=
203
                          virt_addr_match_i[31:24] | !dtlb_match_huge_dout[0];
204
 
205
   assign tlb_miss_o = (tlb_miss & !tlb_huge | tlb_huge_miss & tlb_huge) &
206
                       !tlb_reload_pagefault;
207
 
208
   assign phys_addr_o = tlb_huge ?
209
                        {dtlb_trans_huge_dout[31:24], virt_addr_match_i[23:0]} :
210
                        {dtlb_trans_dout[31:13], virt_addr_match_i[12:0]};
211
 
212
generate /* verilator lint_off WIDTH */
213
if (FEATURE_DMMU_HW_TLB_RELOAD == "ENABLED") begin
214
   /* verilator lint_on WIDTH */
215
 
216
   // Hardware TLB reload
217
   // Compliant with the suggestion outlined in this thread:
218
   // http://lists.openrisc.net/pipermail/openrisc/2013-July/001806.html
219
   //
220
   // PTE layout:
221
   // | 31 ... 13 | 12 |  11  |   10  | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
222
   // |    PPN    | Reserved  |PRESENT| L | X | W | U | D | A |WOM|WBC|CI |CC |
223
   //
224
   // Where X/W/U maps into SWE/SRE/UWE/URE like this:
225
   // X | W | U    SWE | SRE | UWE | URE
226
   // ----------   ---------------------
227
   // x | 0 | 0  =  0  |  1  |  0  |  0
228
   // x | 0 | 1  =  0  |  1  |  0  |  1
229
   // x | 1 | 0  =  1  |  1  |  0  |  0
230
   // x | 1 | 1  =  1  |  1  |  1  |  1
231
 
232
 
233
   localparam TLB_IDLE                  = 2'd0;
234
   localparam TLB_GET_PTE_POINTER       = 2'd1;
235
   localparam TLB_GET_PTE               = 2'd2;
236
   localparam TLB_READ                  = 2'd3;
237
 
238
   reg [1:0] tlb_reload_state = TLB_IDLE;
239
   wire      do_reload;
240
 
241
   assign do_reload = enable_i & tlb_miss_o & (dmmucr[31:10] != 0) &
242
                      (op_load_i | op_store_i);
243
 
244
   assign tlb_reload_busy_o = enable_i & (tlb_reload_state != TLB_IDLE) | do_reload;
245
 
246
   assign tlb_reload_pagefault_o = tlb_reload_pagefault &
247
                                    !tlb_reload_pagefault_clear_i;
248
 
249
   always @(posedge clk) begin
250
      if (tlb_reload_pagefault_clear_i)
251
        tlb_reload_pagefault <= 0;
252
      dtlb_trans_reload_we <= 0;
253
      dtlb_trans_reload_din <= 0;
254
      dtlb_match_reload_we <= 0;
255
      dtlb_match_reload_din <= 0;
256
 
257
      case (tlb_reload_state)
258
        TLB_IDLE: begin
259
           tlb_reload_huge <= 0;
260
           tlb_reload_req_o <= 0;
261
           if (do_reload) begin
262
              tlb_reload_req_o <= 1;
263
              tlb_reload_addr_o <= {dmmucr[31:10],
264
                                    virt_addr_match_i[31:24], 2'b00};
265
              tlb_reload_state <= TLB_GET_PTE_POINTER;
266
           end
267
        end
268
 
269
        //
270
        // Here we get the pointer to the PTE table, next is to fetch
271
        // the actual pte from the offset in the table.
272
        // The offset is calculated by:
273
        // ((virt_addr_match >> PAGE_BITS) & (PTE_CNT-1)) << 2
274
        // Where PAGE_BITS is 13 (8 kb page) and PTE_CNT is 2048
275
        // (number of PTEs in the PTE table)
276
        //
277
        TLB_GET_PTE_POINTER: begin
278
           tlb_reload_huge <= 0;
279
           if (tlb_reload_ack_i) begin
280
              if (tlb_reload_data_i[31:13] == 0) begin
281
                 tlb_reload_pagefault <= 1;
282
                 tlb_reload_req_o <= 0;
283
                 tlb_reload_state <= TLB_IDLE;
284
              end else if (tlb_reload_data_i[9]) begin
285
                 tlb_reload_huge <= 1;
286
                 tlb_reload_req_o <= 0;
287
                 tlb_reload_state <= TLB_GET_PTE;
288
              end else begin
289
                 tlb_reload_addr_o <= {tlb_reload_data_i[31:13],
290
                                       virt_addr_match_i[23:13], 2'b00};
291
                 tlb_reload_state <= TLB_GET_PTE;
292
              end
293
           end
294
        end
295
 
296
        //
297
        // Here we get the actual PTE, left to do is to translate the
298
        // PTE data into our translate and match registers.
299
        //
300
        TLB_GET_PTE: begin
301
           if (tlb_reload_ack_i) begin
302
              tlb_reload_req_o <= 0;
303
              // Check PRESENT bit
304
              if (!tlb_reload_data_i[10]) begin
305
                 tlb_reload_pagefault <= 1;
306
                 tlb_reload_state <= TLB_IDLE;
307
              end else begin
308
                 // Translate register generation.
309
                 // PPN
310
                 dtlb_trans_reload_din[31:13] <= tlb_reload_data_i[31:13];
311
                 // SWE = W
312
                 dtlb_trans_reload_din[9] <= tlb_reload_data_i[7];
313
                 // SRE = 1
314
                 dtlb_trans_reload_din[8] <= 1'b1;
315
                 // UWE = W & U
316
                 dtlb_trans_reload_din[7] <= tlb_reload_data_i[7] &
317
                                              tlb_reload_data_i[6];
318
                 // URE = U
319
                 dtlb_trans_reload_din[6] <= tlb_reload_data_i[6];
320
                 // Dirty, Accessed, Weakly-Ordered-Memory, Writeback cache,
321
                 // Cache inhibit, Cache coherent
322
                 dtlb_trans_reload_din[5:0] <= tlb_reload_data_i[5:0];
323
                 dtlb_trans_reload_we <= 1;
324
 
325
                 // Match register generation.
326
                 // VPN
327
                 dtlb_match_reload_din[31:13] <= virt_addr_match_i[31:13];
328
                 // Valid
329
                 dtlb_match_reload_din[0] <= 1;
330
                 dtlb_match_reload_we <= 1;
331
 
332
                 tlb_reload_state <= TLB_READ;
333
              end
334
           end
335
        end
336
 
337
        // Let the just written values propagate out on the read ports
338
        TLB_READ: begin
339
           tlb_reload_state <= TLB_IDLE;
340
        end
341
 
342
        default:
343
          tlb_reload_state <= TLB_IDLE;
344
      endcase
345
 
346
      // Abort if enable deasserts in the middle of a reload
347
      if (!enable_i | (dmmucr[31:10] == 0))
348
        tlb_reload_state <= TLB_IDLE;
349
 
350
   end
351
end else begin // if (FEATURE_DMMU_HW_TLB_RELOAD == "ENABLED")
352
   assign tlb_reload_pagefault_o = 0;
353
   assign tlb_reload_busy_o = 0;
354
   always @(posedge clk) begin
355
      tlb_reload_req_o <= 0;
356
      tlb_reload_addr_o <= 0;
357
      tlb_reload_pagefault <= 0;
358
      dtlb_trans_reload_we <= 0;
359
      dtlb_trans_reload_din <= 0;
360
      dtlb_match_reload_we <= 0;
361
      dtlb_match_reload_din <= 0;
362
   end
363
end
364
endgenerate
365
 
366
   // DTLB match registers
367
   mor1kx_true_dpram_sclk
368
     #(
369
       .ADDR_WIDTH(OPTION_DMMU_SET_WIDTH),
370
       .DATA_WIDTH(OPTION_OPERAND_WIDTH)
371
       )
372
   dtlb_match_regs
373
     (
374
      // Outputs
375
      .dout_a                           (dtlb_match_dout),
376
      .dout_b                           (dtlb_match_huge_dout),
377
      // Inputs
378
      .clk                              (clk),
379
      .addr_a                           (dtlb_match_addr),
380
      .we_a                             (dtlb_match_we),
381
      .din_a                            (dtlb_match_din),
382
      .addr_b                           (dtlb_match_huge_addr),
383
      .we_b                             (dtlb_match_huge_we),
384
      .din_b                            (dtlb_match_reload_din)
385
      );
386
 
387
 
388
   // DTLB translate registers
389
   mor1kx_true_dpram_sclk
390
     #(
391
       .ADDR_WIDTH(OPTION_DMMU_SET_WIDTH),
392
       .DATA_WIDTH(OPTION_OPERAND_WIDTH)
393
       )
394
   dtlb_translate_regs
395
     (
396
      // Outputs
397
      .dout_a                           (dtlb_trans_dout),
398
      .dout_b                           (dtlb_trans_huge_dout),
399
      // Inputs
400
      .clk                              (clk),
401
      .addr_a                           (dtlb_trans_addr),
402
      .we_a                             (dtlb_trans_we),
403
      .din_a                            (dtlb_trans_din),
404
      .addr_b                           (dtlb_trans_huge_addr),
405
      .we_b                             (dtlb_trans_huge_we),
406
      .din_b                            (dtlb_trans_reload_din)
407
      );
408
 
409
endmodule // mor1kx_dmmu

powered by: WebSVN 2.1.0

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