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-5.0/] [rtl/] [verilog/] [mor1kx_dmmu.v] - Blame information for rev 48

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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