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

powered by: WebSVN 2.1.0

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