pmu_ahb.sv 28 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;
Guillem's avatar
Guillem committed
254
255
256
    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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
     
    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
                //Write to slv registers if slave was selected & was a write. Else
                //register the values given by pmu_raw
GuillemCabo's avatar
GuillemCabo committed
281
                if(address_phase.write_Q && address_phase.select_Q) begin
GuillemCabo's avatar
GuillemCabo committed
282
283
284
285
286
287
288
289
290
291
                    // 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
292
    end else begin : Slvft
GuillemCabo's avatar
GuillemCabo committed
293
294
295
296
297
298
299
300
301
        //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
302
        wire [N_HAM32_SLV*HAM_D-1:0] slv_reg_fte;//fault tolerance in
GuillemCabo's avatar
GuillemCabo committed
303
304
305
306
307
308
309
310
311
312
313
        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
314
            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
315
316
317
318
319
320
        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
321
322
            )slv_hamming32t26d_enc (
                .data_i(slv_reg_fte[(i+1)*HAM_D-1:i*HAM_D]),
GuillemCabo's avatar
GuillemCabo committed
323
324
325
326
327
328
329
330
331
332
333
                .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
334
                    slv_reg[i] <= slv_reg_fte[(i+1)*REG_WIDTH-1:REG_WIDTH*i];
GuillemCabo's avatar
GuillemCabo committed
335
336
337
338
339
340
341
                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
342
            assign slv_reg_fte[i] = 1'b0;
GuillemCabo's avatar
GuillemCabo committed
343
        end
Guillem's avatar
Guillem committed
344

GuillemCabo's avatar
GuillemCabo committed
345
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
        //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
378
            )slv_hamming32t26d_dec (
GuillemCabo's avatar
GuillemCabo committed
379
380
381
382
                .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
383
        end
GuillemCabo's avatar
GuillemCabo committed
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
        // 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
                //Write to slv registers if slave was selected & was a write. Else
                //register the values given by pmu_raw
GuillemCabo's avatar
GuillemCabo committed
402
                if(address_phase.write_Q && address_phase.select_Q) begin
GuillemCabo's avatar
GuillemCabo committed
403
404
405
406
407
408
409
410
411
412
413
414
415
                    //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
416
    end
GuillemCabo's avatar
GuillemCabo committed
417
    endgenerate
Guillem's avatar
Guillem committed
418

Guillem's avatar
Guillem committed
419
420
421
//----------------------------------------------
//------------- AHB control logic
//----------------------------------------------
GuillemCabo's avatar
GuillemCabo committed
422
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
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
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; 
                if (!address_phase.write_Q) begin
                    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; 
                if (!address_phase.write_Q) begin
                    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;
474
    logic state_fte1, state_fte2; //fault tolerance errors
GuillemCabo's avatar
GuillemCabo committed
475
476
477
478
479
480
481
482
    
    //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),
483
484
    .error1_o(state_fte1),
    .error2_o(state_fte2)
GuillemCabo's avatar
GuillemCabo committed
485
486
487
488
489
490
491
492
493
494
    );
    
    //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
495

GuillemCabo's avatar
GuillemCabo committed
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
    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; 
                if (!address_phase.write_Q) begin
                    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; 
                if (!address_phase.write_Q) begin
                    dread_slave = slv_reg_Q[slv_index];
                end else begin
                    dread_slave = 32'hcafee1a1;
                end
            end
        endcase
    end
end
Guillem's avatar
Guillem committed
531
532
533
534
535
// address phase - state update 
always_comb begin
    case (htrans_i)
        TRANS_IDLE: begin
            next = TRANS_IDLE;
Guillem's avatar
Guillem committed
536
        end
Guillem's avatar
Guillem committed
537
        TRANS_BUSY:begin
Guillem's avatar
Guillem committed
538
539
540
541
542
            if(!hsel_i) begin
                next = TRANS_IDLE;
            end else begin
                next = TRANS_BUSY;
            end
Guillem's avatar
Guillem committed
543
        end
Guillem's avatar
Guillem committed
544
545
546
547
548
549
        TRANS_NONSEQUENTIAL:begin
            if(!hsel_i) begin
                next = TRANS_IDLE;
            end else begin
                next = TRANS_NONSEQUENTIAL;
            end
Guillem's avatar
Guillem committed
550
        end
Guillem's avatar
Guillem committed
551
552
553
554
555
556
        TRANS_SEQUENTIAL:begin
            if(!hsel_i) begin
                next = TRANS_IDLE;
            end else begin
                next = TRANS_SEQUENTIAL;
            end
Guillem's avatar
Guillem committed
557
        end
Guillem's avatar
Guillem committed
558
559
560
    endcase
end

GuillemCabo's avatar
GuillemCabo committed
561
// address phase - register required inputs
Guillem's avatar
Guillem committed
562
always_comb begin
GuillemCabo's avatar
GuillemCabo committed
563
564
565
566
567
    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
568
569
        end
        TRANS_BUSY:begin
GuillemCabo's avatar
GuillemCabo committed
570
571
572
            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
573
574
        end
        TRANS_NONSEQUENTIAL:begin
GuillemCabo's avatar
GuillemCabo committed
575
576
577
            address_phase.select_D = hsel_i;
            address_phase.write_D = hwrite_i;
            address_phase.master_addr_D = haddr_i;
Guillem's avatar
Guillem committed
578
579
        end
        TRANS_SEQUENTIAL:begin
GuillemCabo's avatar
GuillemCabo committed
580
581
582
            address_phase.select_D = hsel_i;
            address_phase.write_D = hwrite_i;
            address_phase.master_addr_D = haddr_i;
Guillem's avatar
Guillem committed
583
584
585
        end
    endcase
end
Guillem's avatar
Guillem committed
586

GuillemCabo's avatar
GuillemCabo committed
587
588
589
590
591
592
593
594
595

//data phase - slave response
assign slv_index = address_phase.master_addr_Q[$clog2(N_REGS)+1:2];
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
596
597
598
//----------------------------------------------
//------------- PMU_raw instance
//----------------------------------------------
Guillem's avatar
Guillem committed
599
    wire ahb_write_req;
GuillemCabo's avatar
GuillemCabo committed
600
    assign ahb_write_req = address_phase.write_Q && address_phase.select_Q;
601
    logic pmu_raw_FT1, pmu_raw_FT2;
602
    
Guillem's avatar
Guillem committed
603
604
    PMU_raw #(
		.REG_WIDTH(REG_WIDTH),
605
        .MCCU_N_CORES(MCCU_N_CORES),
Guillem's avatar
Guillem committed
606
		.N_COUNTERS(PMU_COUNTERS),
607
		.N_SOC_EV(N_SOC_EV),
GuillemCabo's avatar
GuillemCabo committed
608
        .FT(FT),
Guillem's avatar
Guillem committed
609
		.N_CONF_REGS(PMU_CFG)
Guillem's avatar
Guillem committed
610
611
612
	)inst_pmu_raw (
		.clk_i(clk_i),
		.rstn_i(rstn_i),
Guillem's avatar
Guillem committed
613
        .regs_i(slv_reg_Q),
Guillem's avatar
Guillem committed
614
        .regs_o(pmu_regs_int),
615
        .wrapper_we_i(ahb_write_req),
616
617
        .intr_FT1_o(pmu_raw_FT1),
        .intr_FT2_o(pmu_raw_FT2),
Guillem's avatar
Guillem committed
618
619
620
621
622
623
        //on pourpose .name connections
        .events_i,
        .intr_overflow_o,
        .intr_quota_o,
        .intr_MCCU_o,
        .intr_RDC_o
Guillem's avatar
Guillem committed
624
	);
Guillem's avatar
Guillem committed
625

GuillemCabo's avatar
GuillemCabo committed
626
627
628
629
//----------------------------------------------
//------------- Generate intr_FT_o
//----------------------------------------------
if (FT == 0 ) begin
630
631
        assign intr_FT1_o = 1'b0;
        assign intr_FT2_o = 1'b0;
GuillemCabo's avatar
GuillemCabo committed
632
end else begin 
633
634
635
636
637
638
        //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
639
640
        //Gather all the signals of uncorrected errors from FT scopes
            // Codestyle. All scopes start with a capital letter
641
642
643
644
        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
645
646
                             };
end
Guillem's avatar
Guillem committed
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
/////////////////////////////////////////////////////////////////////////////////
//
// 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
666
667
668
    //AHB assumptions


Guillem's avatar
Guillem committed
669
    default clocking @(posedge clk_i); endclocking;
670
671
672
673
674
675
676
677
678
679
680
681
682
    //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
683
684
685
686
    // 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
687
        f_past_valid && ($past(rstn_i) != 0) && (slv_reg[0][1] == 0);
Guillem's avatar
Guillem committed
688
689
690
691
692
693
694
    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
695
        f_past_valid && (ahb_write_req==1'b0); 
Guillem's avatar
Guillem committed
696
697
698
    endsequence
        //Register 1, assigned to counter 0 can't decrease
    sequence no_decrease_counter(n);
GuillemCabo's avatar
GuillemCabo committed
699
        (slv_reg[n+1] >= $past(slv_reg[n+1])) && f_past_valid;
Guillem's avatar
Guillem committed
700
701
702
703
704
705
706
707
708
709
710
    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
711
712
            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
713
714
715
            );
        end
    endgenerate
716

GuillemCabo's avatar
GuillemCabo committed
717
    //Base configuration register remains stables if last cycle isn't a reset or
718
719
    //write
    assert property (
GuillemCabo's avatar
GuillemCabo committed
720
721
        (ahb_write_req==1'b0) and (rstn_i==1)
        |=> $stable(slv_reg[0]) 
722
723
        );
    
Guillem's avatar
Guillem committed
724
725
726
727
    //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? 
728
    
729

Guillem's avatar
Guillem committed
730
731
`endif

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