blob: 91bec3639044e9d4810171587c51eb2f56de73f5 [file] [log] [blame]
/**
* Dummy instruction module
*
* Provides pseudo-randomly inserted fake instructions for secure code obfuscation
*/
module brq_ifu_dummy_instr (
// Clock and reset
input logic clk_i,
input logic rst_ni,
// Interface to CSRs
input logic dummy_instr_en_i,
input logic [2:0] dummy_instr_mask_i,
input logic dummy_instr_seed_en_i,
input logic [31:0] dummy_instr_seed_i,
// Interface to IF stage
input logic fetch_valid_i,
input logic id_in_ready_i,
output logic insert_dummy_instr_o,
output logic [31:0] dummy_instr_data_o
);
localparam int unsigned TIMEOUT_CNT_W = 5;
localparam int unsigned OP_W = 5;
typedef enum logic [1:0] {
DUMMY_ADD = 2'b00,
DUMMY_MUL = 2'b01,
DUMMY_DIV = 2'b10,
DUMMY_AND = 2'b11
} dummy_instr_e;
typedef struct packed {
dummy_instr_e instr_type;
logic [OP_W-1:0] op_b;
logic [OP_W-1:0] op_a;
logic [TIMEOUT_CNT_W-1:0] cnt;
} lfsr_data_t;
localparam int unsigned LFSR_OUT_W = $bits(lfsr_data_t);
lfsr_data_t lfsr_data;
logic [TIMEOUT_CNT_W-1:0] dummy_cnt_incr, dummy_cnt_threshold;
logic [TIMEOUT_CNT_W-1:0] dummy_cnt_d, dummy_cnt_q;
logic dummy_cnt_en;
logic lfsr_en;
logic [LFSR_OUT_W-1:0] lfsr_state;
logic insert_dummy_instr;
logic [6:0] dummy_set;
logic [2:0] dummy_opcode;
logic [31:0] dummy_instr;
logic [31:0] dummy_instr_seed_q, dummy_instr_seed_d;
// Shift the LFSR every time we insert an instruction
assign lfsr_en = insert_dummy_instr & id_in_ready_i;
assign dummy_instr_seed_d = dummy_instr_seed_q ^ dummy_instr_seed_i;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
dummy_instr_seed_q <= '0;
end else if (dummy_instr_seed_en_i) begin
dummy_instr_seed_q <= dummy_instr_seed_d;
end
end
prim_lfsr #(
.LfsrDw ( 32 ),
.StateOutDw ( LFSR_OUT_W )
) lfsr_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.seed_en_i ( dummy_instr_seed_en_i ),
.seed_i ( dummy_instr_seed_d ),
.lfsr_en_i ( lfsr_en ),
.entropy_i ( '0 ),
.state_o ( lfsr_state )
);
// Extract fields from LFSR
assign lfsr_data = lfsr_data_t'(lfsr_state);
// Set count threshold for inserting a new instruction. This is the pseudo-random value from the
// LFSR with a mask applied (based on CSR config data) to shorten the period if required.
assign dummy_cnt_threshold = lfsr_data.cnt & {dummy_instr_mask_i,{TIMEOUT_CNT_W-3{1'b1}}};
assign dummy_cnt_incr = dummy_cnt_q + {{TIMEOUT_CNT_W-1{1'b0}},1'b1};
// Clear the counter everytime a new instruction is inserted
assign dummy_cnt_d = insert_dummy_instr ? '0 : dummy_cnt_incr;
// Increment the counter for each executed instruction while dummy instuctions are
// enabled.
assign dummy_cnt_en = dummy_instr_en_i & id_in_ready_i &
(fetch_valid_i | insert_dummy_instr);
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
dummy_cnt_q <= '0;
end else if (dummy_cnt_en) begin
dummy_cnt_q <= dummy_cnt_d;
end
end
// Insert a dummy instruction each time the counter hits the threshold
assign insert_dummy_instr = dummy_instr_en_i & (dummy_cnt_q == dummy_cnt_threshold);
// Encode instruction
always_comb begin
unique case (lfsr_data.instr_type)
DUMMY_ADD : begin
dummy_set = 7'b0000000;
dummy_opcode = 3'b000;
end
DUMMY_MUL : begin
dummy_set = 7'b0000001;
dummy_opcode = 3'b000;
end
DUMMY_DIV : begin
dummy_set = 7'b0000001;
dummy_opcode = 3'b100;
end
DUMMY_AND : begin
dummy_set = 7'b0000000;
dummy_opcode = 3'b111;
end
default : begin
dummy_set = 7'b0000000;
dummy_opcode = 3'b000;
end
endcase
end
// SET RS2 RS1 OP RD
assign dummy_instr = {dummy_set,lfsr_data.op_b,lfsr_data.op_a,dummy_opcode,5'h00,7'h33};
// Assign outputs
assign insert_dummy_instr_o = insert_dummy_instr;
assign dummy_instr_data_o = dummy_instr;
endmodule