Commit aa8fcea7 authored by Guillem's avatar Guillem
Browse files

Untested MCCU with basic features

Basic functionality is shown in verilator TB
parent eda5c782
......@@ -7,12 +7,8 @@
// References : https://upcommons.upc.edu/handle/2117/133656
`default_nettype none
//`define DEBUG
`timescale 1 ns / 1 ps
//TODO:remove this
/* verilator lint_off UNUSED */
/* verilator lint_off UNDRIVEN */
/* verilator lint_off BLKSEQ */
module MCCU #
(
// Width of data registers
......@@ -26,10 +22,10 @@
)
(
input wire clk_i,
//Active low asyncronous reset
//Active low asyncronous reset. It can have hardware or software source
input wire rstn_i,
//Enable signal, active high
input wire en_i,
//TODO: Add enable signal, active high
input wire enable_i,
//Monitored events that can generate contention in the system
input wire [CORE_EVENTS-1:0] events_i [0:N_CORES-1],
//Quota for each of the cores, internally registered, set by software
......@@ -39,28 +35,48 @@
//internally registered, set by software, if 0 event is dissabled
input wire [WEIGHTS_WIDTH-1:0] events_weights_i [0:N_CORES-1]
[0:CORE_EVENTS-1],
output wire [WEIGHTS_WIDTH-1:0] events_weights_o [0:N_CORES-1]
[0:CORE_EVENTS-1],
//Quota interruption
output wire interruption_quota_o[N_CORES-1:0]
);
//Parameters required for additions and substractions of quotas.
//OVERFLOW_PROT can be reduced. It needs to be a bit larger than
//DATA_WIDTH.
localparam integer OVERFLOW_PROT = DATA_WIDTH*2;
//avoid width mismatch when add: OVERFLOW_PROT + DATA_WIDTH
localparam O_D_0PAD = OVERFLOW_PROT-DATA_WIDTH;
//avoid width mismatch when add: DATA_WIDTH + WEIGHTS_WIDTH
localparam D_W_0PAD = DATA_WIDTH-WEIGHTS_WIDTH;
//avoid width mismatch when add: OVERFLOW_PROT + WEIGHTS_WIDTH
localparam O_W_0PAD = OVERFLOW_PROT-WEIGHTS_WIDTH;
//internal registers
reg [DATA_WIDTH-1:0] quota [0:N_CORES-1];
reg [WEIGHTS_WIDTH-1:0] events_weights [0:N_CORES-1] [0:CORE_EVENTS-1];
reg [OVERFLOW_PROT-1:0]ccc_suma[0:N_CORES-1];//Addition of current cycle
//consumed quota
`ifdef DEBUG
reg [OVERFLOW_PROT-1:0] debug_ccc_suma;//Just one core
reg [OVERFLOW_PROT-1:0] debug_ccc_suma_loop;//Just one core
reg [WEIGHTS_WIDTH-1:0] debug_events_weights [0:CORE_EVENTS-1];//Just one core
assign debug_events_weights = events_weights [0];//assign to core 0
integer k;
integer debug_tmp = 0;
`endif
/*----------
Generate one mechanism to monitor te quota for each of the cores in the
SOC,
----------*/
//genvar x;
genvar i;
genvar j;
integer i;
integer j;
generate
begin : GeneratedQuotaMonitor
always @(posedge clk_i, negedge rstn_i) begin: AsyncReset
/*----------
Reset
Auxiliar variables
----------*/
longint tmp_ccc_suma;//temporal addition of ccc_suma
/*----------
Reset
----------*/
if(0 == rstn_i) begin
/*----------
......@@ -75,100 +91,118 @@
----------*/
for (i=0; i<N_CORES; i=i+1) begin : ResetEventsWeights
for (j=0; j<CORE_EVENTS; j=j+1) begin
//TODO: Look why i can't have this secuential
events_weights [i][j] ={WEIGHTS_WIDTH{1'b0}};
events_weights [i][j] <={WEIGHTS_WIDTH{1'b0}};
end
end
/*----------
Async reset current cycle consumed quota
----------*/
for (i=0; i<N_CORES; i=i+1) begin : ResetiCCCQuota
ccc_suma[i] <={OVERFLOW_PROT{1'b0}};
end
end else begin
/*----------
Normal operation
----------*/
/*----------
Set weights of events, as this module is used in the
an axi-lite wrapper the values are already registered
outside and only need to be forwarded
Set weights of events, as this module is used whith an
axi-lite wrapper the values are already registered
outside and only need to be forwarded. Apply the event as
a mask. If the event is inactive in hte current cycle
0 is placed in events_weights for that event.
----------*/
for (i=0; i<N_CORES; i=i+1) begin : SetEventsWeights
for (i=0; i<CORE_EVENTS; i=i+1) begin
//TODO: Look why i can't have this secuential
events_weights [i][j] =events_weights_i[i][j];
for (j=0; j<CORE_EVENTS; j=j+1) begin
if(events_i[i][j]) begin
events_weights [i][j] <=events_weights_i[i][j];
end else begin
events_weights [i][j] <={WEIGHTS_WIDTH{1'b0}};
end
end
end
/*----------
//Set initial quota, as this module is used in the
//an axi-lite wrapper the values are already registered
//axi-lite wrapper the values are already registered
//outside and only need to be forwarded
----------*/
for (i=0; i<N_CORES; i=i+1) begin : SetQuota
quota[i] <= quota_i[i];
end
/*----------
Add quotas of all active signals. The ones that are not
enabled are 0.
----------*/
if(enable_i) begin
for (i=0; i<N_CORES; i=i+1) begin : AddEventsWeights
tmp_ccc_suma=0;
for (j=0; j<CORE_EVENTS; j=j+1) begin
//Reguired to avoid warning. Blocking
//Assigment is legal when usign temporal
//variables.
/* verilator lint_off BLKSEQ */
tmp_ccc_suma ={{O_W_0PAD{1'b0}},events_weights[i][j]} + tmp_ccc_suma;
/* verilator lint_on BLKSEQ */
end
ccc_suma[i]<=tmp_ccc_suma;
`ifdef DEBUG
/* verilator lint_off WIDTH */
/* verilator lint_off BLKSEQ */
//This only applies when 4 events are available
if(i==0 && CORE_EVENTS==4) begin
debug_ccc_suma <= debug_events_weights[0]+debug_events_weights[1]+debug_events_weights[2]+debug_events_weights[3];
debug_tmp=0;
for(k=0; k<CORE_EVENTS; k=k+1) begin
debug_tmp =debug_events_weights[k] + debug_tmp;
end
debug_ccc_suma_loop <= debug_tmp;
end
assert(debug_ccc_suma == debug_ccc_suma_loop);
//disable BLKSeK for the temporal assigment of debug_tmp
/* verilator lint_on BLKSEQ */
/* verilator lint_on WIDTH */
`endif
end
end
end
/*----------
Substract to the core quota the weight of each active
event during this cycle. If the event is active the value
of the weight is substracted, if not 0 is substracted.
----------*/
for (i=0; i<N_CORES; i=i+1) begin : SubstractQuota
//TODO:?There is a partial addition down in comb
if(enable_i) begin
for (i=0; i<N_CORES; i=i+1) begin : SubstractQuota
for (j=0; j<CORE_EVENTS; j=j+1) begin
//underflow detection. Padding needed for
// prevent width mismatch
if( ccc_suma[i] > {{O_D_0PAD{1'b0}},quota[i]} )
begin
quota[i] <={DATA_WIDTH{1'b0}};
end else begin
quota[i] <= quota[i] - ccc_suma[i][DATA_WIDTH-1:0];
end
end
end
end
//check interruption
end
end
/*----------
Add quotas of all signals. The ones that are not enabled are 0
Generate interruptions for quota for each core. Interrupt triggers
one cycle before the result is registered. There is no record of
by how much the quota was exceeded.
----------*/
//OVERFLOW_PROT can be reduced, needs to be a bit larger than
//DATA_WIDTH
localparam integer OVERFLOW_PROT = DATA_WIDTH*2;
wire[OVERFLOW_PROT-1:0]tmp[0:N_CORES];
reg [OVERFLOW_PROT-1:0]suma[0:N_CORES];
//avoid width mismatch when add: OVERFLOW_PROT + DATA_WIDTH
localparam O_D_0PAD = OVERFLOW_PROT-DATA_WIDTH;
//avoid width mismatch when add: DATA_WIDTH + WEIGHTS_WIDTH
localparam D_W_0PAD = DATA_WIDTH-WEIGHTS_WIDTH;
//avoid width mismatch when add: OVERFLOW_PROT + WEIGHTS_WIDTH
localparam O_W_0PAD = OVERFLOW_PROT-WEIGHTS_WIDTH;
//Generate interruptions for quota
for(i=0; i<N_CORES; i=i+1) begin: InterruptionQuota
assign interruption_quota_o[i] =(suma[i]>
{{O_D_0PAD{1'b0}},quota[i]}
genvar x;
for(x=0; x<N_CORES; x=x+1) begin: InterruptionQuota
assign interruption_quota_o[x] =(ccc_suma[x]>
{{O_D_0PAD{1'b0}},quota[x]}
)? 1'b1:1'b0;
end
/*----------
check active signals to be added. This will pass 0 to the adder
if the event is not enabled. If several events are active the
adder will count them next cycle
forward results of internal registers
----------*/
wire [WEIGHTS_WIDTH-1:0] values_count[0:N_CORES] [0:CORE_EVENTS-1];
for(i=0; i<N_CORES; i=i+1) begin: CheckActiveEvents
for (j=0; j<CORE_EVENTS; j=j+1) begin : MaskInactiveEvents
//This assignation sets value to 0 at reset. When the event
//is 0 the values_count is 0 as well. If the event is 1
//it passes the value of events_weights
assign values_count[i][j]=
(rstn_i== 1'b0)
?{WEIGHTS_WIDTH{1'b0}}:
{WEIGHTS_WIDTH{events_i[i][j]}}
&events_weights[i][j];
end
end
//Add the quotas in a combinational block
always @(*) begin : AddQuotasComb
//For all cores
for(i=0; i<N_CORES; i=i+1) begin: SumQuotas
tmp[i] =0;
//For all events
for (j=0; j<CORE_EVENTS; j=j+1) begin
//Add in tmp[i] the weight of all active events
//TODO: add only active weights not all events
tmp[i]={{O_W_0PAD{1'b0}},values_count[i][j]}
+tmp[i];
end
suma[i]=tmp[i];
end
end
end
assign quota_o = quota;
endgenerate
`default_nettype wire //allow compatibility with legacy code and xilinx ip
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
vlib MCCU
vmap work $PWD/MCCU
vlog +incdir+../../hdl/ ../../hdl/*.sv tb_MCCU.v
vmake MCCU/ > Makefile
vsim work.tb_MCCU
//-----------------------------------------------------
// ProjectName: MCCU research
// Function : Shows intended behaviour
// Description: This TB is not used to debug and verify just to show the
// intended behaviour. Intended to be used with QuestaSim.
// Coder : G.Cabo
//***Headers***
//***Test bench***
module tb_MCCU();
//***Parameters***
parameter CLK_PERIOD = 2;
parameter CLK_HALF_PERIOD = CLK_PERIOD / 2;
//***Signals***
reg tb_clk_i ;
reg tb_rstn_i ;
//***Module***
MCCU #(
)
dut_MCCU(
.clk_i (tb_clk_i ),
.rstn_i (tb_rstn_i )
);
//***clk_gen***
//*** TODO ***
//initial tb_clk_i = 0;
//always #CLK_HALF_PERIOD tb_clk_i = !tb_clk_i;
//***task reset_dut***
task reset_dut;
begin
$display("*** Toggle reset.");
//*** TODO ***
end
endtask
//***task init_sim***
task init_sim;
begin
$display("*** init sim.");
//*** TODO ***
end
endtask
//***task init_dump***
task init_dump;
begin
$dumpfile("MCCU_test.vcd");
$dumpvars(0,dut_MCCU);
end
endtask
//***task test_sim***
task test_sim;
begin
$display("*** test_sim.");
//***Handcrafted test***
end
endtask
//***init_sim***
initial begin
init_sim();
init_dump();
reset_dut();
test_sim();
end
endmodule
......@@ -65,12 +65,19 @@ void tick_and_trace(VMCCU* module,VerilatedVcdC* tfp){
struct TestCase {
const char* name;
bool en, rstn;
bool rstn_i, enable_i;
uint64_t events_i[4];
uint64_t quota_i[4];
uint16_t events_weights_i[4][4];
};
TestCase test_cases[] {
//name en,clr,ev0,ev1,ev2,ev3,quota_mask,quota_lim
{ "No Int_quota " ,1 ,0 },
//name ,rstn_i ,enable_i ,events_i ,quota_i ,events_weights_i
{ "Rst " ,0 ,0 ,{0,2,0,4} ,{0,0,0,0} ,{{0,0,0,0},{5,0,0,8},{9,0,11,7},{9,6,11,11}}},
{ "Init " ,1 ,0 ,{16,16,7,7} ,{10,15,20,25} ,{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}},
{ "Delay " ,1 ,0 ,{14,15,3,4} ,{10,15,20,25} ,{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}},
{ "Enable " ,1 ,1 ,{13,12,3,4} ,{10,15,20,25} ,{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}},
{ "Enable " ,1 ,1 ,{1,2,3,4} ,{10,15,20,25} ,{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}},
};
int main(int argc, char **argv, char **env) {
......@@ -101,6 +108,20 @@ int main(int argc, char **argv, char **env) {
int num_test_cases = sizeof(test_cases)/sizeof(TestCase);
for(int k = 0; k < num_test_cases; k++) {
TestCase *test_case = &test_cases[k];
MCCU->rstn_i = test_case->rstn_i;
MCCU->enable_i = test_case->enable_i;
//TODO: find a way to read localparam to drive this loops
int N_CORES =2;
int CORE_EVENTS=4;
for( int i = 0; i<N_CORES; i++){
MCCU->events_i[i] = test_case->events_i[i];
MCCU->quota_i[i] = test_case->quota_i[i];
for(int j = 0; j<CORE_EVENTS; j++) {
MCCU->events_weights_i[i][j] = test_case->events_weights_i[i][j];
}
}
ticktoc_and_trace(MCCU,tfp);
// printf("%s: passed\n", MCCU->DATA_WIDTH);
}
//delay test
......
......@@ -7,7 +7,7 @@ echo -e "${RED} Modify the script if you need to set your verilator path ${NC}"
#export VERILATOR_ROOT=$TOP/verilator
#____________end set path verilator
rm -rf obj_dir
verilator -Wall --cc --trace MCCU.v --exe MCCU_TB.cpp -CFLAGS "-std=c++14"
verilator -Wall --cc --trace ../../hdl/MCCU.sv --exe MCCU_TB.cpp -CFLAGS "-std=c++14"
cd obj_dir/
make -f VMCCU.mk
......
[*]
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
[*] Tue Jul 16 13:02:29 2019
[*]
[dumpfile] "/home/bscuser/GITLAB/multicore_pmu/lagarto-lowrisc/lagarto_modulos/AXI_PMU/MCCU/tb/verilator/obj_dir/VMCCU.vcd"
[dumpfile_mtime] "Tue Jul 16 13:01:20 2019"
[dumpfile_size] 5624
[savefile] "/home/bscuser/GITLAB/multicore_pmu/lagarto-lowrisc/lagarto_modulos/AXI_PMU/MCCU/tb/verilator/tests.gtkw"
[timestart] 0
[size] 1920 1025
[pos] 0 27
*-2.900144 10 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] TOP.
[treeopen] TOP.MCCU.
[treeopen] TOP.MCCU.GeneratedQuotaMonitor.
[sst_width] 297
[signals_width] 246
[sst_expanded] 1
[sst_vpaned_height] 292
@28
[color] 3
TOP.clk_i
[color] 3
TOP.enable_i
TOP.rstn_i
@800200
-Events
@800022
TOP.events_i(0)[3:0]
@28
(0)TOP.events_i(0)[3:0]
(1)TOP.events_i(0)[3:0]
(2)TOP.events_i(0)[3:0]
(3)TOP.events_i(0)[3:0]
@1001200
-group_end
@800022
TOP.events_i(1)[3:0]
@28
(0)TOP.events_i(1)[3:0]
(1)TOP.events_i(1)[3:0]
(2)TOP.events_i(1)[3:0]
(3)TOP.events_i(1)[3:0]
@1001200
-group_end
@1000200
-Events
@24
[color] 6
TOP.MCCU.ccc_suma(0)[63:0]
@23
TOP.MCCU.quota(0)[31:0]
@28
TOP.MCCU.interruption_quota_o(0)
@24
[color] 6
TOP.MCCU.events_weights(0)(0)[9:0]
[color] 6
TOP.MCCU.events_weights(0)(1)[9:0]
[color] 6
TOP.MCCU.events_weights(0)(2)[9:0]
[color] 6
TOP.MCCU.events_weights(0)(3)[9:0]
[color] 2
TOP.MCCU.ccc_suma(1)[63:0]
@22
TOP.MCCU.quota(1)[31:0]
@28
TOP.MCCU.interruption_quota_o(1)
@24
[color] 2
TOP.MCCU.events_weights(1)(0)[9:0]
[color] 2
TOP.MCCU.events_weights(1)(1)[9:0]
[color] 2
TOP.MCCU.events_weights(1)(2)[9:0]
[color] 2
TOP.MCCU.events_weights(1)(3)[9:0]
@22
TOP.MCCU.events_weights_i(0)(0)[9:0]
TOP.MCCU.events_weights_i(0)(1)[9:0]
TOP.MCCU.events_weights_i(0)(2)[9:0]
TOP.MCCU.events_weights_i(0)(3)[9:0]
TOP.MCCU.events_weights_i(1)(0)[9:0]
TOP.MCCU.events_weights_i(1)(1)[9:0]
TOP.MCCU.events_weights_i(1)(2)[9:0]
TOP.MCCU.events_weights_i(1)(3)[9:0]
[pattern_trace] 1
[pattern_trace] 0
Markdown is supported
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