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

powered by: WebSVN 2.1.0

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