Consider a processor implementation, one that can execute arithmetic operations such as:
(opcode,destination,source 0,source 1)
Examples and meaning of each instruction:
ADD R2, R1, R0 → R2 = R1+R0
SUB R3, R2, R1 → R3 = R2 -R1
instructions are represented with 32-bits:
Upper 5 bits: opcode (ADD=0, SUB=1,…)
Next 5 bits: Rd (destination)
Next 5 bits: Rs1 (source 1)
Next 5 bits: Rs0 (source 0)
(leftover bits not used/reserved)
We have R0…R31 in the system.
· Write a class to represent an instruction.
· Increase the chances for data hazards (destination of one instruction is one of the source operands for the next instruction).
Here is the implementation which i thought of, is there a better way to implement the same? Can this be implemented using randsequence?
module alu;
class Instruction;
rand bit [4:0] Rd;
rand bit [4:0] Rs0;
rand bit [4:0] Rs1;
rand enum {Add = 0,Sub,Multiply,Xor,Or,And,Nand,Not,Load,Store} opcode;
rand enum {RAW =0,WAR,WAW} Hazard;
rand bit Dependent;
rand bit [2:0] Interleaving;
rand bit Rs0_or_Rs1;
constraint c {Interleaving inside{[1:7]};}
constraint c_hazard {Hazard dist {RAW := 7, WAR :=2, WAW := 2};}
constraint c_dependent {Dependent dist {1 := 80, 0 := 40};}
bit [31:0] My_Instruction;
function void post_randomize();
My_Instruction = {opcode,Rd,Rs0,Rs1};
endfunction
endclass
class my_alu;
rand Instruction Instruction_h[20];
function new();
foreach (Instruction_h[i])
Instruction_h[i] = new;
endfunction
constraint c1{
foreach (Instruction_h[i])
{
if(Instruction_h[i].Dependent && Instruction_h[i].Hazard==0)
{//RAW
if(Instruction_h[i].Rs0_or_Rs1)
Instruction_h[i].Rs0==Instruction_h[i-(Instruction_h[i].Interleaving)].Rd;
else
Instruction_h[i].Rs1== Instruction_h[i-(Instruction_h[i].Interleaving)].Rd;
}
else if (Instruction_h[i].Dependent && Instruction_h[i].Hazard==1)
{//WAR
if (Instruction_h[i].Rs0_or_Rs1)
Instruction_h[i].Rd==Instruction_h[i-(Instruction_h[i].Interleaving)].Rs0;
else
Instruction_h[i].Rd==Instruction_h[i-(Instruction_h[i].Interleaving)].Rs1;
}
else if (Instruction_h[i].Dependent && Instruction_h[i].Hazard==2) //WAW
Instruction_h[i].Rd==Instruction_h[i-(Instruction_h[i].Interleaving)].Rd;
}
}
endclass
my_alu my_alu_h;
initial begin
my_alu_h = new;
assert (my_alu_h.randomize());
foreach(my_alu_h.Instruction_h[i])
$display("%p",my_alu_h.Instruction_h[i]);
end
endmodule
This code seems to be fine, I have made few modifications such as,
turning off constraint c1 for the first object.
Replaced “i-(Instruction_h[i].Interleaving)”, might cause failure if i < Instruction_h[i].Interleaving.
Additional interleaving constraint so that the address is picked from a previous instruction “Instruction_h[i].Interleaving == i-1; or Instruction_h[i].Interleaving < i”.
Increased “Interleaving” size and removed its base constraint.
Please find the modified code below.
module alu;
class Instruction;
rand bit [4:0] Rd;
rand bit [4:0] Rs0;
rand bit [4:0] Rs1;
rand enum {Add = 0,Sub,Multiply,Xor,Or,And,Nand,Not,Load,Store} opcode;
rand enum {RAW =0,WAR,WAW} Hazard;
rand bit Dependent;
rand bit [4:0] Interleaving;
rand bit Rs0_or_Rs1;
//constraint c {Interleaving inside{[1:7]};}
constraint c_hazard {Hazard dist {RAW := 7, WAR :=2, WAW := 2};}
constraint c_dependent {Dependent dist {1 := 80, 0 := 40};}
bit [31:0] My_Instruction;
function void post_randomize();
My_Instruction = {opcode,Rd,Rs0,Rs1};
endfunction
endclass
class my_alu;
rand Instruction Instruction_h[20];
function new();
foreach (Instruction_h[i])
Instruction_h[i] = new;
endfunction
constraint c1{
foreach (Instruction_h[i])
{
if(i>0) {
Instruction_h[i].Interleaving == i-1; //or Instruction_h[i].Interleaving < i
if(Instruction_h[i].Dependent && Instruction_h[i].Hazard==0)
{//RAW
if(Instruction_h[i].Rs0_or_Rs1)
Instruction_h[i].Rs0==Instruction_h[(Instruction_h[i].Interleaving)].Rd;
else
Instruction_h[i].Rs1== Instruction_h[(Instruction_h[i].Interleaving)].Rd;
}
else if (Instruction_h[i].Dependent && Instruction_h[i].Hazard==1)
{//WAR
if (Instruction_h[i].Rs0_or_Rs1)
Instruction_h[i].Rd==Instruction_h[(Instruction_h[i].Interleaving)].Rs0;
else
Instruction_h[i].Rd==Instruction_h[(Instruction_h[i].Interleaving)].Rs1;
}
else if (Instruction_h[i].Dependent && Instruction_h[i].Hazard==2) //WAW
Instruction_h[i].Rd==Instruction_h[(Instruction_h[i].Interleaving)].Rd;
}
}
}
endclass
my_alu my_alu_h;
initial begin
my_alu_h = new;
assert (my_alu_h.randomize());
foreach(my_alu_h.Instruction_h[i])
$display("%p",my_alu_h.Instruction_h[i]);
end
endmodule
Thank you Raja for your reply, I believe the constraint solver will take care of the failure condition you are mentioning (might cause failure if i < Instruction_h[i].Interleaving)
The value of Interleaving will be set in such a range that it will find an object instance of the class Instruction. I have tried the code and working on EDA playground.
Thanks for the link, yes it is working with synopsys VCS 2020.03 and mentor questa 2020.1 simulators. But the randomization is failing with cadence xcelium 20.09 simulator, which I was using. Probably its the way constraint solvers are implemented in different EDA simulators.
According me, your solution works and looks fine. Thank you!