| |
| |
| /** |
| * 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 |