Commit 9ff17bdf authored by Guillem's avatar Guillem
Browse files

dummy ahb module

no burst supported
parent 4de6060f
//-----------------------------------------------------
// ProjectName: LEON3_kc705_pmu
// Function : Submodule of the PMU to handle counters
// Description: This module is contains the adders and registers for the PMU
// the registers are exposed through the interface to the modules
// other modules of the PMU and passed through to the PMU wrapper
// through the module PMU_raw
//
// Coder : G.Cabo
// References :
`default_nettype none
`timescale 1 ns / 1 ps
`ifndef SYNT
`ifdef FORMAL
`define ASSERTIONS
`endif
`endif
module PMU_counters #
(
// Width of registers data bus
parameter integer REG_WIDTH = 32,
// Amount of counters
parameter integer N_COUNTERS = 9
)
(
// Global Clock Signal
input wire clk_i,
// Global Reset Signal. This Signal is Active LOW
input wire rstn_i,
// Soft Reset Signal from configuration registeres. This Signal is
// Active HIGH
input wire softrst_i,
// Enable Signal from configuration registeres. This Signal is
// Active HIGH
input wire en_i,
// Write enable signal. When this signal is high any value in regs_i
// is feed in to the internal registers. The Wrapper has to ensure
// that the propper values are feeded in.
// rst_i and softrst_i, have priority over we_i.
//TODO: Consider if is worth adding acces to individual registers
input wire we_i,
// Input/output wire from registers of the wrapper to PMU_raw internal
// registers
input wire [REG_WIDTH-1:0] regs_i [0:N_COUNTERS-1],
output wire [REG_WIDTH-1:0] regs_o [0:N_COUNTERS-1],
//external signals from Soc events
input wire [N_COUNTERS-1:0] events_i
);
reg [REG_WIDTH-1:0] slv_reg [0:N_COUNTERS-1] /*verilator public*/;
//-------------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
//(softrst_i high) or hard reset (rstn_i) slv_registers are set
//to 0. If non of this cases happen if the PMU is enabled (en_i high) and
//the event of the given counter (events_i[k]) is high the counter
// increases by one.
always @(posedge clk_i, negedge rstn_i) begin
integer i;
if(rstn_i == 1'b0 ) begin
for (i=0; i<N_COUNTERS; i=i+1) begin
slv_reg[i] <={REG_WIDTH{1'b0}};
end
end else begin
for (i=0; i<N_COUNTERS; i=i+1) begin
if(softrst_i) slv_reg[i] <={REG_WIDTH{1'b0}};
else if (we_i) slv_reg <= regs_i;
else if(events_i[i] & en_i) slv_reg[i] <= slv_reg[i]+1;
end
end
end
//Map input and output registers
assign regs_o = slv_reg;
//TODO: fill formal propperties
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
`endif
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
//-----------------------------------------------------
// ProjectName: LEON3_kc705_pmu
// Function : Submodule of the PMU to handle overflow of counters
// Description: This module checks the bus of reg_o coming out of the counters
// module. It trigger the signal of overflow when all the bits of
// a given bus are high.
//
// The counters in the bus have one bit map in to the overflow
// interrupt mask. The index of the counter and the bit in the
// mask register is the same.
//
// Coder : G.Cabo
// References :
`default_nettype none
`timescale 1 ns / 1 ps
`ifndef SYNT
`ifdef FORMAL
`define ASSERTIONS
`endif
`endif
module PMU_overflow #
(
// Width of counters registers
parameter integer REG_WIDTH = 32,
// Amount of counters
parameter integer N_COUNTERS = 9
)
(
// Global Clock Signal
input wire clk_i,
// Global Reset Signal. This Signal is Active LOW
input wire rstn_i,
// Soft Reset Signal from configuration registeres. This Signal is
// Active HIGH
input wire softrst_i,
// Enable Signal from configuration registeres. This Signal is
// Active HIGH
input wire en_i,
// Input wire from wrapper containing the values of the counters
input wire [REG_WIDTH-1:0] counter_regs_i [0:N_COUNTERS-1],
// Input overflow interrupt mask. Only counters with their corresponding
// mask interrupt set to high can trigger the overflow interrupt
// If the mask is set to 0, the interrupt vector mask will not be
// updated either
input wire [N_COUNTERS-1:0] over_intr_mask_i,
// Global interrupt overflow
output wire intr_overflow_o,
// Output of the Overflow interruption vector
output wire [N_COUNTERS-1:0] over_intr_vect_o
);
//-------------Overflow
//OR reduction to detect overflow of each counter
wire overflow [0:N_COUNTERS-1];
genvar i;
generate
for (i=0; i<N_COUNTERS; i=i+1) begin : OR_reduction_counters
assign overflow[i]=|counter_regs_i[i];
end
endgenerate
//check the mask for the overflow signals
wire [N_COUNTERS-1:0] masked_overflow ;
generate
for (i=0; i<N_COUNTERS; i=i+1) begin : masking_overflow
assign masked_overflow[i]=overflow[i] & over_intr_mask_i[i];
end
endgenerate
//AND overflow and mask for each counter and OR reduc
wire intr_overflow_int;
assign intr_overflow_int=|masked_overflow;
//Drive output interrupt
assign intr_overflow_o = intr_overflow_int;
//Set overflow internal interruption vector
reg [N_COUNTERS-1:0] over_intr_vect_int;
always_ff @(posedge clk_i, negedge rstn_i) begin
integer i;
if(rstn_i == 1'b0 ) begin
over_intr_vect_int <={N_COUNTERS{1'b0}};
end else begin
if(softrst_i) over_intr_vect_int <={N_COUNTERS{1'b0}};
else if(en_i) begin
over_intr_vect_int <=masked_overflow;
end
end
end
//Drive output overflow interruption vector
assign over_intr_vect_o = over_intr_vect_int;
//TODO: fill formal propperties
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
`endif
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
//-----------------------------------------------------
// ProjectName: LEON3_kc705_pmu
// Function : Submodule of the PMU to handle quota consumption of a single
// core.
// Description: This module checks the content of the counters selected by the
// mask register. The value of the selected counters is added and
// compared against the quota limit register. If the total quota
// is exceeded then an interrupt is risen.
//
// To account for a given event a 1 must be set to the Quota mask
// register. When the mask is 0 the value is not accounted for the
// quota.
//
// The adition of counters is sequential, therefore you could
// notice up to N cycles (where N is the number of counters
// ) from the point that the quota is exceeded until the point
// where the interrupt is risen.
//
// Coder : G.Cabo
// References :
`default_nettype none
`timescale 1 ns / 1 ps
`ifndef SYNT
`ifdef FORMAL
`define ASSERTIONS
`endif
`endif
module PMU_quota #
(
// Width of counters registers
parameter integer REG_WIDTH = 32,
// Amount of counters
parameter integer N_COUNTERS = 9,
//Localparameters
localparam max_width = $clog2(N_COUNTERS)+REG_WIDTH
)
(
// Global Clock Signal
input wire clk_i,
// Global Reset Signal. This Signal is Active LOW
input wire rstn_i,
// Input wire from wrapper containing the values of the counters
input wire [REG_WIDTH-1:0] counter_value_i [0:N_COUNTERS-1],
// Soft Reset Signal from configuration registeres. This Signal is
// Active HIGH
input wire softrst_i,
// Input wire from wrapper with the maximum allowed quota consumption
//Quota is calculated with the
//sum_all_counters (counter_value_i[n] * counter_quota_mask_i[n])
input wire [max_width-1:0] quota_limit_i,
// Input quota interrupt mask. Only counters with their corresponding
// mask interrupt set to high can be added to compute towards the
// total quota that triggers the interrupt
input wire [N_COUNTERS-1:0] quota_mask_i,
// Interrupt quota
output wire intr_quota_o
);
//-------------Quota
//A quota consumption interruption is generated when the total of
//measured events exceeds the value set in quota_limit_i.
//To account for a given event a 1 must be set to the correspondent bit in
//quota_mask_i.
//When the mask is 0 the value is not accounted for the quota.
// Maximum width of counter to prevent overflow given the addition of N
//values of fix width
// Mask counter values that are disabled
wire [REG_WIDTH-1:0] masked_counter_value_int [0:N_COUNTERS-1];
genvar x;
generate
//mask counter values
for (x=0; x<N_COUNTERS; x=x+1) begin : mask_counters
//when reset is eneabled the values are 0. If not reset
// check the mask and pass the value of the counter if enabled
assign masked_counter_value_int[x]=
(softrst_i || (rstn_i == 1'b0))
? {REG_WIDTH{1'b0}} : {REG_WIDTH{quota_mask_i[x]}} & counter_value_i[x];
end
endgenerate
//Add values of all the masked signals sequentially
// state_int shall jump to reset state if the mask changes
wire new_mask;
reg [N_COUNTERS-1:0] old_mask;
always_ff @(posedge clk_i, negedge rstn_i) begin
if(rstn_i == 1'b0 ) begin
old_mask <= {N_COUNTERS{1'b0}};
end else if(softrst_i) begin
old_mask <= {N_COUNTERS{1'b0}};
end else begin
old_mask <= quota_mask_i;
end
end
assign new_mask = old_mask != quota_mask_i ? 1'b1: 1'b0;
//generate a freespining counter to add values masked registers
//State 0 = Reset suma_int
//State 1 = Add counter 0 + Suman_int
// ...
//State n = Add counter n + Suman_int
//State 0 = Reset suma_int
// ...
localparam n_states = $clog2(N_COUNTERS+1);
reg [n_states-1:0] state_int;
always_ff @(posedge clk_i, negedge rstn_i) begin
integer i;
if(rstn_i == 1'b0 ) begin
state_int <={n_states{1'b0}};
end else if(softrst_i || new_mask) begin
state_int <={n_states{1'b0}};
end else begin
state_int <= state_int + 1 ;
end
end
// One state per counter + reset state -> $clog2(N_COUNTERS+1)
//TODO: I dont fully understand the difference between
//A : end else if (clk_i && !rstn_i) begin
//B : end else if (clk_i) begin
// B will throw the following spyglass error.
// [10] STARC05-1.3.1.3 AsyncResetOtherUse Warning
// ./PMU_quota.sv 90 10 Asynchronous reset signal
// 'PMU_quota.rstn_i' (flop: 'PMU_quota.old_mask[0]') used as
// non-reset/synchronous-reset at instance
// 'PMU_quota.\suma_int_reg[35] .D'
// (File Name: './PMU_quota.sv' ,Line no.: '136')
localparam padding0 = max_width - REG_WIDTH;
reg [max_width-1:0] suma_int;
always_ff @(posedge clk_i, negedge rstn_i) begin
integer i;
if(rstn_i == 1'b0 ) begin
suma_int <={max_width{1'b0}};
end else if(softrst_i) begin
suma_int <={max_width{1'b0}};
end else if (clk_i && !rstn_i) begin
if(new_mask) begin
suma_int <={max_width{1'b0}};
end else begin
suma_int <= suma_int + {{padding0{1'b0}},masked_counter_value_int[state_int]};
end
end
end
//Check if quota is exceeded and generate interrupt
assign intr_quota_o = (suma_int > quota_limit_i )
? 1'b1 : 1'b0;
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
`endif
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
//-----------------------------------------------------
// ProjectName: LEON3_kc705_pmu
// Function : Integrate a register bank and AHB-lite interface
// Description: AHB-lite interface implementation of a register bank
//
// This module is responsible managing reads and writes from a
// AHB master and sets internal registers
//
// Coder : G.Cabo
// References : AMBA 3 AHB-lite specifications
// ARM IHI 0033A
// Notes :
`default_nettype none
`timescale 1 ns / 1 ps
`ifndef SYNT
`ifdef FORMAL
`define ASSERTIONS
`endif
`endif
module dummy_ahb #
(
parameter haddr = 0,
parameter hmask = 0,
// Total amount of registers
parameter integer N_REGS = 10,
// Width of registers data bus
parameter integer REG_WIDTH = 32,
//haddr width
localparam integer HADDR_WIDTH = 32,
//hdata width
localparam integer HDATA_WIDTH = 32
)
(
input wire rstn_i,
input wire clk_i,
// -- AHB bus slave interface
// slave select
input wire hsel_i,
// previous transfer done
input wire hreadyi_i,
// 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
output wire [HDATA_WIDTH-1:0] hrdata_o
// full AHB signals
// current master
// input wire [3:0] hmaster_i,
// split completion
// output wire [15:0] hsplit_o
);
//----------------------------------------------
//------------- Local parameters
//----------------------------------------------
// ** 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{
logic select;
logic write;
logic master_ready;
logic [HADDR_WIDTH-1:0] master_addr;
logic [HDATA_WIDTH-1:0] master_data;
logic [1:0] trans_type;
logic [2:0] trans_size;
logic [2:0] burst_type;
logic [3:0] protection;
logic lock;
} address_phase;
/* //TODO: clean up
var struct packed{
logic slave_ready;
logic [1:0] slave_resp;
logic [HDATA_WIDTH-1:0] slave_data;
} data_phase;
*/
//----------------------------------------------
//------------- AHB registers
//----------------------------------------------
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];
assign slv_reg_Q = slv_reg;
always_ff @(posedge clk_i, negedge rstn_i) begin
if(rstn_i == 1'b0 ) begin
slv_reg<='{default:0};
end else begin
slv_reg <= slv_reg_D;
end
end
//----------------------------------------------
//------------- AHB control logic
//----------------------------------------------
logic [1:0] state, next;
// address phase - state update
always_comb begin
case (htrans_i)
TRANS_IDLE: begin
next = TRANS_IDLE;
end
TRANS_BUSY:begin
next = TRANS_BUSY;
end
TRANS_NONSEQUENTIAL:begin
if(!hsel_i) begin
next = TRANS_IDLE;
end else begin
next = TRANS_NONSEQUENTIAL;
end
end
TRANS_SEQUENTIAL:begin
if(!hsel_i) begin
next = TRANS_IDLE;
end else begin
next = TRANS_SEQUENTIAL;
end
end
endcase
end
// address phase - register required inputs
always_ff @(posedge clk_i, negedge rstn_i) begin
if(rstn_i == 1'b0 ) begin
//initialize all the structure to 0 at reset
address_phase <= '{default:0};
end else begin
case (next)
TRANS_IDLE:begin
address_phase.select <= hsel_i;
address_phase.write <= hwrite_i;
end
TRANS_BUSY:begin
address_phase.select <= hsel_i;
address_phase.write <= hwrite_i;
end
TRANS_NONSEQUENTIAL:begin
address_phase.select <= hsel_i;
address_phase.write <= hwrite_i;
address_phase.master_ready <= hreadyi_i;
address_phase.master_addr <= haddr_i;
// address_phase.master_data <= hwdata_i;
address_phase.trans_type <= htrans_i;
//address_phase.trans_size <= hsize_i;
//address_phase.burst_type <= hburst_i;
//address_phase.protection <= hprot_i;
//address_phase.lock <= hmastlock_i;
end
TRANS_SEQUENTIAL:begin
address_phase.select <= hsel_i;
address_phase.write <= hwrite_i;
address_phase.master_ready <= hreadyi_i;
address_phase.master_addr <= haddr_i;
// address_phase.master_data <= hwdata_i;
address_phase.trans_type <= htrans_i;
//address_phase.trans_size <= hsize_i;
//address_phase.burst_type <= hburst_i;
//address_phase.protection <= hprot_i;
//address_phase.lock <= hmastlock_i;
end
endcase
end
end
//data phase - state update
always_ff @(posedge clk_i, negedge rstn_i) begin
if(rstn_i == 1'b0 ) begin
state<=TRANS_IDLE;
end else begin
state <= next;
end
end
//data phase - slave response
wire [$clog2(N_REGS)-1:0] slv_index;
logic [HDATA_WIDTH-1:0] dwrite_slave; //Data master to the register bank
assign slv_index = address_phase.master_addr[$clog2(N_REGS)+1:2];
logic [1:0] complete_transfer_status;
logic [HDATA_WIDTH-1:0] dread_slave; //response from slave
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]}};
//TODO: review
//dread_slave and dwrite_slave can be latched
//They will be ignored by the master and slave registers
always_latch begin
case (state)
TRANS_IDLE: begin
complete_transfer_status = TRANSFER_SUCCESS_COMPLETE;
end
TRANS_BUSY:begin
complete_transfer_status = TRANSFER_SUCCESS_COMPLETE;
end
TRANS_NONSEQUENTIAL:begin
complete_transfer_status = TRANSFER_SUCCESS_COMPLETE;
dwrite_slave = hwdata_i;
if (!address_phase.write) begin
dread_slave = slv_reg_Q[slv_index];
end
end
TRANS_SEQUENTIAL:begin
complete_transfer_status = TRANSFER_SUCCESS_COMPLETE;