Implementing a Macro for Caravel

Originally written by Kareem Farid and Mohamed Hosni

Note

If you do not have prior experience with LibreLane, please make sure to go through the Getting Started: Newcomers tutorial first.

Initially released in 2020 by Efabless Corporation, the Caravel harness chip is comprised of base functions supporting IO, power, and configuration as well as drop-in modules for a management SoC core, and a ≈ 3mm x 3.6mm open project area for the placement of user IP blocks.

Both OpenLane and LibreLane were initially developed for use with Caravel, which in turn was created for the OpenMPW project.

AES stands for Advanced Encryption Standard which is a symmetric encryption algorithm widely used across the globe to secure data. It operates on blocks of data using keys of 128, 192, or 256 bits to encrypt and decrypt information, providing a high level of security and efficiency for electronic data protection. In this tutorial, we are going to harden an AES core and have it as a Caravel User Project macro to serve as an accelerator for the chip Caravel.

Creating your own project repository

Note

For the purposes of this tutorial, we will be using a maintained fork of the Caravel User Project by UmbraLogic Technologies LLC that uses LibreLane instead of OpenLane.

  1. Start by creating a new repository from the Caravel user project LibreLane template. Let’s call it caravel_aes_accelerator.

  2. Open a terminal and clone your repository as follows:

    $ git clone git@github.com:<github_user_name>/caravel_aes_accelerator.git ~/caravel_aes_accelerator
    

RTL integration

We begin by using the open-source RTLs for AES by Joachim Strömbergson and adding a Wishbone bus wrapper for Caravel. Since the RTL from secworks provides a generic memory interface, we only need to add the ack, write_enable, and read_enable logic to the Wishbone wrapper.

  1. Clone the secworks/aes Git repository

    $ git clone git@github.com:secworks/aes.git ~/secworks_aes
    
  2. Create the Verilog file ~/caravel_aes_accelerator/verilog/rtl/aes_wb_wrapper.v and add the Wishbone wrapper to the RTL:

    aes_wb_wrapper.v
    // SPDX-FileCopyrightText: 2020 Efabless Corporation
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //      http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    // SPDX-License-Identifier: Apache-2.0
    
    `default_nettype none
    
    module aes_wb_wrapper (
    `ifdef USE_POWER_PINS
        inout VPWR,
        inout VGND,
    `endif
    
        // Wishbone Slave ports (WB MI A)
        input wb_clk_i,
        input wb_rst_i,
        input wbs_stb_i,
        input wbs_cyc_i,
        input wbs_we_i,
        input [3:0] wbs_sel_i,
        input [31:0] wbs_dat_i,
        input [31:0] wbs_adr_i,
        output wbs_ack_o,
        output [31:0] wbs_dat_o
    );
    
        wire valid;
        wire write_enable;
        wire read_enable;
    
        reg wbs_ack_o_reg;
    
        assign valid = wbs_cyc_i && wbs_stb_i;
        assign write_enable = wbs_we_i && valid;
        assign read_enable = ~wbs_we_i && valid;
    
        aes aes(
            // Clock and reset.
            .clk(wb_clk_i),
            .reset_n(!wb_rst_i),
    
            // Control.
            .cs(wbs_cyc_i && wbs_stb_i),
            .we(write_enable),
    
            // Data ports.
            .address(wbs_adr_i[9:2]),
            .write_data(wbs_dat_i),
            .read_data(wbs_dat_o)
        );
    
        // Ack logic
        always @(posedge wb_clk_i or posedge wb_rst_i) begin
            if (wb_rst_i)
                wbs_ack_o_reg <= 1'b0;
            else if (wbs_cyc_i && wbs_stb_i && ~wbs_ack_o_reg)
                wbs_ack_o_reg <= 1'b1;
            else
                wbs_ack_o_reg <= 1'b0;
        end
    
        assign wbs_ack_o = wbs_ack_o_reg;
    
    endmodule
    
    `default_nettype none
    
  3. Instantiate the aes_wb_wrapper in the user_project_wrapper Verilog file under ~/caravel_aes_accelerator/verilog/rtl

    user_project_wrapper.v
    // SPDX-FileCopyrightText: 2020 Efabless Corporation
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //      http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    // SPDX-License-Identifier: Apache-2.0
    
    `default_nettype none
    /*
     *-------------------------------------------------------------
     *
     * user_project_wrapper
     *
     * This wrapper enumerates all of the pins available to the
     * user for the user project.
     *
     * An example user project is provided in this wrapper.  The
     * example should be removed and replaced with the actual
     * user project.
     *
     *-------------------------------------------------------------
     */
    
    module user_project_wrapper #(
        parameter BITS = 32
    ) (
    `ifdef USE_POWER_PINS
        inout vdda1,	// User area 1 3.3V supply
        inout vdda2,	// User area 2 3.3V supply
        inout vssa1,	// User area 1 analog ground
        inout vssa2,	// User area 2 analog ground
        inout vccd1,	// User area 1 1.8V supply
        inout vccd2,	// User area 2 1.8v supply
        inout vssd1,	// User area 1 digital ground
        inout vssd2,	// User area 2 digital ground
    `endif
    
        // Wishbone Slave ports (WB MI A)
        input wb_clk_i,
        input wb_rst_i,
        input wbs_stb_i,
        input wbs_cyc_i,
        input wbs_we_i,
        input [3:0] wbs_sel_i,
        input [31:0] wbs_dat_i,
        input [31:0] wbs_adr_i,
        output wbs_ack_o,
        output [31:0] wbs_dat_o,
    
        // Logic Analyzer Signals
        input  [127:0] la_data_in,
        output [127:0] la_data_out,
        input  [127:0] la_oenb,
    
        // IOs
        input  [`MPRJ_IO_PADS-1:0] io_in,
        output [`MPRJ_IO_PADS-1:0] io_out,
        output [`MPRJ_IO_PADS-1:0] io_oeb,
    
        // Analog (direct connection to GPIO pad---use with caution)
        // Note that analog I/O is not available on the 7 lowest-numbered
        // GPIO pads, and so the analog_io indexing is offset from the
        // GPIO indexing by 7 (also upper 2 GPIOs do not have analog_io).
        inout [`MPRJ_IO_PADS-10:0] analog_io,
    
        // Independent clock (on independent integer divider)
        input   user_clock2,
    
        // User maskable interrupt signals
        output [2:0] user_irq
    );
    
    /*--------------------------------------*/
    /* User project is instantiated  here   */
    /*--------------------------------------*/
    
    aes_wb_wrapper mprj (
    `ifdef USE_POWER_PINS
    	.VPWR(vccd2),
    	.VGND(vssd2),
    `endif
    
        .wb_clk_i(wb_clk_i),
        .wb_rst_i(wb_rst_i),
    
        // MGMT SoC Wishbone Slave
    
        .wbs_cyc_i(wbs_cyc_i),
        .wbs_stb_i(wbs_stb_i),
        .wbs_we_i(wbs_we_i),
        .wbs_sel_i(wbs_sel_i),
        .wbs_adr_i(wbs_adr_i),
        .wbs_dat_i(wbs_dat_i),
        .wbs_ack_o(wbs_ack_o),
        .wbs_dat_o(wbs_dat_o)
    );
    
    endmodule	// user_project_wrapper
    
    `default_nettype wire
    

Hardening strategies

There are 3 options for implementing a Caravel User Project design using LibreLane:

  1. Macro-First Hardening: Harden the user macro(s) initially and incorporate them into the user project wrapper without top-level standard cells. Ideal for smaller designs, as this approach significantly reduces Placement and Routing (PnR) and signoff time.

  2. Full-Wrapper Flattening: Merge the user macro(s) with the user_project_wrapper, covering the entire wrapper area. While this method demands more time and iterations for PnR and signoff, it ultimately enhances performance, making it suitable for designs requiring the full wrapper area.

  3. Top-Level Integration: A hybrid approach where the user macro(s) are hardened then instantiated in the wrapper alongside standard cells at the top level. This is useful to allow user macros to be harderned separately, but the top-level may still insert its own buffers or similar to handle boundary violations.

See also

See the Caravel Integration & Power Routing document (archived from original) for more information about these options.

For this tutorial, we will be following all three in order.