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

WIP ahb pmu

parent 4e29a902
...@@ -49,7 +49,7 @@ module PMU_quota # ...@@ -49,7 +49,7 @@ module PMU_quota #
// Input wire from wrapper with the maximum allowed quota consumption // Input wire from wrapper with the maximum allowed quota consumption
//Quota is calculated with the //Quota is calculated with the
//sum_all_counters (counter_value_i[n] * counter_quota_mask_i[n]) //sum_all_counters (counter_value_i[n] * counter_quota_mask_i[n])
wire [max_width-1:0] quota_limit_i, input wire [max_width-1:0] quota_limit_i,
// Input quota interrupt mask. Only counters with their corresponding // Input quota interrupt mask. Only counters with their corresponding
// mask interrupt set to high can be added to compute towards the // mask interrupt set to high can be added to compute towards the
// total quota that triggers the interrupt // total quota that triggers the interrupt
......
//-----------------------------------------------------
// ProjectName: LEON3_kc705_pmu
// Function : Integrate PMU features under one module
// Description: Interface agnostic implementation of the PMU. Values of the
// PMU are registered in this module.
//
// This module is responsible of configure the memory map, handle
// write / read syncronization with a higher level module that
// integrates standar bus interfaces such as AXI, AHB or wishbone.
//
// Parametrization of the features is configured here by
// replicating instances of features and adjusting basic
// parameters such as counters width.
//
// Coder : G.Cabo
// References : Implementation of Maximum-Contention Control Unit (MCCU):
// ResourceAccess Count and Contention Time Enforcement.
// https://upcommons.upc.edu/handle/2117/133656
`default_nettype none
`timescale 1 ns / 1 ps
`ifndef SYNT
`ifdef FORMAL
`define ASSERTIONS
`endif
`endif
module PMU_raw #
(
// Width of registers data bus
parameter integer REG_WIDTH = 32,
// Width of registers IDs
parameter integer REG_ID_WIDTH = 5,
// Amount of counters
parameter integer N_COUNTERS = 9,
// Configuration registers
parameter integer N_CONF_REGS = 1,
// Overflow
parameter integer OVERFLOW = 0, //Yes/No
// Quota
parameter integer QUOTA = 0, //Yes/No
// MCCU - Maximum-contention Control Unit mode
parameter integer MCCU = 0, //Yes/No
// MCCU - N_CORES
parameter integer N_CORES = 1,
//
parameter integer TOTAL_NREGS = N_COUNTERS + N_CONF_REGS
)
(
/* //interruptions risen when one event exceeds it expected max duration
output wire int_rdc_o,
//interruptions risen when cores exceeds the quota of MCCU
output wire MCCU_int_o [N_CORES-1:0],
//interruption rises when one of the counters overflows
output reg int_overflow_o,
//interruption rises when the total of cuota consumed is exceeded
output wire int_quota_o,
//external signals from Soc events
input wire [N_COUNTERS-1:0] events_i, // bus of signals for counters
// Global Clock Signal
input wire clk_i,
// Global Reset Signal. This Signal is Active LOW
input wire rstn_i,
// Input/output wire from registers of the wrapper to PMU_raw internal
// registers
input wire [REG_WIDTH-1:0] regs_i [0:TOTAL_NREGS-1],
output wire [REG_WIDTH-1:0] regs_o [0:TOTAL_NREGS-1],
// Wrapper writte enable
input wire wrapper_we_i,
// Wrapper writte addres
input wire [REG_ID_WIDTH-1:0] wrapper_wa_i
*/
);
//----------------------------------------------
//------------- Counters instance
//----------------------------------------------
PMU_counters # (
.REG_WIDTH (32),
.N_COUNTERS (9)
)
inst_counters (
.clk_i (),
.rstn_i (),
.softrst_i (),
.en_i (),
.we_i (),
.regs_i (),
.regs_o (),
.events_i ()
);
//----------------------------------------------
//------------- Overflow interuption instance
//----------------------------------------------
PMU_overflow # (
.REG_WIDTH (32),
.N_COUNTERS (9)
)
inst_overflow (
.clk_i (),
.rstn_i (),
.softrst_i (),
.en_i (),
.counter_regs_i (),
.over_intr_mask_i (),
.intr_overflow_o (),
.over_intr_vect_o ()
);
//----------------------------------------------
//------------- Quota interruption instance
//----------------------------------------------
PMU_quota # (
.REG_WIDTH (32),
.N_COUNTERS (9)
)
inst_quota(
.clk_i (),
.rstn_i (),
.counter_value_i(),
.softrst_i (),
.quota_limit_i (),
.quota_mask_i (),
.intr_quota_o ()
);
//----------------------------------------------
//------------- MCCU instance
//----------------------------------------------
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),
//Signals per core. Change this may break Verilator TB
.CORE_EVENTS (MCCU_CORE_EVENTS)
)
inst_MCCU(
.clk_i (clk_i),
.rstn_i (rstn_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?
.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
.events_weights_i (MCCU_events_weights_int),//core_events times WEIGHTS_WIDTH registers
.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
//it seems to be te right solution.
);
//----------------------------------------------
//------------- Request Duration Counter (RDC)
//----------------------------------------------
RDC #(
// 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)
) inst_RDC(
.clk_i (clk_i),
.rstn_i (rstn_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
.interruption_vector_rdc_o(intrv_rdc_int) // vector with offending
//signals. One hot encoding.
//Cleared when MCCU is disabled.
);
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
`endif
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
/* -- Instance of pmu_ahb.sv
component pmu_ahb
generic (
haddr : integer := 0;
hmask : integer := 16#fff#);
n_regs : integer := 20 ;
reg_width : integer := CFG_AHBDW --32
port (
rst : in std_ulogic;
clk : in std_ulogic;
-- AHB bus slave interface
hsel_i : in std_ulogic; -- slave select
haddr_i : in std_logic_vector(31 downto 0); -- address bus
hwrite_i : in std_ulogic; -- read/write
htrans_i : in std_logic_vector(1 downto 0); -- transfer type
hsize_i : in std_logic_vector(2 downto 0); -- transfer size
hburst_i : in std_logic_vector(2 downto 0); -- burst type
hwdata_i : in std_logic_vector(CFG_AHBDW-1 downto 0); -- write data bus
hprot_i : in std_logic_vector(3 downto 0); -- prtection control
hreadyi_i : in std_ulogic; -- transfer done
hmaster_i : in std_logic_vector(3 downto 0); -- current master
hmastlock_i : in std_ulogic; -- locked access
hreadyo_o : out std_ulogic; -- trasfer done
hresp_o : out std_logic_vector(1 downto 0); -- response type
hrdata_o : out std_logic_vector(CFG_AHBDW-1 downto 0); -- read data bus
hsplit_o : out std_logic_vector(15 downto 0) -- split completion
-- PMU input signals
-- PMU output signals
end component;
*/
//-----------------------------------------------------
// 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
// References : AHB5 specifications
// https://silver.arm.com/download/download.tm?pv=2646779
`default_nettype none
`timescale 1 ns / 1 ps
`ifndef SYNT
`ifdef FORMAL
`define ASSERTIONS
`endif
`endif
module pmu_ahb #
(
parameter haddr = 0,
parameter hmask = 0,
// Total amount of registers
parameter integer N_REGS = 20,
// 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,
// 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,
// transfer done
input wire hreadyi_i,
// current master
input wire [3:0] hmaster_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,
// split completion
output wire [15:0] hsplit_o
// -- PMU input signals
// -- PMU output signals
);
//----------------------------------------------
//------------- Local parameters
//----------------------------------------------
//----------------------------------------------
//------------- AHB registers
//----------------------------------------------
reg [REG_WIDTH-1:0] slv_reg [0:N_REGS-1];
wire [REG_WIDTH-1:0] slv_reg_D [0:N_REGS-1];
wire [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
//----------------------------------------------
//basic transfers
//Addres phase 1 cycle unless extended by previous bus transfer
//Data phase 1 + extende by HREADY
//Simple transfer NO WAIT STATES (1 cycle address + 1 cycle data)
//capture Addres - hold address for data phase
reg [HADDR_WIDTH-1:0] haddr_int;
always_ff @(posedge clk_i, negedge rstn_i) begin
if(rstn_i == 1'b0 ) begin
haddr_int <= {HADDR_WIDTH{1'b0}};
end else begin
haddr_int <= haddr_i;
end
end
//capture data - hold data for data phase
reg [HDATA_WIDTH-1:0] hdata_int;
always_ff @(posedge clk_i, negedge rstn_i) begin
if(rstn_i == 1'b0 ) begin
hdata_int <= {HDATA_WIDTH{1'b0}};
end else begin
hdata_int <= hwdata_i;
end
end
// Detect direction, and register for data stage . HWRITE controls direction
//(HIGH means write transfer from master to slave)
//(LOW means read transfer from slave to master)
wire write_req_d;
wire read_req_d;
reg write_req_q;
reg read_req_q;
assign write_req_d = !rstn_i ? 1'b0 : !hreadyi_i? 1'b0 : hwrite_i ? 1'b1 : 1'b0;
assign read_req_d = !rstn_i ? 1'b0 : !hreadyi_i? 1'b0 : hwrite_i ? 1'b0 : 1'b1;
always_ff @(posedge clk_i, negedge rstn_i) begin
if(rstn_i == 1'b0 ) begin
write_req_q <= 1'b0;
read_req_q <= 1'b0;
end else begin
write_req_q <= write_req_d;
read_req_q <= read_req_d;
end
end
// Generate index of write/read responses
// Assume only 32b acces are done. 2 LSB are not used in address
wire [$clog2(N_REGS)-1:0] slv_index;
assign slv_index = haddr_int[$clog2(N_REGS)+1:2];
//Response in data cycle
reg [REG_WIDTH-1:0] resp_data;
always_ff @(posedge clk_i, negedge rstn_i) begin
if(rstn_i == 1'b0 ) begin
resp_data <= {REG_WIDTH{1'b0}};
end else begin
resp_data <= slv_reg[haddr_i];
end
end
//Write in data cycle - Writes to slave registers are arbitrated due to
//the implementation of my slave
wire [REG_WIDTH-1:0] write_data;
assign write_data = hwdata_i;
//Send registerd signals to interface
assign hrdata_o = resp_data;
//assign hreadyo_o = resp_done || read_done;
//Write in data cycle
//----------------------------------------------
//------------- AHB to PMU_raw synchronization
//----------------------------------------------
//This will increase in complexity later
genvar i;
generate
for(i=0;i<N_REGS;i++) begin
// Always update the next value for the slave registers
// Careful, remeber to not write when rstn_i is LOW
assign slv_reg_D[i] = write_req_d && (i==slv_index)
? write_data :slv_reg_Q[i];
end
endgenerate
//----------------------------------------------
//------------- PMU_raw instance
//----------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
//AHB read and write can't happen at the same time
always_ff @(posedge clk_i, negedge rstn_i) begin
assert 1'b1 != (write_req_d && read_req_d)
assert 1'b1 != (write_req_q && read_req_q)
end
`endif
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment