AXI_PMU_interface_v1_0_S00_AXI.sv 39 KB
Newer Older
Guillem's avatar
Guillem committed
1
2
3
4
5
6
7
8
9
10
11
//-----------------------------------------------------
// ProjectName: Drac
// Function   : Monitor events generated by SoC
// Description: The PMU is an AXI peripheral that allow to monitor several
//              events, you can set how many you need with N_COUNTERS.
//              The amount of Counters and configuration registers affect the
//              IO space adress in the processor, so be sure that the driver
//              library writtes in the correspoding address.
//              axi_awaddr[1:0] and axi_araddr[1:0] are unused because data 
//              is accessed must be 32bit aligned.
// Coder      : G.Cabo
Guillem's avatar
Guillem committed
12
13
14
// References : Implementation of Maximum-Contention Control Unit (MCCU): 
//              ResourceAccess Count and Contention Time Enforcement. 
//              https://upcommons.upc.edu/handle/2117/133656
Guillem's avatar
Guillem committed
15
16

`default_nettype none
bscuser's avatar
bscuser committed
17
18
`timescale 1 ns / 1 ps

Guillem's avatar
Guillem committed
19
20
21
22
23
`ifndef SYNT
    `ifdef FORMAL 
        `define ASSERTIONS
    `endif
`endif
bscuser's avatar
bscuser committed
24
25
26
27
28
29
30
	module AXI_PMU_interface_v1_0_S00_AXI #
	(
		// Width of S_AXI data bus
		parameter integer C_S_AXI_DATA_WIDTH	= 32,
		// Width of S_AXI address bus
		parameter integer C_S_AXI_ADDR_WIDTH	= 7,
		// Amount of counters
Guillem's avatar
Guillem committed
31
		parameter integer N_COUNTERS	= 9,
bscuser's avatar
bscuser committed
32
		// Configuration registers
33
34
35
36
		parameter integer N_CONF_REGS	= 1,
		// Overflow
		parameter integer OVERFLOW	= 1, //Yes/No
		// Quota
Guillem's avatar
Guillem committed
37
38
39
40
41
		parameter integer QUOTA	= 1, //Yes/No
		// MCCU - Maximum-contention Control Unit mode
		parameter integer MCCU	= 1, //Yes/No
		// MCCU - N_CORES
		parameter integer N_CORES	= 1 
bscuser's avatar
bscuser committed
42
43
	)
	(
Guillem's avatar
Guillem committed
44
45
        //interruptions risen when one event exceeds it expected max duration
        output wire int_rdc_o,
Guillem's avatar
Guillem committed
46
47
        //interruptions risen when cores exceeds the quota of MCCU
        output wire MCCU_int_o [N_CORES-1:0],
48
        //interruption rises when one of the counters overflows
Guillem's avatar
Guillem committed
49
        output reg int_overflow_o,
50
        //interruption rises when the total of cuota consumed is exceeded
Guillem's avatar
Guillem committed
51
        output wire int_quota_o,
Guillem's avatar
Guillem committed
52
53
        //external signals from Soc events
        input wire [N_COUNTERS-1:0] events_i, // bus of signals for counters 
bscuser's avatar
bscuser committed
54
		// Global Clock Signal
Guillem's avatar
Guillem committed
55
		input wire  S_AXI_ACLK_i,
bscuser's avatar
bscuser committed
56
		// Global Reset Signal. This Signal is Active LOW
Guillem's avatar
Guillem committed
57
		input wire  S_AXI_ARESETN_i,
bscuser's avatar
bscuser committed
58
		// Write address (issued by master, acceped by Slave)
Guillem's avatar
Guillem committed
59
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR_i,
bscuser's avatar
bscuser committed
60
61
		// Write address valid. This signal indicates that the master signaling
    		// valid write address and control information.
Guillem's avatar
Guillem committed
62
		input wire  S_AXI_AWVALID_i,
bscuser's avatar
bscuser committed
63
64
		// Write address ready. This signal indicates that the slave is ready
    		// to accept an address and associated control signals.
Guillem's avatar
Guillem committed
65
		output wire  S_AXI_AWREADY_o,
bscuser's avatar
bscuser committed
66
		// Write data (issued by master, acceped by Slave) 
Guillem's avatar
Guillem committed
67
		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA_i,
bscuser's avatar
bscuser committed
68
69
70
		// Write strobes. This signal indicates which byte lanes hold
    		// valid data. There is one write strobe bit for each eight
    		// bits of the write data bus.    
Guillem's avatar
Guillem committed
71
		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB_i,
bscuser's avatar
bscuser committed
72
73
		// Write valid. This signal indicates that valid write
    		// data and strobes are available.
Guillem's avatar
Guillem committed
74
		input wire  S_AXI_WVALID_i,
bscuser's avatar
bscuser committed
75
76
		// Write ready. This signal indicates that the slave
    		// can accept the write data.
Guillem's avatar
Guillem committed
77
		output wire  S_AXI_WREADY_o,
bscuser's avatar
bscuser committed
78
79
		// Write response. This signal indicates the status
    		// of the write transaction.
Guillem's avatar
Guillem committed
80
		output wire [1 : 0] S_AXI_BRESP_o,
bscuser's avatar
bscuser committed
81
82
		// Write response valid. This signal indicates that the channel
    		// is signaling a valid write response.
Guillem's avatar
Guillem committed
83
		output wire  S_AXI_BVALID_o,
bscuser's avatar
bscuser committed
84
85
		// Response ready. This signal indicates that the master
    		// can accept a write response.
Guillem's avatar
Guillem committed
86
		input wire  S_AXI_BREADY_i,
bscuser's avatar
bscuser committed
87
		// Read address (issued by master, acceped by Slave)
Guillem's avatar
Guillem committed
88
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR_i,
bscuser's avatar
bscuser committed
89
90
		// Read address valid. This signal indicates that the channel
    		// is signaling valid read address and control information.
Guillem's avatar
Guillem committed
91
		input wire  S_AXI_ARVALID_i,
bscuser's avatar
bscuser committed
92
93
		// Read address ready. This signal indicates that the slave is
    		// ready to accept an address and associated control signals.
Guillem's avatar
Guillem committed
94
		output wire  S_AXI_ARREADY_o,
bscuser's avatar
bscuser committed
95
		// Read data (issued by slave)
Guillem's avatar
Guillem committed
96
		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA_o,
bscuser's avatar
bscuser committed
97
98
		// Read response. This signal indicates the status of the
    		// read transfer.
Guillem's avatar
Guillem committed
99
		output wire [1 : 0] S_AXI_RRESP_o,
bscuser's avatar
bscuser committed
100
101
		// Read valid. This signal indicates that the channel is
    		// signaling the required read data.
Guillem's avatar
Guillem committed
102
		output wire  S_AXI_RVALID_o,
bscuser's avatar
bscuser committed
103
104
		// Read ready. This signal indicates that the master can
    		// accept the read data and response information.
Guillem's avatar
Guillem committed
105
		input wire  S_AXI_RREADY_i
bscuser's avatar
bscuser committed
106
	);
Guillem's avatar
Guillem committed
107
//----------------------------------------------
Guillem's avatar
Guillem committed
108
//-------------AXI and PMU local paramaters
Guillem's avatar
Guillem committed
109
//----------------------------------------------
Guillem's avatar
Guillem committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
	localparam integer OPT_MEM_ADDR_BITS = 4;
    
    //One bit per counter and round up to N registers of DATA_WIDTH
    localparam integer N_OVERFLOW_REGS= (OVERFLOW == 0)? 0
                       :(N_COUNTERS % C_S_AXI_DATA_WIDTH) >0
                       ? (N_COUNTERS / C_S_AXI_DATA_WIDTH)+1 
                       : (N_COUNTERS / C_S_AXI_DATA_WIDTH);

    localparam integer N_QUOTA_MASK= (QUOTA==1)
                       ?(N_COUNTERS/C_S_AXI_DATA_WIDTH)+1:0;

    localparam integer N_QUOTA_LIMIT= (QUOTA==1)?1:0;//quota_limit
    

    //if more than 32 counters extra registers are needed for overflow
    localparam integer BASE_QUOTA = N_COUNTERS + N_CONF_REGS + N_OVERFLOW_REGS;
    //First addres for the MCCU
    localparam integer BASE_MCCU = BASE_QUOTA + N_QUOTA_MASK + N_QUOTA_LIMIT;
Guillem's avatar
Guillem committed
129
//----------------------------------------------
Guillem's avatar
Guillem committed
130
//-------------MCCU local paramaters
Guillem's avatar
Guillem committed
131
//----------------------------------------------
Guillem's avatar
Guillem committed
132
133
    //this parameters are 0 if PMU is not declared
    localparam MCCU_DATA_WIDTH = (MCCU!=0)? C_S_AXI_DATA_WIDTH : 0;  
Guillem's avatar
Guillem committed
134
    localparam MCCU_WEIGHTS_WIDTH = (MCCU!=0)?  8 : 0;
Guillem's avatar
Guillem committed
135
136
    localparam MCCU_N_CORES = (MCCU!=0)? N_CORES : 0;
    localparam MCCU_CORE_EVENTS = (MCCU!=0)? 4: 0;
Guillem's avatar
Guillem committed
137
138
139
140
141
142
143
    //Number of Registers needed to indicate the source of RDC interuption
    localparam MCCU_RDC_REGS = (MCCU==0)? 0 : (MCCU_N_CORES*MCCU_CORE_EVENTS)%
                                          C_S_AXI_DATA_WIDTH > 0 ?
                                          ((MCCU_N_CORES*MCCU_CORE_EVENTS)
                                          /C_S_AXI_DATA_WIDTH) + 1 :
                                          ((MCCU_N_CORES*MCCU_CORE_EVENTS)
                                          /C_S_AXI_DATA_WIDTH);
Guillem's avatar
Guillem committed
144
145
146
147
148
149
150
151
152
153
154
155
    //number of registers needed to store weights
    localparam integer MCCU_WEIGHTS_REGS = (MCCU==0) ?
                        0:
                        ((MCCU_N_CORES * MCCU_CORE_EVENTS * MCCU_WEIGHTS_WIDTH)
                        % MCCU_DATA_WIDTH )>0
                        ? 
                        ((MCCU_N_CORES * MCCU_CORE_EVENTS * MCCU_WEIGHTS_WIDTH)
                        / MCCU_DATA_WIDTH) + 1 
                        :
                        ((MCCU_N_CORES * MCCU_CORE_EVENTS * MCCU_WEIGHTS_WIDTH)
                        / MCCU_DATA_WIDTH);
                                     
Guillem's avatar
Guillem committed
156
157
    localparam MCCU_REGS = (MCCU!=0)? 1 + MCCU_N_CORES + MCCU_N_CORES 
                                        + MCCU_WEIGHTS_REGS + MCCU_RDC_REGS : 0;
Guillem's avatar
Guillem committed
158
    //the outputs of quota_o are read only
Guillem's avatar
Guillem committed
159
    localparam MCCU_R_REGS = (MCCU!=0)? MCCU_N_CORES + MCCU_RDC_REGS : 0;
Guillem's avatar
Guillem committed
160
    //the remaining registers are read write
Guillem's avatar
Guillem committed
161
    localparam MCCU_RW_REGS = (MCCU!=0)? (1 + MCCU_N_CORES + MCCU_WEIGHTS_REGS):0;
Guillem's avatar
Guillem committed
162
    //Base for the read only registers (output quota)   
Guillem's avatar
Guillem committed
163
164
165
166
    localparam BASE_MCCU_R_ONLY = BASE_MCCU + MCCU_RW_REGS;
    //Base for interruption vector Request Duration Counter
    localparam BASE_MCCU_INTRV_RDC = BASE_MCCU_R_ONLY + MCCU_N_CORES;
//----------------------------------------------
Guillem's avatar
Guillem committed
167
//-------------PMU additions local paramaters dependent on MCCU
Guillem's avatar
Guillem committed
168
//----------------------------------------------
Guillem's avatar
Guillem committed
169
170
171
172
173
174
175
176
177
178
179
180
    //This may change, there are advantages to be able to set the initial
    //value MCCU output registers are not read only in the strict way. they
    //can be written but they are automatically erased or updated to the right
    //value The same happen with the lower bits of the configuration register
    //of MCCU
    localparam integer R_ONLY_REGS = N_COUNTERS + MCCU_R_REGS;
    //Quota out registers of MCCU are write and read
    localparam integer RW_REGS = N_CONF_REGS + N_OVERFLOW_REGS + N_QUOTA_MASK
                                 + N_QUOTA_LIMIT + MCCU_RW_REGS;
    //Total of memory map registers
    localparam integer TOTAL_REGS = R_ONLY_REGS + RW_REGS;
	// Wire reset and enable signals
Guillem's avatar
Guillem committed
181
//----------------------------------------------
Guillem's avatar
Guillem committed
182
//------------ AXI4LITE signals
Guillem's avatar
Guillem committed
183
//----------------------------------------------
Guillem's avatar
Guillem committed
184
	/* verilator lint_off UNUSED */
185
    //Lower bits are not used due to 32 bit address aligment
Guillem's avatar
Guillem committed
186
187
    reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr;
	/* verilator lint_on UNUSED */
bscuser's avatar
bscuser committed
188
189
190
191
	reg  	axi_awready;
	reg  	axi_wready;
	reg [1 : 0] 	axi_bresp;
	reg  	axi_bvalid;
Guillem's avatar
Guillem committed
192
	/* verilator lint_off UNUSED */
193
    //Lower bits are not used due to 32 bit address aligment
bscuser's avatar
bscuser committed
194
	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_araddr;
Guillem's avatar
Guillem committed
195
	/* verilator lint_on UNUSED */
bscuser's avatar
bscuser committed
196
197
198
199
200
	reg  	axi_arready;
	reg [C_S_AXI_DATA_WIDTH-1 : 0] 	axi_rdata;
	reg [1 : 0] 	axi_rresp;
	reg  	axi_rvalid;

Guillem's avatar
Guillem committed
201
202
203
204
//----------------------------------------------
//-------------MCCU wires
//----------------------------------------------
    //Write back remaining quota in to slv_register allocated for it
Guillem's avatar
Guillem committed
205
    wire [MCCU_DATA_WIDTH-1:0] MCCU_quota_o [ 0: MCCU_N_CORES-1];
Guillem's avatar
Guillem committed
206
207
208
209
210
211
212
213
214
    //Interruption to request to Processor to check interruption_vector_rdc
    wire intr_rdc_o;
    assign int_rdc_o = intr_rdc_o;
    //Write back Request Duration Counter (RDC) events in to slv_register 
    //allocated for it. You need to softreset MCCU to clear this vector
    wire [MCCU_CORE_EVENTS-1:0] intrv_rdc_int [0:MCCU_N_CORES-1];
//----------------------------------------------
//-- Signals for user logic register space example
//------------------------------------------------
Guillem's avatar
Guillem committed
215
	//-- Number of Slave Registers 
Guillem's avatar
Guillem committed
216
    reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg [0:TOTAL_REGS-1] /*verilator public*/;
bscuser's avatar
bscuser committed
217
218
	
    wire	 slv_reg_rden;
219
	wire	 slv_reg_wren/*verilator public*/;
bscuser's avatar
bscuser committed
220
221
222
	reg [C_S_AXI_DATA_WIDTH-1:0]	 reg_data_out;
	integer	 byte_index;
	reg	 aw_en;
Guillem's avatar
Guillem committed
223
//----------------------------------------------
Guillem's avatar
Guillem committed
224
//------------ PMU signals
Guillem's avatar
Guillem committed
225
226
//----------------------------------------------
    wire en_PMU, rst_PMU;
Guillem's avatar
Guillem committed
227
228
229
    //the first bit of the first config register is the enable
    assign en_PMU = slv_reg[N_COUNTERS][0];
    //the second bit of the first config register is the reset
Guillem's avatar
Guillem committed
230
    assign rst_PMU = slv_reg[N_COUNTERS][1];
bscuser's avatar
bscuser committed
231
232
233

	// I/O Connections assignments

Guillem's avatar
Guillem committed
234
235
236
237
238
239
240
241
	assign S_AXI_AWREADY_o	= axi_awready;
	assign S_AXI_WREADY_o	= axi_wready;
	assign S_AXI_BRESP_o	= axi_bresp;
	assign S_AXI_BVALID_o	= axi_bvalid;
	assign S_AXI_ARREADY_o	= axi_arready;
	assign S_AXI_RDATA_o	= axi_rdata;
	assign S_AXI_RRESP_o	= axi_rresp;
	assign S_AXI_RVALID_o	= axi_rvalid;
bscuser's avatar
bscuser committed
242
	// Implement axi_awready generation
Guillem's avatar
Guillem committed
243
244
	// axi_awready is asserted for one S_AXI_ACLK_i clock cycle when both
	// S_AXI_AWVALID_i and S_AXI_WVALID_i are asserted. axi_awready is
bscuser's avatar
bscuser committed
245
246
	// de-asserted when reset is low.

GuillemCabo's avatar
GuillemCabo committed
247
	always @( posedge S_AXI_ACLK_i)
bscuser's avatar
bscuser committed
248
	begin
Guillem's avatar
Guillem committed
249
	  if ( S_AXI_ARESETN_i == 1'b0 )
bscuser's avatar
bscuser committed
250
251
252
253
254
255
	    begin
	      axi_awready <= 1'b0;
	      aw_en <= 1'b1;
	    end 
	  else
	    begin    
Guillem's avatar
Guillem committed
256
	      if (~axi_awready && S_AXI_AWVALID_i && S_AXI_WVALID_i && aw_en)
bscuser's avatar
bscuser committed
257
258
259
260
261
262
263
264
	        begin
	          // slave is ready to accept write address when 
	          // there is a valid write address and write data
	          // on the write address and data bus. This design 
	          // expects no outstanding transactions. 
	          axi_awready <= 1'b1;
	          aw_en <= 1'b0;
	        end
Guillem's avatar
Guillem committed
265
	        else if (S_AXI_BREADY_i && axi_bvalid)
bscuser's avatar
bscuser committed
266
267
268
269
270
271
272
273
274
275
276
277
278
	            begin
	              aw_en <= 1'b1;
	              axi_awready <= 1'b0;
	            end
	      else           
	        begin
	          axi_awready <= 1'b0;
	        end
	    end 
	end       

	// Implement axi_awaddr latching
	// This process is used to latch the address when both 
Guillem's avatar
Guillem committed
279
	// S_AXI_AWVALID_i and S_AXI_WVALID_i are valid. 
bscuser's avatar
bscuser committed
280

GuillemCabo's avatar
GuillemCabo committed
281
	always @( posedge S_AXI_ACLK_i)
bscuser's avatar
bscuser committed
282
	begin
Guillem's avatar
Guillem committed
283
	  if ( S_AXI_ARESETN_i == 1'b0 )
bscuser's avatar
bscuser committed
284
	    begin
Guillem's avatar
Guillem committed
285
	      axi_awaddr <= {C_S_AXI_ADDR_WIDTH{1'b0}};
bscuser's avatar
bscuser committed
286
287
288
	    end 
	  else
	    begin    
Guillem's avatar
Guillem committed
289
	      if (~axi_awready && S_AXI_AWVALID_i && S_AXI_WVALID_i && aw_en)
bscuser's avatar
bscuser committed
290
291
	        begin
	          // Write Address latching 
Guillem's avatar
Guillem committed
292
	          axi_awaddr <= S_AXI_AWADDR_i;
bscuser's avatar
bscuser committed
293
294
295
296
297
	        end
	    end 
	end       

	// Implement axi_wready generation
Guillem's avatar
Guillem committed
298
299
	// axi_wready is asserted for one S_AXI_ACLK_i clock cycle when both
	// S_AXI_AWVALID_i and S_AXI_WVALID_i are asserted. axi_wready is 
bscuser's avatar
bscuser committed
300
301
	// de-asserted when reset is low. 

GuillemCabo's avatar
GuillemCabo committed
302
	always @( posedge S_AXI_ACLK_i)
bscuser's avatar
bscuser committed
303
	begin
Guillem's avatar
Guillem committed
304
	  if ( S_AXI_ARESETN_i == 1'b0 )
bscuser's avatar
bscuser committed
305
306
307
308
309
	    begin
	      axi_wready <= 1'b0;
	    end 
	  else
	    begin    
Guillem's avatar
Guillem committed
310
	      if (~axi_wready && S_AXI_WVALID_i && S_AXI_AWVALID_i && aw_en )
bscuser's avatar
bscuser committed
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
	        begin
	          // slave is ready to accept write data when 
	          // there is a valid write address and write data
	          // on the write address and data bus. This design 
	          // expects no outstanding transactions. 
	          axi_wready <= 1'b1;
	        end
	      else
	        begin
	          axi_wready <= 1'b0;
	        end
	    end 
	end       

	// Implement memory mapped register select and write logic generation
	// The write data is accepted and written to memory mapped registers when
Guillem's avatar
Guillem committed
327
	// axi_awready, S_AXI_WVALID_i, axi_wready and S_AXI_WVALID_i are asserted. Write strobes are used to
bscuser's avatar
bscuser committed
328
329
330
331
	// select byte enables of slave registers while writing.
	// These registers are cleared when reset (active low) is applied.
	// Slave register write enable is asserted when valid address and data are available
	// and the slave is ready to accept the write address and write data.
Guillem's avatar
Guillem committed
332
	assign slv_reg_wren = axi_wready && S_AXI_WVALID_i && axi_awready && S_AXI_AWVALID_i;
bscuser's avatar
bscuser committed
333

GuillemCabo's avatar
GuillemCabo committed
334
	always @( posedge S_AXI_ACLK_i)
bscuser's avatar
bscuser committed
335
	begin
Guillem's avatar
Guillem committed
336
	  if ( S_AXI_ARESETN_i == 1'b0 )
bscuser's avatar
bscuser committed
337
338
	    begin : reset_all
        integer i;
Guillem's avatar
Guillem committed
339
        for (i=N_COUNTERS; i<TOTAL_REGS; i=i+1) slv_reg[i] <={C_S_AXI_DATA_WIDTH{1'b0}};
bscuser's avatar
bscuser committed
340
341
342
343
344
	    end 
	  else begin
	    if (slv_reg_wren)
	      begin : strobes
            integer i;
Guillem's avatar
Guillem committed
345
346
            integer write_address;
            /* verilator lint_off WIDTH */
347
348
            // Width mismatch between integer 32B and MSB due to aligment of 
            // addresses
Guillem's avatar
Guillem committed
349
350
351
            write_address = axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB];
            /* verilator lint_on WIDTH */
            
Guillem's avatar
Guillem committed
352
            for (i=N_COUNTERS; i<TOTAL_REGS; i=i+1)begin
Guillem's avatar
Guillem committed
353
                if (write_address == i) begin
bscuser's avatar
bscuser committed
354
                    for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
Guillem's avatar
Guillem committed
355
                      if ( S_AXI_WSTRB_i[byte_index] == 1 ) begin
bscuser's avatar
bscuser committed
356
                        // Respective byte enables are asserted as per write strobes 
Guillem's avatar
Guillem committed
357
                        slv_reg[i][(byte_index*8) +: 8] <= S_AXI_WDATA_i[(byte_index*8) +: 8];
bscuser's avatar
bscuser committed
358
359
360
                      end  
                end
            end
Guillem's avatar
Guillem committed
361
	      end else begin
Guillem's avatar
Guillem committed
362
363
          //here we do the "auto_update" of MCCU variables. Reset overwritten
          //values and update interruption vector
Guillem's avatar
Guillem committed
364
365
366
            if(MCCU!=0) begin
                //set the slv_reg of MCCU_quota_o in case someone has
                //overwritten it
Guillem's avatar
Guillem committed
367
368
                for(integer q=0; q< MCCU_N_CORES-1; q++) begin
                    slv_reg[BASE_MCCU_R_ONLY+q]<=MCCU_quota_o[q];
Guillem's avatar
Guillem committed
369
370
371
372
373
374
                end
                //set lower bits of MCCU main configuration back to 0. If this
                //is not reset to 0. MCCU will try to set the quota again and
                //quota will neve decrease. The first bit shall stay enabled
                //and the remaining are masked to 0 
                slv_reg[BASE_MCCU]<=slv_reg[BASE_MCCU] & {1'b1,{C_S_AXI_DATA_WIDTH-1{1'b0}}};
Guillem's avatar
Guillem committed
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
                //Request Duration Counter (RDC) logic. It needs to check if the MCCU
                //generates any interrupt and update the RDC interruption 
                //vector into the slv_register. Map in to slv_reg as in
                //example:
                
                //For 4 cores, 16 signals each, slv_register width 32 bit
                //Core ID, Signal ID, slv_reg     x         , slv_reg bit 
                //0      , 0        , BASE_MCCU_INTRV_RDC   , 0
                //0      , 15       , BASE_MCCU_INTRV_RDC   , 15
                //1      , 0        , BASE_MCCU_INTRV_RDC   , 16
                //1      , 15       , BASE_MCCU_INTRV_RDC   , 31
                //2      , 0        , BASE_MCCU_INTRV_RDC+1 , 0
                
                //TODO: Up to 16 signals per core are supported given the
                //current CDR interruption implementation. Signals per core
                //must be a power of two.
                `ifdef ASSERTIONS
                    assert (MCCU_N_CORES<17);
                    assert ((MCCU_N_CORES==1)  ||
                            (MCCU_N_CORES==2)  ||
                            (MCCU_N_CORES==8)  ||
                            (MCCU_N_CORES==16));
                `endif
                for(integer q=0; q< MCCU_N_CORES*MCCU_CORE_EVENTS; q++) begin
                   /*
                    automatic integer reg_index = (MCCU_N_CORES*MCCU_CORE_EVENTS)
                                        /C_S_AXI_DATA_WIDTH;
                    automatic integer current_slv_reg = BASE_MCCU_INTRV_RDC+reg_index;
                    automatic integer current_slv_bit = q-(reg_index*C_S_AXI_DATA_WIDTH);
                    //TODO: Solve iterators of this loop and check spyglass
                    automatic integer current_intrv_reg = q/MCCU_CORE_EVENTS;
                    automatic integer current_intrv_bit = q-(current_intrv_reg*MCCU_CORE_EVENTS);*/
                    slv_reg [BASE_MCCU_INTRV_RDC][q] <= 
                        intrv_rdc_int[q/MCCU_CORE_EVENTS][q-(q/MCCU_CORE_EVENTS*MCCU_CORE_EVENTS)];
                end
Guillem's avatar
Guillem committed
410
411
412
413
            end
            if(OVERFLOW==1) begin : generated_overflow
            //iterate over the registers, each one has one overflow bit
                    //When more than 32 counters, extra registers are needed
414
                    `ifdef ASSERTIONS
Guillem's avatar
Guillem committed
415
                        assert(N_COUNTERS < 33);
416
417
                    `endif
                for (integer j=0; j<N_COUNTERS; j=j+1) begin : overflow_bit
Guillem's avatar
Guillem committed
418
419
                    localparam integer OVERFLOW_REGS_OFFSET= N_COUNTERS+N_CONF_REGS;
                    automatic integer a = j/C_S_AXI_DATA_WIDTH;
Guillem's avatar
Guillem committed
420
                        if (rst_PMU) 
Guillem's avatar
Guillem committed
421
422
423
424
425
426
427
428
                            slv_reg[a+OVERFLOW_REGS_OFFSET]
                            <={C_S_AXI_DATA_WIDTH{1'b0}};
                        else if (slv_reg[j]=={C_S_AXI_DATA_WIDTH{1'b1}})
                                 slv_reg[a+OVERFLOW_REGS_OFFSET][j]<=1'b1;
                end
             end
          end
        end
bscuser's avatar
bscuser committed
429
430
431
432
	end    

	// Implement write response logic generation
	// The write response and response valid signals are asserted by the slave 
Guillem's avatar
Guillem committed
433
	// when axi_wready, S_AXI_WVALID_i, axi_wready and S_AXI_WVALID_i are asserted.  
bscuser's avatar
bscuser committed
434
435
436
	// This marks the acceptance of address and indicates the status of 
	// write transaction.

GuillemCabo's avatar
GuillemCabo committed
437
	always @( posedge S_AXI_ACLK_i)
bscuser's avatar
bscuser committed
438
	begin
Guillem's avatar
Guillem committed
439
	  if ( S_AXI_ARESETN_i == 1'b0 )
bscuser's avatar
bscuser committed
440
441
442
443
444
445
	    begin
	      axi_bvalid  <= 0;
	      axi_bresp   <= 2'b0;
	    end 
	  else
	    begin    
Guillem's avatar
Guillem committed
446
	      if (axi_awready && S_AXI_AWVALID_i && ~axi_bvalid && axi_wready && S_AXI_WVALID_i)
bscuser's avatar
bscuser committed
447
448
449
450
451
452
453
	        begin
	          // indicates a valid write response is available
	          axi_bvalid <= 1'b1;
	          axi_bresp  <= 2'b0; // 'OKAY' response 
	        end                   // work error responses in future
	      else
	        begin
Guillem's avatar
Guillem committed
454
	          if (S_AXI_BREADY_i && axi_bvalid) 
bscuser's avatar
bscuser committed
455
456
457
458
459
460
461
462
463
464
	            //check if bready is asserted while bvalid is high) 
	            //(there is a possibility that bready is always asserted high)   
	            begin
	              axi_bvalid <= 1'b0; 
	            end  
	        end
	    end
	end   

	// Implement axi_arready generation
Guillem's avatar
Guillem committed
465
466
	// axi_arready is asserted for one S_AXI_ACLK_i clock cycle when
	// S_AXI_ARVALID_i is asserted. axi_awready is 
bscuser's avatar
bscuser committed
467
	// de-asserted when reset (active low) is asserted. 
Guillem's avatar
Guillem committed
468
	// The read address is also latched when S_AXI_ARVALID_i is 
bscuser's avatar
bscuser committed
469
470
	// asserted. axi_araddr is reset to zero on reset assertion.

GuillemCabo's avatar
GuillemCabo committed
471
	always @( posedge S_AXI_ACLK_i)
bscuser's avatar
bscuser committed
472
	begin
Guillem's avatar
Guillem committed
473
	  if ( S_AXI_ARESETN_i == 1'b0 )
bscuser's avatar
bscuser committed
474
475
476
477
478
479
	    begin
	      axi_arready <= 1'b0;
	      axi_araddr  <= {C_S_AXI_ADDR_WIDTH{1'b0}};
	    end 
	  else
	    begin    
Guillem's avatar
Guillem committed
480
	      if (~axi_arready && S_AXI_ARVALID_i)
bscuser's avatar
bscuser committed
481
482
483
484
	        begin
	          // indicates that the slave has acceped the valid read address
	          axi_arready <= 1'b1;
	          // Read address latching
Guillem's avatar
Guillem committed
485
	          axi_araddr  <= S_AXI_ARADDR_i;
bscuser's avatar
bscuser committed
486
487
488
489
490
491
492
493
494
	        end
	      else
	        begin
	          axi_arready <= 1'b0;
	        end
	    end 
	end       

	// Implement axi_arvalid generation
Guillem's avatar
Guillem committed
495
496
	// axi_rvalid is asserted for one S_AXI_ACLK_i clock cycle when both 
	// S_AXI_ARVALID_i and axi_arready are asserted. The slave registers 
bscuser's avatar
bscuser committed
497
498
499
500
501
	// data are available on the axi_rdata bus at this instance. The 
	// assertion of axi_rvalid marks the validity of read data on the 
	// bus and axi_rresp indicates the status of read transaction.axi_rvalid 
	// is deasserted on reset (active low). axi_rresp and axi_rdata are 
	// cleared to zero on reset (active low).  
GuillemCabo's avatar
GuillemCabo committed
502
	always @( posedge S_AXI_ACLK_i)
bscuser's avatar
bscuser committed
503
	begin
Guillem's avatar
Guillem committed
504
	  if ( S_AXI_ARESETN_i == 1'b0 )
bscuser's avatar
bscuser committed
505
506
507
508
509
510
	    begin
	      axi_rvalid <= 0;
	      axi_rresp  <= 0;
	    end 
	  else
	    begin    
Guillem's avatar
Guillem committed
511
	      if (axi_arready && S_AXI_ARVALID_i && ~axi_rvalid)
bscuser's avatar
bscuser committed
512
513
514
515
516
	        begin
	          // Valid read data is available at the read data bus
	          axi_rvalid <= 1'b1;
	          axi_rresp  <= 2'b0; // 'OKAY' response
	        end   
Guillem's avatar
Guillem committed
517
	      else if (axi_rvalid && S_AXI_RREADY_i)
bscuser's avatar
bscuser committed
518
519
520
521
522
523
524
525
526
527
	        begin
	          // Read data is accepted by the master
	          axi_rvalid <= 1'b0;
	        end                
	    end
	end    

	// Implement memory mapped register select and read logic generation
	// Slave register read enable is asserted when valid address is available
	// and the slave is ready to accept the read address.
Guillem's avatar
Guillem committed
528
	assign slv_reg_rden = axi_arready & S_AXI_ARVALID_i & ~axi_rvalid;
bscuser's avatar
bscuser committed
529
530
531
532
	always @(*)
	begin :decode_read
	      // Address decoding for reading registers
	      integer i;
Guillem's avatar
Guillem committed
533
534
535
536
537
          // Address read as integer to avoid width mismatch
          integer read_address;
          /* verilator lint_off WIDTH */
          read_address = axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB];
          /* verilator lint_on WIDTH */
Guillem's avatar
Guillem committed
538
539
540
541
542
543
544
545
546
547
548
          
          reg_data_out ={C_S_AXI_DATA_WIDTH{1'b0}};
          //check if the address is out of the range of R registers
          if(read_address > 0 && read_address < TOTAL_REGS) begin
              for (i=0; i<TOTAL_REGS; i=i+1) begin
                if (read_address==i) begin
                    //TODO: I think W415a is alright here. There is a better
                    //way to do it?
                    reg_data_out =slv_reg[i];
                end
              end
bscuser's avatar
bscuser committed
549
          end
Guillem's avatar
Guillem committed
550
    end
bscuser's avatar
bscuser committed
551
	// Output register or memory read data
GuillemCabo's avatar
GuillemCabo committed
552
	always @( posedge S_AXI_ACLK_i)
bscuser's avatar
bscuser committed
553
	begin
Guillem's avatar
Guillem committed
554
	  if ( S_AXI_ARESETN_i == 1'b0 )
bscuser's avatar
bscuser committed
555
556
557
558
559
	    begin
	      axi_rdata  <= 0;
	    end 
	  else
	    begin    
Guillem's avatar
Guillem committed
560
	      // When there is a valid read address (S_AXI_ARVALID_i) with 
bscuser's avatar
bscuser committed
561
562
563
564
565
566
567
568
569
	      // acceptance of read address by the slave (axi_arready), 
	      // output the read dada 
	      if (slv_reg_rden)
	        begin
	          axi_rdata <= reg_data_out;     // register read data
	        end   
	    end
	end    

Guillem's avatar
Guillem committed
570
   
571
572
573
//-------------Adders with reset
    //Inside the generate loop it creates as many counters as the parameter
    //N_COUNTERS. For each of them one slv_reg is assigned. When a soft reset
Guillem's avatar
Guillem committed
574
    //(rst_PMU high) or hard reset (S_AXI_ARESETN_i) slv_registers are set
575
576
577
    //to 0. If non of this cases happen if the PMU is enabled (en_PMU high) and
    //the event of the given counter (events_i[k]) is high the counter
    // increases by one.
bscuser's avatar
bscuser committed
578
579
580
    genvar k;
    generate
    for (k=0; k<N_COUNTERS; k=k+1) begin : generated_counter
GuillemCabo's avatar
GuillemCabo committed
581
        always @(posedge S_AXI_ACLK_i) begin
Guillem's avatar
Guillem committed
582
583
584
            if(!S_AXI_ARESETN_i)
                slv_reg[k] <={C_S_AXI_DATA_WIDTH{1'b0}};
            else begin
Guillem's avatar
Guillem committed
585
                if(rst_PMU) slv_reg[k] <={C_S_AXI_DATA_WIDTH{1'b0}};
Guillem's avatar
Guillem committed
586
587
                else if(events_i[k] & en_PMU) slv_reg[k] <= slv_reg[k]+1;
            end
bscuser's avatar
bscuser committed
588
589
590
        end
    end
    endgenerate
591
592
593
594
595
596
597
598
//-------------Overflow
//TODO:
//this one may not be parametric if more than 32 counters are used
    //Here we generate the overflow signal for each one of the counters. 
    //One bit per counter is given in the overflow register. a accounts for
    //multiple 32 bit registers if needed.(slv_reg[a+OVERFLOW_REGS_OFFSET])
    //Overflow registers are placed after Counter and Configuration registers.
    //At hard or soft reset values are set to 0. 
Guillem's avatar
Guillem committed
599
600
601
602
603
604
605
    if(OVERFLOW==1) begin : generated_int_overflow
        always@(*) begin
                //TODO:multiple assigments (W415a) seems safe here 
                int_overflow_o = 0;
            //iterate over the registers, each one has one overflow bit
                for (integer j=0; j<N_COUNTERS; j=j+1) begin : overflow_bit
                    //When more than 32 counters, extra registers are needed
606
607
                    automatic integer OVERFLOW_REGS_OFFSET= N_COUNTERS+N_CONF_REGS;
                    automatic integer a = j/C_S_AXI_DATA_WIDTH;
Guillem's avatar
Guillem committed
608
                    int_overflow_o =(rst_PMU || (S_AXI_ARESETN_i == 1'b0))?
Guillem's avatar
Guillem committed
609
                                         1'b0: | slv_reg[a+OVERFLOW_REGS_OFFSET];
610
                end
Guillem's avatar
Guillem committed
611
612
613
614
            //decide the overflow register if there are more than 32 counters
            //if overflow set bit to 1
        end
    end else assign int_overflow_o = 1'b0;
615
616
617

//-------------Quota
    //TODO
Guillem's avatar
Guillem committed
618
    //instead of sum the 16 registers at the same time you could use a 
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
    //statemachine that sums two at a time. you will increase latency but less
    //hardware is required
    //64 bits for overflow are not needed

    //A quota consumption interruption is generated when a the total of 
    //measured events exceeds the value set in slv_reg[BASE_QUOTA+1].
    //To account for a given event a 1 must be set to the correspondent bit in
    //slv_reg[BASE_QUOTA][x]. (This register is refered as Quota mask)
    //When the mask is 0 the value is not accounted for the quota.
    //If the QUOTA local parameter is set to 0, int_quota_o will never trigger.
    genvar x;
    generate
        if(QUOTA==1) begin : generated_quota
            //from each register we take a wire 
            wire [C_S_AXI_DATA_WIDTH-1:0] values_count [0:N_COUNTERS-1];
            reg [63:0]suma;//64bits to avoid overflows
Guillem's avatar
Guillem committed
635
            longint tmp;
636
637
638
639
            for (x=0; x<N_COUNTERS; x=x+1) begin : check_mask
                //when reset is eneabled the values are 0. If not reset
                // check the mask and pass the value of the counter if enabled
                assign values_count[x]=
Guillem's avatar
Guillem committed
640
                        (rst_PMU || (S_AXI_ARESETN_i == 1'b0))
641
642
643
644
                        ?{C_S_AXI_DATA_WIDTH{1'b0}}:
                        {C_S_AXI_DATA_WIDTH{slv_reg[BASE_QUOTA][x]}}
                        &slv_reg[x];
            end
Guillem's avatar
Guillem committed
645
646
647
648
            //avoid width mismatch when dealing with 32b register addition
            localparam padding0 = 64-C_S_AXI_DATA_WIDTH;
            assign int_quota_o =(suma>{{padding0{1'b0}},slv_reg[BASE_QUOTA+1]})
                                ? 1'b1:1'b0;
649
            //Add quotas of all signals. The ones that are not enabled are 0
Guillem's avatar
Guillem committed
650
651
            integer y;
            //TODO: why I cant use the same genvar X. Instead of y?
652
653
            always @(*) begin
                    tmp =0;
Guillem's avatar
Guillem committed
654
655
                    for(y=0; y<N_COUNTERS; y=y+1)  begin: sum_quotas
                       tmp={{padding0{1'b0}},values_count[y]}+tmp;
656
657
658
659
660
                    end
                    suma=tmp;
            end
        end else assign int_quota_o =1'b0;
    endgenerate
Guillem's avatar
Guillem committed
661
662
663
664
665
666

//-------------MCCU instance and auxiliar logic
        //max cores == MCCU_DATA_WIDTH -1
    if(MCCU !=0) begin : generate_MCCU
        wire [MCCU_CORE_EVENTS-1:0] events_int [0:MCCU_N_CORES-1];
        wire MCCU_enable_int;
Guillem's avatar
Guillem committed
667
        wire MCCU_update_quota_int [0:MCCU_N_CORES-1];
Guillem's avatar
Guillem committed
668
        
Guillem's avatar
Guillem committed
669
        //first n bits (MCCU_N_CORES) set when the quota need to be updated.
Guillem's avatar
Guillem committed
670
671
672
673
674
675
676
677
678
679
680
681
        //The update_quota_int needs to be  reset after one cycle. IF
            // not the counter will not decrease.
            // This module maps the bits of the slave registers to the unpack wire
            // that connects with the MCCU to trigger an update of the quota
            //The update only at rise can be done here with some temporal
            //registers that check when the slv_register as changed, but it
            //will need to check as well if there is a new write every time,
            //not only the changes in slv_reg. I have prefered to reset the
            //lower bits of slv_reg[BASE_MCCU] to 0 every time the register is
            //not written. To prevent problems with multidriven signals we
            //shall check the AXI_LITE state machines
            
Guillem's avatar
Guillem committed
682
683
684
            //Addres where the  base configuration register is located
            //current write address
        genvar i; 
Guillem's avatar
Guillem committed
685
686
687
688
689
        for (i=0;i<MCCU_N_CORES;i=i+1) begin
            assign MCCU_update_quota_int[i] = slv_reg[BASE_MCCU][i];
        end 
        //last bit of the  first register in the MCCU region is the enable
        assign MCCU_enable_int = slv_reg[BASE_MCCU][MCCU_DATA_WIDTH-1];
Guillem's avatar
Guillem committed
690
691
692
693
        //penultimate bit of the  first register in the MCCU region does soft 
        //reset of MCCU registers
        wire MCCU_rstn_int; 
        assign MCCU_rstn_int = ~slv_reg[BASE_MCCU][MCCU_DATA_WIDTH-2];
Guillem's avatar
Guillem committed
694
        //Map interesting signals to MCCU
Guillem's avatar
Guillem committed
695
696
697
698
699
700
701
702
703
704
        //TODO: Each new instance needs to be tweaked here. Depending on the
        //SOC you may want to route the signals differently for events_int
        for(i = 0; i<MCCU_N_CORES; i++) begin
            assign events_int[i] = {
                                    events_i[0+i]
                                    ,events_i[1+i]
                                    ,events_i[2+i]
                                    ,events_i[3+i]
            };
        end
Guillem's avatar
Guillem committed
705
706
707
708
709
710
711
712
713
714
715
716
717
       
        
        //Map slv_regs that control the quota in to the MCCCU
        wire [MCCU_DATA_WIDTH-1:0] MCCU_quota_int [ 0: MCCU_N_CORES-1];
        //TODO: this is not parametric. if more than one config register is
        //needed for MCCU this need to be changed. Parametrize this in the
        //futute
        localparam OFFSET_MCCU_CONFIG = 1;
        for (i=0;i<MCCU_N_CORES;i=i+1) begin
            assign MCCU_quota_int[i] = slv_reg[BASE_MCCU + 
                                                      OFFSET_MCCU_CONFIG+i];
        end 
         
Guillem's avatar
Guillem committed
718
719
720
        //map slv_reg s to events_weights_i. Weight size shall be a power of
        //2 an smaller than MCCU_DATA_WIDTH. This constrain can be overcome
        //with a mechanism "align" the weights of the registers in hardware but
Guillem's avatar
Guillem committed
721
722
723
724
725
726
727
728
729
730
731
732
        `ifdef ASSERTIONS
             //we will skip it for now And assume that MCCU_DATA_WIDTH is
             //always aligned
             //TODO: handele misaligment aligments and remove this constrains 
            always@(*) begin
            assert (
                    (MCCU_DATA_WIDTH!=4) 
                    ||(MCCU_DATA_WIDTH!=8) 
                    || (MCCU_DATA_WIDTH!=16) 
                    || (MCCU_DATA_WIDTH!=32);
            end
        `endif
Guillem's avatar
Guillem committed
733
734
        
        //Nº of the slv_register where weights start
Guillem's avatar
Guillem committed
735
        localparam OFFSET_MCCU_WEIGHTS = OFFSET_MCCU_CONFIG + MCCU_N_CORES;
Guillem's avatar
Guillem committed
736
        //Nº of bits required to store all weights
Guillem's avatar
Guillem committed
737
738
        localparam TOTAL_WEIGHT_BITS = MCCU_CORE_EVENTS * MCCU_N_CORES
                                       * MCCU_WEIGHTS_WIDTH; 
Guillem's avatar
Guillem committed
739
        //Single wire array with the values of the weights
Guillem's avatar
Guillem committed
740
741
742
743
744
745
746
747
748
749
750
751
752
        wire [TOTAL_WEIGHT_BITS-1:0] weights_flat_bitarray;
        for (i=0;i<MCCU_CORE_EVENTS*MCCU_N_CORES;i=i+1) begin : slv_reg_to_flat_bitarray
            //Track the Nº of bits used by the weight registers until this
            //iteration of the loop
            localparam USED_BITS = (i+1)*MCCU_WEIGHTS_WIDTH;
            //Track the Nº of registers that weights ocuppy based on DATA_WIDTH
            //WEIGHTS_WIDTH and iteration
            localparam USED_REGISTERS = ((USED_BITS % MCCU_DATA_WIDTH)>0) ?
                                        USED_BITS/MCCU_DATA_WIDTH+1 : 
                                        USED_BITS/MCCU_DATA_WIDTH;
            //Rename local parameter for clarify  assignation
            localparam CURRENT_REG_OFFSET = USED_REGISTERS; 
            //Offset of the weights you are assigning in  this iteration for
Guillem's avatar
Guillem committed
753
            //the weights_flat_bitarray. 
Guillem's avatar
Guillem committed
754
755
756
757
758
            localparam ARRAY_BIT_OFFSET_H = USED_BITS-1;
            localparam ARRAY_BIT_OFFSET_L = (USED_BITS
                                            -MCCU_WEIGHTS_WIDTH);
            
            //If ARRAY_BIT_OFFSET_H exceeds the first slv_reg size we have
Guillem's avatar
Guillem committed
759
            //to wrap the indexes.
Guillem's avatar
Guillem committed
760
761
762
763
764
            localparam int SLV_BIT_OFFSET_H = ARRAY_BIT_OFFSET_H 
                                                % MCCU_DATA_WIDTH; 
            localparam int SLV_BIT_OFFSET_L = ARRAY_BIT_OFFSET_L 
                                                % MCCU_DATA_WIDTH;
            `ifdef ASSERTIONS
Guillem's avatar
Guillem committed
765
            always@(*) begin
Guillem's avatar
Guillem committed
766
767
                // If the registers can not fit one weigth this design is not
                // valid
Guillem's avatar
Guillem committed
768
769
                assert(MCCU_DATA_WIDTH>=MCCU_WEIGHTS_WIDTH);
                assert(SLV_BIT_OFFSET_H>SLV_BIT_OFFSET_L);
Guillem's avatar
Guillem committed
770
                //right now the weights shall be always aligned
Guillem's avatar
Guillem committed
771
            end
Guillem's avatar
Guillem committed
772
773
            `endif
            //If weight is not misaligned
Guillem's avatar
Guillem committed
774
            if(SLV_BIT_OFFSET_H>SLV_BIT_OFFSET_L) begin : aligned_weight
Guillem's avatar
Guillem committed
775
776
777
                assign weights_flat_bitarray[ARRAY_BIT_OFFSET_H
                                            :ARRAY_BIT_OFFSET_L]
                                            =
Guillem's avatar
Guillem committed
778
779
                                            slv_reg [CURRENT_REG_OFFSET 
                                            + BASE_MCCU + N_CORES]
Guillem's avatar
Guillem committed
780
                                           [SLV_BIT_OFFSET_H:SLV_BIT_OFFSET_L];
Guillem's avatar
Guillem committed
781
            end 
Guillem's avatar
Guillem committed
782
        end 
Guillem's avatar
Guillem committed
783
784
785
786
787
788
789
790
        //rearrange weights to match events_weights_i
        wire [MCCU_WEIGHTS_WIDTH-1:0] MCCU_events_weights_int [0:MCCU_N_CORES-1]
                                                       [0:MCCU_CORE_EVENTS-1];
        //genvar x;
        for(x=0;x<MCCU_N_CORES;x++) begin
            genvar y;
            for(y=0;y<MCCU_CORE_EVENTS;y++) begin
                //calculate the indexes in the flat bitarray
Guillem's avatar
Guillem committed
791
792
                localparam LOW_INDEX = (x*MCCU_CORE_EVENTS*MCCU_WEIGHTS_WIDTH)+(y*MCCU_WEIGHTS_WIDTH);
                localparam HIGH_INDEX = (((x*MCCU_CORE_EVENTS*MCCU_WEIGHTS_WIDTH)+((y+1)*MCCU_WEIGHTS_WIDTH))-1);
Guillem's avatar
Guillem committed
793
                assign MCCU_events_weights_int [x][y] = weights_flat_bitarray
Guillem's avatar
Guillem committed
794
                                                        [HIGH_INDEX:LOW_INDEX]; 
Guillem's avatar
Guillem committed
795
796
            end
        end
Guillem's avatar
Guillem committed
797
798
799
800
801
802
803
        MCCU # (
            // Width of data registers
            .DATA_WIDTH     (MCCU_DATA_WIDTH),
            // Width of weights registers
            .WEIGHTS_WIDTH  (MCCU_WEIGHTS_WIDTH),
            //Cores. Change this may break Verilator TB
            .N_CORES        (MCCU_N_CORES),
GuillemCabo's avatar
GuillemCabo committed
804
805
            //Fault Tolerance
            .FT(0),
Guillem's avatar
Guillem committed
806
807
808
809
810
            //Signals per core. Change this may break Verilator TB
            .CORE_EVENTS    (MCCU_CORE_EVENTS)
        )
        inst_MCCU(
            .clk_i                  (S_AXI_ACLK_i),
Guillem's avatar
Guillem committed
811
            .rstn_i                 (S_AXI_ARESETN_i || MCCU_rstn_int),
Guillem's avatar
Guillem committed
812
            .enable_i               (MCCU_enable_int),// Software map
Guillem's avatar
Guillem committed
813
814
815
816
            .events_i               (events_int),//how to parametrize this? new parameter on top or up to the programer that does the integration?
            .quota_i                (MCCU_quota_int),//One register per core
            .update_quota_i         (MCCU_update_quota_int),//Software map
            .quota_o                (MCCU_quota_o),//write back to a read register
GuillemCabo's avatar
GuillemCabo committed
817
818
            .intr_FT1_o(),
            .intr_FT2_o(),
Guillem's avatar
Guillem committed
819
            .events_weights_i       (MCCU_events_weights_int),//core_events times WEIGHTS_WIDTH registers
Guillem's avatar
Guillem committed
820
821
822
            .interruption_quota_o   (MCCU_int_o)//N_CORES output signals Add this to top or single toplevel interrupt and an interrupt vector that identifies the source?
                                       // Individual interrupts allow each core to
                                       // handle their own interrupts , therefore
Guillem's avatar
Guillem committed
823
824
825
826
827
                                       //it seems to be te right solution.
        );

        //Request Duration Counter (RDC)
        //TODO: events_int is not the group of signals you actually need
Guillem's avatar
Guillem committed
828
        RDC #(
Guillem's avatar
Guillem committed
829
830
831
832
833
834
835
836
            // Width of data registers
            .DATA_WIDTH     (MCCU_DATA_WIDTH),
            // Width of weights registers
            .WEIGHTS_WIDTH  (MCCU_WEIGHTS_WIDTH),
            //Cores. 
            .N_CORES        (MCCU_N_CORES),
            //Signals per core. 
            .CORE_EVENTS    (MCCU_CORE_EVENTS)
Guillem's avatar
Guillem committed
837
        ) inst_RDC(
Guillem's avatar
Guillem committed
838
839
840
841
842
843
            .clk_i                  (S_AXI_ACLK_i),
            .rstn_i                 (S_AXI_ARESETN_i || MCCU_rstn_int ),
            .enable_i               (MCCU_enable_int),// Software map
            .events_i               (events_int),//how to parametrize this? new parameter on top or up to the programer that does the integration?
            .events_weights_i       (MCCU_events_weights_int),//core_events times WEIGHTS_WIDTH registers
            .interruption_rdc_o(intr_rdc_o),// interruption signaling a signal has exceed the expected maximum request time
GuillemCabo's avatar
GuillemCabo committed
844
            .watermark_o(),
Guillem's avatar
Guillem committed
845
846
847
848
            .interruption_vector_rdc_o(intrv_rdc_int) // vector with offending
                //signals. One hot encoding.
                //Cleared when MCCU is disabled.
        );
Guillem's avatar
Guillem committed
849
850
851
852
853
854
855
856
    end else begin
        //TODO: what happen if i is an integer instead of a genvar?
        genvar i;
        //drive interrupts to 0 if no MCCU to prevent problems
        for (i=0;i<MCCU_N_CORES;i=i+1) begin
            assign MCCU_int_o[i] = 1'b0;
        end
    end
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef	FORMAL
localparam	F_LGDEPTH = 4;

	wire	[(F_LGDEPTH-1):0]	f_axi_awr_outstanding,
					f_axi_wr_outstanding,
					f_axi_rd_outstanding;
	// Connect our slave to the AXI-lite property set
	//
	faxil_slave #(  .C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
			.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH),
			.F_LGDEPTH(F_LGDEPTH)) properties(
		.i_clk(S_AXI_ACLK_i),
		.i_axi_reset_n(S_AXI_ARESETN_i),
		//
		.i_axi_awaddr(S_AXI_AWADDR_i),
		.i_axi_awcache(4'h0),
		.i_axi_awprot(1'b0),
		.i_axi_awvalid(S_AXI_AWVALID_i),
		.i_axi_awready(S_AXI_AWREADY_o),
		//
		.i_axi_wdata(S_AXI_WDATA_i),
		.i_axi_wstrb(S_AXI_WSTRB_i),
		.i_axi_wvalid(S_AXI_WVALID_i),
		.i_axi_wready(S_AXI_WREADY_o),
		//
		.i_axi_bresp(S_AXI_BRESP_o),
		.i_axi_bvalid(S_AXI_BVALID_o),
		.i_axi_bready(S_AXI_BREADY_i),
		//
		.i_axi_araddr(S_AXI_ARADDR_i),
		.i_axi_arprot(1'b0),
		.i_axi_arcache(4'h0),
		.i_axi_arvalid(S_AXI_ARVALID_i),
		.i_axi_arready(S_AXI_ARREADY_o),
		//
		.i_axi_rdata(S_AXI_RDATA_o),
		.i_axi_rresp(S_AXI_RRESP_o),
		.i_axi_rvalid(S_AXI_RVALID_o),
		.i_axi_rready(S_AXI_RREADY_i),
		//
		.f_axi_rd_outstanding(f_axi_rd_outstanding),
		.f_axi_wr_outstanding(f_axi_wr_outstanding),
		.f_axi_awr_outstanding(f_axi_awr_outstanding));
`endif

bscuser's avatar
bscuser committed
907
endmodule
908

Guillem's avatar
Guillem committed
909
`default_nettype wire //allow compatibility with legacy code and xilinx ip
bscuser's avatar
bscuser committed
910