blob: f02fe3791a37178513f3c7f89732d30cd55fbda2 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
module otbn_top_coco #(
// Instruction data width
parameter ImemDataWidth = 39,
// Data path width for BN (wide) instructions, in bits.
parameter WLEN = 256,
// Sideload key data width
parameter SideloadKeyWidth = 384
) (
input clk_sys,
input rst_sys_n,
input imem_we_i,
input [ImemDataWidth-1:0] imem_wdata_i,
input [ImemDataWidth-1:0] imem_wmask_i,
input [WLEN-1:0] edn_rnd_data_i,
input [WLEN-1:0] edn_urnd_data_i,
input [SideloadKeyWidth-1:0] sideload_key_share_0_i,
input [SideloadKeyWidth-1:0] sideload_key_share_1_i,
output [31:0] otbn_cycle_cnt_o
);
// Size of the instruction memory, in bytes
localparam ImemSizeByte = 128*4; //32'h1000;
// Size of the data memory, in bytes
localparam DmemSizeByte = 8*32; //32'h1000;
// "Extended" WLEN: the size of the datapath with added integrity bits
localparam ExtWLEN = WLEN * ImemDataWidth / 32;
/* Math function: Number of bits needed to address |value| items.
* This function is taken from prim_util_pkg.sv and re-coded
*
* 0 for value == 0
* vbits = 1 for value == 1
* ceil(log2(value)) for value > 1
*/
function automatic [31:0] vbits;
input [31:0] value;
begin : fclog2
integer result;
if (value == 1) begin
vbits = 1;
end else begin
value = value - 1;
for (result = 0; value > 0; result = result + 1) begin
value = value >> 1;
end
vbits = result;
end
end : fclog2
endfunction
// Instruction memory adress width
localparam ImemAddrWidth = vbits(ImemSizeByte);
// Data memory adress width
localparam DmemAddrWidth = vbits(DmemSizeByte);
reg otbn_start;
// Intialise otbn_start_done to 1 so that we only signal otbn_start after we have seen a reset. If
// you don't do this, we start OTBN before the reset, which can generate confusing trace messages.
reg otbn_start_done = 1'b1;
wire secure_wipe_running;
// Instruction memory (IMEM) signals
wire imem_req;
wire [ImemAddrWidth-1:0] imem_addr;
wire [ImemDataWidth-1:0] imem_rdata;
wire imem_rvalid;
// Data memory (DMEM) signals
wire dmem_req;
wire dmem_write;
wire [DmemAddrWidth-1:0] dmem_addr;
wire [ ExtWLEN-1:0] dmem_wdata;
wire [ ExtWLEN-1:0] dmem_wmask;
wire [ ExtWLEN-1:0] dmem_rdata;
wire dmem_rvalid;
wire dmem_rerror;
// Entropy Distribution Network (EDN)
wire edn_rnd_req, edn_urnd_req;
wire edn_rnd_ack, edn_urnd_ack;
assign edn_rnd_ack = edn_rnd_req;
assign edn_urnd_ack = edn_urnd_req;
// Sideload Key
wire [2*SideloadKeyWidth-1:0] sideload_key_shares;
assign sideload_key_shares = {sideload_key_share_1_i, sideload_key_share_0_i};
localparam [3:0] MuBi4False = 4'h9;
otbn_core u_otbn_core (
.clk_i (clk_sys),
.rst_ni(rst_sys_n),
.start_i (otbn_start),
.done_o (),
.locking_o (),
.secure_wipe_running_o(secure_wipe_running),
.err_bits_o (),
.recoverable_err_o(),
.imem_req_o (imem_req),
.imem_addr_o (imem_addr),
.imem_rdata_i (imem_rdata),
.imem_rvalid_i(imem_rvalid),
.dmem_req_o (dmem_req),
.dmem_write_o (dmem_write),
.dmem_addr_o (dmem_addr),
.dmem_wdata_o (dmem_wdata),
.dmem_wmask_o (dmem_wmask),
.dmem_rmask_o (),
.dmem_rdata_i (dmem_rdata),
.dmem_rvalid_i(dmem_rvalid),
.dmem_rerror_i(dmem_rerror),
.edn_rnd_req_o (edn_rnd_req),
.edn_rnd_ack_i (edn_rnd_ack),
.edn_rnd_data_i(edn_rnd_data_i),
.edn_rnd_fips_i(1'b1),
.edn_rnd_err_i (1'b0),
.edn_urnd_req_o (edn_urnd_req),
.edn_urnd_ack_i (edn_urnd_ack),
.edn_urnd_data_i(edn_urnd_data_i),
.insn_cnt_o (),
.insn_cnt_clear_i(1'b0),
.mems_sec_wipe_o (),
.dmem_sec_wipe_urnd_key_o(),
.imem_sec_wipe_urnd_key_o(),
.req_sec_wipe_urnd_keys_i(1'b0),
.escalate_en_i(MuBi4False),
.rma_req_i (MuBi4False),
.rma_ack_o (),
.software_errs_fatal_i(1'b0),
.sideload_key_shares_i (sideload_key_shares),
.sideload_key_shares_valid_i(2'b11)
);
// Track when OTBN is done with its initial secure wipe of the internal state. We use this to
// wait for the OTBN core to complete the initial secure wipe before we send it the start signal.
// Also keep a delayed copy of the done signal. This is necessary to align with the status of
// OTBN and the model, which lags one cycle behind the completion of the OTBN core.
reg init_sec_wipe_done_q;
always @(posedge clk_sys, negedge rst_sys_n) begin
if (!rst_sys_n) begin
init_sec_wipe_done_q <= 1'b0;
end else begin
if (!secure_wipe_running) begin
init_sec_wipe_done_q <= 1'b1;
end
end
end
// Pulse otbn_start for 1 cycle after the initial secure wipe is done.
// Flop `done_o` from otbn_core to match up with model done signal.
always @(posedge clk_sys or negedge rst_sys_n) begin
if (!rst_sys_n) begin
otbn_start <= 1'b0;
otbn_start_done <= 1'b0;
end else begin
if (!otbn_start_done && init_sec_wipe_done_q) begin
otbn_start <= 1'b1;
otbn_start_done <= 1'b1;
end else if (otbn_start) begin
otbn_start <= 1'b0;
end
end
end
// OTBN cycle counter to easily inspect waves and associate those waves with COCO-ALMA tool
// output. The counter is reset with the start pulse being sent.
reg [31:0] otbn_cycle_cnt_q;
always @(posedge clk_sys or negedge rst_sys_n) begin
if (!rst_sys_n) begin
otbn_cycle_cnt_q <= 32'b0;
end else begin
if (otbn_start) begin
otbn_cycle_cnt_q <= 32'b0;
end else if (otbn_start_done) begin
otbn_cycle_cnt_q <= otbn_cycle_cnt_q + 1;
end
end
end
assign otbn_cycle_cnt_o = otbn_cycle_cnt_q;
localparam DmemSizeWords = DmemSizeByte / (WLEN / 8);
localparam DmemIndexWidth = vbits(DmemSizeWords);
wire [DmemIndexWidth-1:0] dmem_index;
wire [DmemAddrWidth-DmemIndexWidth-1:0] unused_dmem_addr;
assign dmem_index = dmem_addr[DmemAddrWidth-1:DmemAddrWidth-DmemIndexWidth];
assign unused_dmem_addr = dmem_addr[DmemAddrWidth-DmemIndexWidth-1:0];
assign dmem_rerror = 1'b0;
ram_1p #(
.DataWidth(ExtWLEN),
.AddrWidth(DmemIndexWidth),
.Depth(DmemSizeWords)
) u_dmem (
.clk_i(clk_sys),
.rst_ni(rst_sys_n),
.req_i(dmem_req),
.we_i(dmem_write),
.addr_i(dmem_index),
.wdata_i(dmem_wdata),
.wmask_i(dmem_wmask),
.rvalid_o(dmem_rvalid),
.rdata_o(dmem_rdata)
);
localparam ImemSizeWords = ImemSizeByte / 4;
localparam ImemIndexWidth = vbits(ImemSizeWords);
wire [ImemIndexWidth-1:0] imem_index;
wire [1:0] unused_imem_addr;
assign imem_index = imem_addr[ImemAddrWidth-1:2];
assign unused_imem_addr = imem_addr[1:0];
ram_1p #(
.DataWidth(ImemDataWidth),
.AddrWidth(ImemIndexWidth),
.Depth(ImemSizeWords)
) u_imem (
.clk_i(clk_sys),
.rst_ni(rst_sys_n),
.req_i(imem_req),
.we_i(imem_we_i),
.addr_i(imem_index),
.wdata_i(imem_wdata_i),
.wmask_i(imem_wmask_i),
.rvalid_o(imem_rvalid),
.rdata_o(imem_rdata)
);
endmodule