pmu_ahb.sv 28.2 KB
Newer Older
Guillem's avatar
Guillem committed
1
2
3
4
5
6
7
8
9
//-----------------------------------------------------
// ProjectName: LEON3_kc705_pmu
// Function   : Integrate PMU and AHB interface
// Description: AHB interface implementation of the  PMU. 
//              
//              This module is responsible managing reads and writes from and
//              AHB master and interface with pmu_ahb module.
//
// Coder      : G.Cabo
Guillem's avatar
Guillem committed
10
11
// References : AMBA 3 AHB-lite  specifications 
//              ARM IHI 0033A  
12
13
14
// Notes      : Any write to a control registers takes 2 clock cycles to
//              take effect since it propagates from the wrapper to the
//              internal regs of the PMU
Guillem's avatar
Guillem committed
15
16
17
18
19
20
21
22
23
24
25

`default_nettype none
`timescale 1 ns / 1 ps

`ifndef SYNT
    `ifdef FORMAL 
        `define ASSERTIONS
    `endif
`endif
	module pmu_ahb #
	(
26
27
        parameter integer haddr = 0,                                                  
        parameter integer hmask  = 0,                                           
Guillem's avatar
Guillem committed
28
29
		// Width of registers data bus
        parameter integer REG_WIDTH = 32,
30
31
32
        // Number of counters
        parameter integer PMU_COUNTERS = 24,
        // Number of SoC events
GuillemCabo's avatar
GuillemCabo committed
33
	    parameter integer N_SOC_EV = 128,
34
	// Total amount of registers (use ahb_pmu_mem_map.ods) 
GuillemCabo's avatar
GuillemCabo committed
35
        parameter integer N_REGS = 55, 
GuillemCabo's avatar
GuillemCabo committed
36
        // Fault tolerance mechanisms (FT==0 -> FT disabled)
37
        parameter integer FT  = 0,                                           
38
39
	// -- Local parameters
		//haddr width
Guillem's avatar
Guillem committed
40
        localparam integer HADDR_WIDTH = 32,
41
		//hdata width
Guillem's avatar
Guillem committed
42
        localparam integer HDATA_WIDTH = 32,
43
		// Cores connected to MCCU
GuillemCabo's avatar
GuillemCabo committed
44
        parameter MCCU_N_CORES = 6,
45
46
		// Number of configuration registers
        localparam PMU_CFG = 1
Guillem's avatar
Guillem committed
47
48
49
50
51
52
53
	)
	(
         input wire rstn_i,
         input wire clk_i,
    //  -- AHB bus slave interface                                              
        // slave select
        input wire         hsel_i,                               
Guillem's avatar
Guillem committed
54
55
        // previous transfer done 
        input wire         hreadyi_i,
Guillem's avatar
Guillem committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
        // address bus 
        input wire [HADDR_WIDTH-1:0]  haddr_i,
        // read/write 
        input wire         hwrite_i,
        // transfer type
        input wire [1:0]   htrans_i,
        // transfer size
        input wire [2:0]   hsize_i,
        // burst type
        input wire [2:0]   hburst_i,
        // write data bus
        input wire [HDATA_WIDTH-1:0]  hwdata_i,
        // prtection control
        input wire [3:0]   hprot_i,
        // locked access 
        input wire         hmastlock_i,
        // trasfer done 
        output wire        hreadyo_o,
        // response type
        output wire [1:0]  hresp_o,
        // read data bus
Guillem's avatar
Guillem committed
77
78
        output wire [HDATA_WIDTH-1:0] hrdata_o,
    // -- PMU specific signales
79
        input wire [N_SOC_EV-1:0] events_i,
Guillem's avatar
Guillem committed
80
81
82
83
84
85
86
        //interruption rises when one of the counters overflows
        output wire intr_overflow_o,
        //interruption rises when overal events quota is exceeded 
        output wire intr_quota_o,
        // MCCU interruption for exceeded quota. One signal per core
        output wire [MCCU_N_CORES-1:0] intr_MCCU_o,
        // RDC (Request Duration Counter) interruption for exceeded quota
GuillemCabo's avatar
GuillemCabo committed
87
        output wire intr_RDC_o,
88
89
        // FT (Fault tolerance) interrupt, error detected and recovered
        output wire intr_FT1_o,
GuillemCabo's avatar
GuillemCabo committed
90
        // FT (Fault tolerance) interrupt, error detected but not recoverable
91
        output wire intr_FT2_o
Guillem's avatar
Guillem committed
92
    );
Guillem's avatar
Guillem committed
93
94
95
96
97
98
99
100
101
102
103
    //----------------------------------------------
    // VIVADO: list of debug signals for ILA 
    //----------------------------------------------   
    `ifdef ILA_DEBUG_PMU_AHB                                              
    (* MARK_DEBUG = "TRUE" *) wire debug_hsel_i     ;        
    (* MARK_DEBUG = "TRUE" *) wire [HADDR_WIDTH-1:0] debug_haddr_i     ;       
    (* MARK_DEBUG = "TRUE" *) wire debug_hwrite_i    ;       
    (* MARK_DEBUG = "TRUE" *) wire [1:0] debug_htrans_i    ;       
    (* MARK_DEBUG = "TRUE" *) wire [2:0] debug_hsize_i     ;       
    (* MARK_DEBUG = "TRUE" *) wire [2:0] debug_hburst_i    ;       
    (* MARK_DEBUG = "TRUE" *) wire [HDATA_WIDTH-1:0] debug_hwdata_i    ;       
Guillem's avatar
Guillem committed
104
    (* MARK_DEBUG = "TRUE" *) wire [3:0] debug_hprot_i     ;       
Guillem's avatar
Guillem committed
105
106
107
108
109
    (* MARK_DEBUG = "TRUE" *) wire debug_hreadyi_i   ;       
    (* MARK_DEBUG = "TRUE" *) wire debug_hmastlock_i ;       
    (* MARK_DEBUG = "TRUE" *) wire debug_hreadyo_o   ;       
    (* MARK_DEBUG = "TRUE" *) wire [1:0] debug_hresp_o     ;       
    (* MARK_DEBUG = "TRUE" *) wire [HDATA_WIDTH-1:0] debug_hrdata_o    ;       
110
    (* MARK_DEBUG = "TRUE" *) wire [N_SOC_EV-1:0] debug_events_i   ;        
Guillem's avatar
Guillem committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    (* MARK_DEBUG = "TRUE" *) wire debug_intr_overflow_o;    
    (* MARK_DEBUG = "TRUE" *) wire debug_intr_quota_o;       
    (* MARK_DEBUG = "TRUE" *) wire [MCCU_N_CORES-1:0] debug_intr_MCCU_o;        
    (* MARK_DEBUG = "TRUE" *) wire debug_intr_RDC_o;         
    assign debug_hsel_i   = hsel_i;                                                      
    assign debug_haddr_i = haddr_i;                          
    assign debug_hwrite_i = hwrite_i;                        
    assign debug_htrans_i = htrans_i;                        
    assign debug_hsize_i = hsize_i;                          
    assign debug_hburst_i = hburst_i;                        
    assign debug_hwdata_i = hwdata_i;                        
    assign debug_hprot_i = hprot_i;                          
    assign debug_hreadyi_i = hreadyi_i;                      
    assign debug_hmastlock_i = hmastlock_i;                  
    assign debug_hreadyo_o = hreadyo_o;                      
    assign debug_hresp_o = hresp_o;                          
    assign debug_hrdata_o = hrdata_o;                        
    assign debug_events_i = events_i;                        
    assign debug_intr_overflow_o = intr_overflow_o;          
    assign debug_intr_quota_o = intr_quota_o;                
    assign debug_intr_MCCU_o = intr_MCCU_o;                  
    assign debug_intr_RDC_o = intr_RDC_o ;  
    `endif                                                                                                              
Guillem's avatar
Guillem committed
134
135
136
//----------------------------------------------
//------------- Local parameters
//----------------------------------------------
Guillem's avatar
Guillem committed
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// ** Types of bursts (hburst_i) ** 
    //Single burst
    localparam SINGLE = 3'b00;
    //Incrementing burst of undefined length
    localparam INCR = 3'b01;
    //4-beat wrapping burst
    localparam WRAP4 = 3'b010;
    //4-beat incrementing burst
    localparam INCR4 = 3'b011;
    //8-beat wrapping burst
    localparam WRAP8 = 3'b100;
    //8-beat incrementing burst
    localparam INCR8 = 3'b101;
    //16-beat wrapping burs
    localparam WRAP16 = 3'b110;
    //16-beat incrementing burst
    localparam INCR16 = 3'b111;

// ** Type of transfers (htrans_i) **
    localparam TRANS_IDLE = 2'b00;
    localparam TRANS_BUSY = 2'b01;
    localparam TRANS_NONSEQUENTIAL = 2'b10;
    localparam TRANS_SEQUENTIAL = 2'b11;

// ** Type of Ready outputs (hreadyo_o) **
    //PENDING. Transfer has to be extended one cycle more
    //COMPLETE. Transfer has finish
localparam READY_PENDING = 1'b0;
localparam READY_COMPLETE = 1'b1;

// ** Type of Response outputs (hresp_o)**
    //OKAY. Transfer has finish or has to be extended
    //ERROR. Transfer is not valid 
localparam READYO_OKAY = 1'b0;
localparam READYO_ERROR = 1'b1;

// ** Transfer status **
// **{{hresp_o},{hready_o}} 
localparam TRANSFER_PENDING = 2'b00;
localparam TRANSFER_SUCCESS_COMPLETE = 2'b01;
localparam TRANSFER_ERROR_RESP_1CYCLE = 2'b10;
localparam TRANSFER_ERROR_RESP_2CYCLE = 2'b11;

//----------------------------------------------
//------------- Data structures
//----------------------------------------------
var struct packed{
GuillemCabo's avatar
GuillemCabo committed
184
185
    logic select_D, select_Q;
    logic write_D, write_Q;
Guillem's avatar
Guillem committed
186
//    logic master_ready;
GuillemCabo's avatar
GuillemCabo committed
187
    logic [HADDR_WIDTH-1:0] master_addr_D, master_addr_Q;
Guillem's avatar
Guillem committed
188
} address_phase;
GuillemCabo's avatar
GuillemCabo committed
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
if (FT==0) begin
    logic select, write;
    logic [HADDR_WIDTH-1:0] master_addr;
    always_ff @(posedge clk_i) begin
        if (rstn_i==0) begin
            select <= 1'b0;
            write <= 1'b0;
            master_addr <= '{default:0};
        end else begin
            select <= address_phase.select_D;
            write <= address_phase. write_D;
            master_addr <= address_phase.master_addr_D;
        end
    end
    
    always_comb begin
        address_phase.select_Q = select;
        address_phase.write_Q = write;
        address_phase.master_addr_Q = master_addr;
    end
end else begin : Apft //Address phase FT
210
211
    logic write_fte1, select_fte1, master_addr_fte1;
    logic write_fte2, select_fte2, master_addr_fte2;
GuillemCabo's avatar
GuillemCabo committed
212
213
214
215
216
217
218
    
    triple_reg#(.IN_WIDTH(1)
    )write_trip(
    .clk_i(clk_i),
    .rstn_i(rstn_i),
    .din_i(address_phase.write_D),
    .dout_o(address_phase.write_Q),
219
220
    .error1_o(write_fte1), // ignore corrected errors
    .error2_o(write_fte2)
GuillemCabo's avatar
GuillemCabo committed
221
222
223
224
225
226
227
228
    );
    
    triple_reg#(.IN_WIDTH(1)
    )select_trip(
    .clk_i(clk_i),
    .rstn_i(rstn_i),
    .din_i(address_phase.select_D),
    .dout_o(address_phase.select_Q),
229
230
    .error1_o(select_fte1), // ignore corrected errors
    .error2_o(select_fte2)
GuillemCabo's avatar
GuillemCabo committed
231
232
233
234
235
236
237
238
    );
    
    triple_reg#(.IN_WIDTH(HADDR_WIDTH)
    )master_addr_trip(
    .clk_i(clk_i),
    .rstn_i(rstn_i),
    .din_i(address_phase.master_addr_D),
    .dout_o(address_phase.master_addr_Q),
239
240
    .error1_o(master_addr_fte1), // ignore corrected errors
    .error2_o(master_addr_fte2)
GuillemCabo's avatar
GuillemCabo committed
241
242
243
244
    );
    
end

Guillem's avatar
Guillem committed
245
246
247
248

//----------------------------------------------
//------------- AHB registers
//----------------------------------------------
GuillemCabo's avatar
GuillemCabo committed
249
250
251
252
253
    wire [REG_WIDTH-1:0] pmu_regs_int [0:N_REGS-1];
    logic [HDATA_WIDTH-1:0] dwrite_slave; //Data master to the register bank
    logic [1:0] complete_transfer_status;
    logic [HDATA_WIDTH-1:0] dread_slave; //response from slave
    wire [$clog2(N_REGS)-1:0] slv_index;
GuillemCabo's avatar
GuillemCabo committed
254
    wire  invalid_index;
Guillem's avatar
Guillem committed
255
256
257
    logic [REG_WIDTH-1:0] slv_reg [0:N_REGS-1];
    logic [REG_WIDTH-1:0] slv_reg_D [0:N_REGS-1];
    logic [REG_WIDTH-1:0] slv_reg_Q [0:N_REGS-1];
GuillemCabo's avatar
GuillemCabo committed
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
     
    generate
    if (FT==0) begin
        always_ff @(posedge clk_i) begin
            if(rstn_i == 1'b0 ) begin
                slv_reg<='{default:0};
            end else begin 
                slv_reg <= slv_reg_D;
            end
        end
        //----------------------------------------------
        //------------- Slave registers update
        //----------------------------------------------

        //Each cycle the values in slv_reg_D will be saved in slv_reg
            //So if you want to update slv_reg the values for slv_reg_D shall be 
            //assigned in this section
            //If you add aditional logic that can change the values of the registers
            //the next always block have to be modified to add the aditional
            //conditions under which the slv_reg shall be updated
        always_comb begin
                //AHB write
GuillemCabo's avatar
GuillemCabo committed
280
281
282
                //Write to slv registers if slave was selected & was a write to a valid register
                //Else register the values given by pmu_raw
                if(address_phase.write_Q && address_phase.select_Q && !invalid_index) begin
GuillemCabo's avatar
GuillemCabo committed
283
284
285
286
287
288
289
290
291
292
                    // get the values from the pmu_raw instance
                    slv_reg_Q = slv_reg;
                    slv_reg_Q [slv_index] = dwrite_slave;
                    slv_reg_D = pmu_regs_int;
                    slv_reg_D[slv_index] = dwrite_slave; 
                end else begin
                    slv_reg_D = pmu_regs_int;
                    slv_reg_Q = slv_reg;
                end
        end 
GuillemCabo's avatar
GuillemCabo committed
293
    end else begin : Slvft
GuillemCabo's avatar
GuillemCabo committed
294
295
296
297
298
299
300
301
302
        //FT version of the registers
            // Hamming bits, 6 for each 26 bits of data
        localparam HAM_P=6;//protection bits
        localparam HAM_D=26;//data bits
        localparam HAM_M=HAM_P+HAM_D;//mesage bits
        localparam N_HAM32_SLV= (((REG_WIDTH*N_REGS)+(HAM_D-1))/(HAM_D));
            //interrupt FT error
        wire  [N_HAM32_SLV-1:0] ift_slv; //interrupt fault tolerance mechanism
            //"Flat" slv_reg Q and D signals
GuillemCabo's avatar
GuillemCabo committed
303
        wire [N_HAM32_SLV*HAM_D-1:0] slv_reg_fte;//fault tolerance in
GuillemCabo's avatar
GuillemCabo committed
304
305
306
307
308
309
310
311
312
313
314
        wire [N_HAM32_SLV*HAM_D-1:0] slv_reg_fto;//fault tolerance out
        wire [REG_WIDTH-1:0] slv_reg_ufto [0:N_REGS-1];//unpacked fault tolerance out
        wire [N_HAM32_SLV*HAM_D-1:0] slv_reg_pQ ;//protected output
            //"Flat" hamming messages (Data+parity bits)
        wire [(HAM_M*N_HAM32_SLV)-1:0] ham_mbits_D;
        wire [(HAM_M*N_HAM32_SLV)-1:0] ham_mbits_Q;
            //Registers for parity bits
        logic [HAM_P*N_HAM32_SLV-1:0] ham_pbits;
        //Feed and send flat assigment in to original format 
        for (genvar i =0; i<N_REGS; i++) begin
            //assign slv_register inputs to a flat hamming input
GuillemCabo's avatar
GuillemCabo committed
315
            assign slv_reg_fte[(i+1)*REG_WIDTH-1:i*REG_WIDTH]=slv_reg_D[i][REG_WIDTH-1:0];
GuillemCabo's avatar
GuillemCabo committed
316
317
318
319
320
321
        end
        // SEC-DEC hamming on 26 bit data chunks
        for (genvar i =0; i<(N_HAM32_SLV); i++) begin : slv_ham_enc
            //encoder
                //hv_o needs to inteleave protection and data bits
            hamming32t26d_enc#(
GuillemCabo's avatar
GuillemCabo committed
322
323
            )slv_hamming32t26d_enc (
                .data_i(slv_reg_fte[(i+1)*HAM_D-1:i*HAM_D]),
GuillemCabo's avatar
GuillemCabo committed
324
325
326
327
328
329
330
331
332
333
334
                .hv_o(ham_mbits_D[(i+1)*(HAM_M)-1:i*(HAM_M)])
            );
        end
        //Feed data into original registers
        for (genvar i =0; i<N_REGS; i++) begin
            always_ff @(posedge clk_i) begin
                if(rstn_i == 1'b0 ) begin
                    slv_reg[i]<='{default:0};
                end else begin
                    //You could be using ham_mbits_D but code is longer
                    //Some of the ham_mbits_D aren't needed
GuillemCabo's avatar
GuillemCabo committed
335
                    slv_reg[i] <= slv_reg_fte[(i+1)*REG_WIDTH-1:REG_WIDTH*i];
GuillemCabo's avatar
GuillemCabo committed
336
337
338
339
340
341
342
                end
            end
            assign slv_reg_pQ[(i+1)*REG_WIDTH-1:i*REG_WIDTH] = slv_reg[i];
        end
        // pad signals to fill an integer number of 26 bit chunks
        for (genvar i =(N_REGS)*REG_WIDTH; i<N_HAM32_SLV*HAM_D; i++) begin
            assign slv_reg_pQ[i] = 1'b0;
GuillemCabo's avatar
GuillemCabo committed
343
            assign slv_reg_fte[i] = 1'b0;
GuillemCabo's avatar
GuillemCabo committed
344
        end
Guillem's avatar
Guillem committed
345

GuillemCabo's avatar
GuillemCabo committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
        //Feed encoded parity bits into extra registers
        for (genvar i =0; i<N_HAM32_SLV; i++) begin
            always_ff @(posedge clk_i) begin
                if(rstn_i == 1'b0 ) begin
                    ham_pbits[(i+1)*HAM_P-1:i*HAM_P]<='{default:0};
                end else begin 
                    ham_pbits[(i+1)*HAM_P-1:i*HAM_P]<={
                                                      ham_mbits_D[i*HAM_M+16]
                                                      ,ham_mbits_D[i*HAM_M+8]
                                                      ,ham_mbits_D[i*HAM_M+4]
                                                      ,ham_mbits_D[i*HAM_M+2]
                                                      ,ham_mbits_D[i*HAM_M+1]
                                                      ,ham_mbits_D[i*HAM_M+0]
                                                     };
                end
            end
            //Get flat registered messages
            assign ham_mbits_Q [(i+1)*HAM_M-1:i*HAM_M] = {
                                                        slv_reg_pQ[i*HAM_D+25:i*HAM_D+11]
                                                        ,ham_pbits[i*HAM_P+5]
                                                        ,slv_reg_pQ[i*HAM_D+10:i*HAM_D+4]
                                                        ,ham_pbits[i*HAM_P+4]
                                                        ,slv_reg_pQ[i*HAM_D+3:i*HAM_D+1]
                                                        ,ham_pbits[i*HAM_P+3]
                                                        ,slv_reg_pQ[i*HAM_D]
                                                        ,ham_pbits[i*HAM_P+2]
                                                        ,ham_pbits[i*HAM_P+1]
                                                        ,ham_pbits[i*HAM_P]
                                                        };
        end
        for (genvar i =0; i<N_HAM32_SLV; i++) begin : slv_ham_dec
            //decoder
            hamming32t26d_dec#(
GuillemCabo's avatar
GuillemCabo committed
379
            )slv_hamming32t26d_dec (
GuillemCabo's avatar
GuillemCabo committed
380
381
382
383
                .data_o(slv_reg_fto[(i+1)*HAM_D-1:i*HAM_D]),
                .hv_i(ham_mbits_Q[(i+1)*HAM_M-1:i*HAM_M]),
                .ded_error_o(ift_slv[i])
            );
Guillem's avatar
Guillem committed
384
        end
GuillemCabo's avatar
GuillemCabo committed
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
        // get a packed 2d structure to assign slv_reg
        for (genvar i =0; i<N_REGS; i++) begin
            assign slv_reg_ufto[i]=slv_reg_fto[(i+1)*REG_WIDTH-1:i*REG_WIDTH];
        end
        //----------------------------------------------
        //------------- Slave registers update
        //----------------------------------------------

        //Each cycle the values in slv_reg_D will be saved in slv_reg
            //So if you want to update slv_reg the values for slv_reg_D shall be 
            //assigned in this section
            //If you add aditional logic that can change the values of the registers
            //the next always block have to be modified to add the aditional
            //conditions under which the slv_reg shall be updated
        always_comb begin
                //AHB write
GuillemCabo's avatar
GuillemCabo committed
401
402
403
                //Write to slv registers if slave was selected & was a write to a valid register
                //Else register the values given by pmu_raw
                if(address_phase.write_Q && address_phase.select_Q && !invalid_index) begin
GuillemCabo's avatar
GuillemCabo committed
404
405
406
407
408
409
410
411
412
413
414
415
416
                    //Feed and send flat assigment in to original format 
                        //assign flat hamming outputs to slv_reg_Q
                    slv_reg_Q=slv_reg_ufto;
                    slv_reg_Q [slv_index] = dwrite_slave;
                    slv_reg_D = pmu_regs_int;
                    slv_reg_D[slv_index] = dwrite_slave; 
                end else begin
                    slv_reg_D = pmu_regs_int;
                    //Feed and send flat assigment in to original format 
                        //assign flat hamming outputs to slv_reg_Q
                    slv_reg_Q=slv_reg_ufto;
                end
        end 
Guillem's avatar
Guillem committed
417
    end
GuillemCabo's avatar
GuillemCabo committed
418
    endgenerate
Guillem's avatar
Guillem committed
419

Guillem's avatar
Guillem committed
420
421
422
//----------------------------------------------
//------------- AHB control logic
//----------------------------------------------
GuillemCabo's avatar
GuillemCabo committed
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
logic [1:0] next;

if (FT==0) begin
    logic [1:0] state;

    //data phase - state update
    always_ff @(posedge clk_i) begin
        if(rstn_i == 1'b0 ) begin
            state <= TRANS_IDLE;
        end else begin 
            state <= next;
        end
    end

    always_comb begin
    //NOTE: I don't expect any of the cafe beaf values in the registers if they do
    //there is a bug
        case (state)
            TRANS_IDLE: begin
                complete_transfer_status = TRANSFER_SUCCESS_COMPLETE; 
                dwrite_slave = 32'hbeaf1d1e; 
                dread_slave = 32'hcafe1d1e; 
            end
            TRANS_BUSY:begin
                complete_transfer_status = TRANSFER_SUCCESS_COMPLETE; 
                dwrite_slave = 32'hbeafb551; 
                dread_slave = 32'hcafeb551; 
            end
            TRANS_NONSEQUENTIAL:begin
                complete_transfer_status = TRANSFER_SUCCESS_COMPLETE; 
                dwrite_slave = hwdata_i; 
GuillemCabo's avatar
GuillemCabo committed
454
                if (!address_phase.write_Q && !invalid_index) begin
GuillemCabo's avatar
GuillemCabo committed
455
456
457
458
459
460
461
462
                    dread_slave = slv_reg_Q[slv_index];
                end else begin
                    dread_slave = 32'hcafe01a1;
                end
            end
            TRANS_SEQUENTIAL:begin
                complete_transfer_status = TRANSFER_SUCCESS_COMPLETE; 
                dwrite_slave = hwdata_i; 
GuillemCabo's avatar
GuillemCabo committed
463
                if (!address_phase.write_Q && !invalid_index) begin
GuillemCabo's avatar
GuillemCabo committed
464
465
466
467
468
469
470
471
472
473
474
                    dread_slave = slv_reg_Q[slv_index];
                end else begin
                    dread_slave = 32'hcafee1a1;
                end
            end
        endcase
    end
end else begin : Stateft
    //Fault tolerant implementation
        //Triplication of next and state registers 
    logic [1:0] state_D, state_Q;
475
    logic state_fte1, state_fte2; //fault tolerance errors
GuillemCabo's avatar
GuillemCabo committed
476
477
478
479
480
481
482
483
    
    //error1 signals a corrected error, safe to ignore
    triple_reg#(.IN_WIDTH(2)
    )state_trip(
    .clk_i(clk_i),
    .rstn_i(rstn_i),
    .din_i(state_D),
    .dout_o(state_Q),
484
485
    .error1_o(state_fte1),
    .error2_o(state_fte2)
GuillemCabo's avatar
GuillemCabo committed
486
487
488
489
490
491
492
493
494
495
    );
    
    //data phase - state update
    always_comb begin
        if(rstn_i == 1'b0 ) begin
            state_D = TRANS_IDLE;
        end else begin 
            state_D = next;
        end
    end
Guillem's avatar
Guillem committed
496

GuillemCabo's avatar
GuillemCabo committed
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
    always_comb begin
    //NOTE: I don't expect any of the cafe beaf values in the registers if they do
    //there is a bug
        case (state_Q)
            TRANS_IDLE: begin
                complete_transfer_status = TRANSFER_SUCCESS_COMPLETE; 
                dwrite_slave = 32'hbeaf1d1e; 
                dread_slave = 32'hcafe1d1e; 
            end
            TRANS_BUSY:begin
                complete_transfer_status = TRANSFER_SUCCESS_COMPLETE; 
                dwrite_slave = 32'hbeafb551; 
                dread_slave = 32'hcafeb551; 
            end
            TRANS_NONSEQUENTIAL:begin
                complete_transfer_status = TRANSFER_SUCCESS_COMPLETE; 
                dwrite_slave = hwdata_i; 
GuillemCabo's avatar
GuillemCabo committed
514
                if (!address_phase.write_Q && !invalid_index) begin
GuillemCabo's avatar
GuillemCabo committed
515
516
517
518
519
520
521
522
                    dread_slave = slv_reg_Q[slv_index];
                end else begin
                    dread_slave = 32'hcafe01a1;
                end
            end
            TRANS_SEQUENTIAL:begin
                complete_transfer_status = TRANSFER_SUCCESS_COMPLETE; 
                dwrite_slave = hwdata_i; 
GuillemCabo's avatar
GuillemCabo committed
523
                if (!address_phase.write_Q && !invalid_index) begin
GuillemCabo's avatar
GuillemCabo committed
524
525
526
527
528
529
530
531
                    dread_slave = slv_reg_Q[slv_index];
                end else begin
                    dread_slave = 32'hcafee1a1;
                end
            end
        endcase
    end
end
Guillem's avatar
Guillem committed
532
533
534
535
536
// address phase - state update 
always_comb begin
    case (htrans_i)
        TRANS_IDLE: begin
            next = TRANS_IDLE;
Guillem's avatar
Guillem committed
537
        end
Guillem's avatar
Guillem committed
538
        TRANS_BUSY:begin
Guillem's avatar
Guillem committed
539
540
541
542
543
            if(!hsel_i) begin
                next = TRANS_IDLE;
            end else begin
                next = TRANS_BUSY;
            end
Guillem's avatar
Guillem committed
544
        end
Guillem's avatar
Guillem committed
545
546
547
548
549
550
        TRANS_NONSEQUENTIAL:begin
            if(!hsel_i) begin
                next = TRANS_IDLE;
            end else begin
                next = TRANS_NONSEQUENTIAL;
            end
Guillem's avatar
Guillem committed
551
        end
Guillem's avatar
Guillem committed
552
553
554
555
556
557
        TRANS_SEQUENTIAL:begin
            if(!hsel_i) begin
                next = TRANS_IDLE;
            end else begin
                next = TRANS_SEQUENTIAL;
            end
Guillem's avatar
Guillem committed
558
        end
Guillem's avatar
Guillem committed
559
560
561
    endcase
end

GuillemCabo's avatar
GuillemCabo committed
562
// address phase - register required inputs
Guillem's avatar
Guillem committed
563
always_comb begin
GuillemCabo's avatar
GuillemCabo committed
564
565
566
567
568
    case (next) 
        TRANS_IDLE:begin
            address_phase.select_D = hsel_i;
            address_phase.write_D = 0; 
            address_phase.master_addr_D = address_phase.master_addr_Q;
Guillem's avatar
Guillem committed
569
570
        end
        TRANS_BUSY:begin
GuillemCabo's avatar
GuillemCabo committed
571
572
573
            address_phase.select_D = hsel_i;
            address_phase.write_D = 0;
            address_phase.master_addr_D = address_phase.master_addr_Q;
Guillem's avatar
Guillem committed
574
575
        end
        TRANS_NONSEQUENTIAL:begin
GuillemCabo's avatar
GuillemCabo committed
576
577
578
            address_phase.select_D = hsel_i;
            address_phase.write_D = hwrite_i;
            address_phase.master_addr_D = haddr_i;
Guillem's avatar
Guillem committed
579
580
        end
        TRANS_SEQUENTIAL:begin
GuillemCabo's avatar
GuillemCabo committed
581
582
583
            address_phase.select_D = hsel_i;
            address_phase.write_D = hwrite_i;
            address_phase.master_addr_D = haddr_i;
Guillem's avatar
Guillem committed
584
585
586
        end
    endcase
end
Guillem's avatar
Guillem committed
587

GuillemCabo's avatar
GuillemCabo committed
588
589
590

//data phase - slave response
assign slv_index = address_phase.master_addr_Q[$clog2(N_REGS)+1:2];
GuillemCabo's avatar
GuillemCabo committed
591
assign invalid_index = int'(address_phase.master_addr_Q[$clog2(N_REGS)+1:2]) >= N_REGS? 1'b1:1'b0;
GuillemCabo's avatar
GuillemCabo committed
592
593
594
595
596
597
assign hrdata_o = dread_slave;

assign hreadyo_o = complete_transfer_status [0];
//TODO: review the amount of bits for hresp_o
assign hresp_o = {{complete_transfer_status[1]},{complete_transfer_status[1]}};

Guillem's avatar
Guillem committed
598
599
600
//----------------------------------------------
//------------- PMU_raw instance
//----------------------------------------------
Guillem's avatar
Guillem committed
601
    wire ahb_write_req;
GuillemCabo's avatar
GuillemCabo committed
602
    assign ahb_write_req = address_phase.write_Q && address_phase.select_Q;
603
    logic pmu_raw_FT1, pmu_raw_FT2;
604
    
Guillem's avatar
Guillem committed
605
606
    PMU_raw #(
		.REG_WIDTH(REG_WIDTH),
607
        .MCCU_N_CORES(MCCU_N_CORES),
Guillem's avatar
Guillem committed
608
		.N_COUNTERS(PMU_COUNTERS),
609
		.N_SOC_EV(N_SOC_EV),
GuillemCabo's avatar
GuillemCabo committed
610
        .FT(FT),
Guillem's avatar
Guillem committed
611
		.N_CONF_REGS(PMU_CFG)
Guillem's avatar
Guillem committed
612
613
614
	)inst_pmu_raw (
		.clk_i(clk_i),
		.rstn_i(rstn_i),
Guillem's avatar
Guillem committed
615
        .regs_i(slv_reg_Q),
Guillem's avatar
Guillem committed
616
        .regs_o(pmu_regs_int),
617
        .wrapper_we_i(ahb_write_req),
618
619
        .intr_FT1_o(pmu_raw_FT1),
        .intr_FT2_o(pmu_raw_FT2),
Guillem's avatar
Guillem committed
620
621
622
623
624
625
        //on pourpose .name connections
        .events_i,
        .intr_overflow_o,
        .intr_quota_o,
        .intr_MCCU_o,
        .intr_RDC_o
Guillem's avatar
Guillem committed
626
	);
Guillem's avatar
Guillem committed
627

GuillemCabo's avatar
GuillemCabo committed
628
629
630
631
//----------------------------------------------
//------------- Generate intr_FT_o
//----------------------------------------------
if (FT == 0 ) begin
632
633
        assign intr_FT1_o = 1'b0;
        assign intr_FT2_o = 1'b0;
GuillemCabo's avatar
GuillemCabo committed
634
end else begin 
635
636
637
638
639
640
        //Gather all the signals of corrected errors from FT scopes
            // Codestyle. All scopes start with a capital letter
        assign intr_FT1_o = |{Apft.write_fte1,Apft.select_fte1, Apft.master_addr_fte1,
                             Stateft.state_fte1,
                             pmu_raw_FT1
                             };
GuillemCabo's avatar
GuillemCabo committed
641
642
        //Gather all the signals of uncorrected errors from FT scopes
            // Codestyle. All scopes start with a capital letter
643
644
645
646
        assign intr_FT2_o = |{Slvft.ift_slv,
                             Apft.write_fte2,Apft.select_fte2, Apft.master_addr_fte2,
                             Stateft.state_fte2,
                             pmu_raw_FT2
GuillemCabo's avatar
GuillemCabo committed
647
648
                             };
end
Guillem's avatar
Guillem committed
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
/////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef	FORMAL
    //auxiliar registers
    reg f_past_valid ;
    initial f_past_valid = 1'b0;
    //Set f_past_valid after first clock cycle
    always@( posedge clk_i )
        f_past_valid <= 1'b1;
   
    //assume that if f_past is not valid you have to reset
    always @(*) begin
		if(0 == f_past_valid) begin
            assume(0 == rstn_i);
         end
    end
668
669
670
    //AHB assumptions


Guillem's avatar
Guillem committed
671
    default clocking @(posedge clk_i); endclocking;
672
673
674
675
676
677
678
679
680
681
682
683
684
    //If the peripheral is not selected there is no chance to issue a write
    assert property (((hsel_i == 0) && f_past_valid 
                    ) 
                    |=> (ahb_write_req == 0));

    //If htrans_i is not iddle or busy and  there is a write. ahb_write_req is
    //one in the next cycle unless there is a reset in the next cycle
    assert property (((hsel_i == 1) && f_past_valid && rstn_i==1 && $stable(rstn_i) 
                    && (htrans_i!=TRANS_IDLE && htrans_i!=TRANS_BUSY)
                    && (hwrite_i==1)
                    )
                    |=> (ahb_write_req == 1) || rstn_i==0);

Guillem's avatar
Guillem committed
685
686
687
688
    // If there is no write and no reset the slv_Regs used by the counters can
    // only decrease due to an overflow
        //posible resets of counters
    sequence no_counter_reset;
GuillemCabo's avatar
GuillemCabo committed
689
        f_past_valid && ($past(rstn_i) != 0) && (slv_reg[0][1] == 0);
Guillem's avatar
Guillem committed
690
691
692
693
694
695
696
    endsequence
    sequence counter_reset;
        (rstn_i == 0) || (slv_reg[0][1] == 1);
    endsequence
        //There is no pending write or it is not valid
    sequence no_ahb_write;
        //since ahb is pipelined i check for the last addres phase
GuillemCabo's avatar
GuillemCabo committed
697
        f_past_valid && (ahb_write_req==1'b0); 
Guillem's avatar
Guillem committed
698
699
700
    endsequence
        //Register 1, assigned to counter 0 can't decrease
    sequence no_decrease_counter(n);
GuillemCabo's avatar
GuillemCabo committed
701
        (slv_reg[n+1] >= $past(slv_reg[n+1])) && f_past_valid;
Guillem's avatar
Guillem committed
702
703
704
705
706
707
708
709
710
711
712
    endsequence
        //Register 1, can decrease at overflow
    sequence overflow_counter(n);
        $past(slv_reg[n+1]) == 32'hffffffff;
    endsequence
        //check property for all pmu registers.
        //TODO: Do we actually want to check all ? Takes 6 minutes each. 
    generate
        genvar i;
        for (i=0;i<PMU_COUNTERS;i++) begin
        assert property (
GuillemCabo's avatar
GuillemCabo committed
713
714
            no_ahb_write and (rstn_i==1) and (slv_reg[0][1] == 0)
            |=> no_decrease_counter(i) or overflow_counter(i)
Guillem's avatar
Guillem committed
715
716
717
            );
        end
    endgenerate
718

GuillemCabo's avatar
GuillemCabo committed
719
    //Base configuration register remains stables if last cycle isn't a reset or
720
721
    //write
    assert property (
GuillemCabo's avatar
GuillemCabo committed
722
723
        (ahb_write_req==1'b0) and (rstn_i==1)
        |=> $stable(slv_reg[0]) 
724
725
        );
    
Guillem's avatar
Guillem committed
726
727
728
729
    //TODO: If counters cant decrease by their own what explains that we read
    //incoherent values out of the pmu? AHB properties? Does it fail to read
    //when only one core is available? Does only happen in multicore? What if 
    //nops are inserted after each read? 
730
    
731

Guillem's avatar
Guillem committed
732
733
`endif

Guillem's avatar
Guillem committed
734
735
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip