Bit-blasting a multi-port RAM instance

From Verific Design Automation FAQ
Jump to: navigation, search

Q: What is bit-blasting a multi-port RAM instance

Verific’s RAM extraction creates a minimal-port, multi-port RAM model in the netlist for every identifier that behaves as a RAM in the original RTL design. The decision to implement the identifier as a RAM was done easy on, during the analysis phase, and based on very limited information about the identifier and how it is used in the RTL model.

It is very likely that there will be cases where it is needed to "undo" an extracted RAM. For example, just before mapping a multi port RAM to a target technology, it may turn out that that particular multiport RAM is not available in the target library. Rather than terminating the application, it would then be desirable to "bit-blast" the RamNet and to implement the behavior as a collection of traditional logic like registers, selection logic, etc..

This is why Verific implemented a RamNet "bit-blast" algorithm. This algorithm takes a RamNet with its connected read/write ports and translate this structure into a bit-blasted netlist similar to what would be created if no multiport RAM architecture was inferred in the first place. This "bit-blast" algorithm is implemented under API routine RamNet::BlastNet(). As most other routines on RamNet, this is a virtual routine, so it can be called from the Net base class.

Verific creates operator "enable decoder" (class OperEnabledDecoder : public Operator) when bit-blasting a RamNet. When a WritePort has a write-enable signal, the bit-blasted logic should infer a decoder with the write address and all the decoded bits gated with the write-enable net. This operator serves that purpose.

Relevant:

  APIs: Net::BlastNet(), Netlist::BlastRamNets().
  Tcl command: blast_ram.

ram.v:

module top (input clk, input write, input [1:0]addr,
            input [1:0]addr1, input [0:3]data, output reg [0:3] out) ;
  reg [0:3]ram [3:0] ;

  always @(posedge clk) begin
    if (write) ram[addr] <= data ;
  end

  always @(posedge clk) begin
    out <= ram[addr1] ;
  end
endmodule
 

tcl script:

set_runtime_flag "veri_extract_dualport_rams" 0
set_runtime_flag "veri_extract_multiport_rams" 1
analyze ram.v
elaborate
write netlist.v
blast_ram
write blasted_netlist.v
 

netlist.v:

//
// Verific Verilog Description of module top
//

module top (clk, write, addr, addr1, data, out);   // ram.v(1)
    input clk;   // ram.v(1)
    input write;   // ram.v(1)
    input [1:0]addr;   // ram.v(1)
    input [1:0]addr1;   // ram.v(2)
    input [0:3]data;   // ram.v(2)
    output [0:3]out;   // ram.v(2)
    
    wire [15:0] ram /* Original declaration bounds: [3:0][0:3] */  /* verific ORIG_DEPTH=4, ORIG_WIDTH=4 */ ;   // ram.v(3)
    
    wire n7, n8, n9, n10;
    
    ClockedWritePort_2_4_3_0_0_3 clk_write_port_4 (.clk(clk), .write_enable(write), 
            .write_address({addr}), .write_data({data}), .Ram(ram));   // ram.v(6)
    VERIFIC_DFFRS i9 (.d(n8), .clk(clk), .s(1'b0), .r(1'b0), .q(out[1]));   // ram.v(11)
    VERIFIC_DFFRS i10 (.d(n9), .clk(clk), .s(1'b0), .r(1'b0), .q(out[2]));   // ram.v(11)
    VERIFIC_DFFRS i11 (.d(n10), .clk(clk), .s(1'b0), .r(1'b0), .q(out[3]));   // ram.v(11)
    VERIFIC_DFFRS i8 (.d(n7), .clk(clk), .s(1'b0), .r(1'b0), .q(out[0]));   // ram.v(11)
    ReadPort_2_4_3_0_0_3 read_port_6 (.read_enable(1'b1), .read_address({addr1}), 
            .read_data({n7, n8, n9, n10}), .Ram(ram));   // ram.v(10)
    
endmodule

//
// Verific Verilog Description of OPERATOR ClockedWritePort_2_4_3_0_0_3
//

module ClockedWritePort_2_4_3_0_0_3 (clk, write_enable, write_address, 
            write_data, Ram);
    input clk;
    input write_enable;
    input [1:0]write_address;
    input [3:0]write_data;
    output [15:0] Ram;
    
    
    
endmodule

//
// Verific Verilog Description of OPERATOR ReadPort_2_4_3_0_0_3
//

module ReadPort_2_4_3_0_0_3 (read_enable, read_address, read_data, Ram);
    input read_enable;
    input [1:0]read_address;
    output [3:0]read_data;
    input [15:0] Ram;
    
    
    
endmodule
 

blasted_netlist.v

//
// Verific Verilog Description of module top
//

module top (clk, write, addr, addr1, data, out);   // ram.v(1)
    input clk;   // ram.v(1)
    input write;   // ram.v(1)
    input [1:0]addr;   // ram.v(1)
    input [1:0]addr1;   // ram.v(2)
    input [0:3]data;   // ram.v(2)
    output [0:3]out;   // ram.v(2)
    
    wire ram_0_3;   // ram.v(3)
    wire ram_0_2;   // ram.v(3)
    wire ram_0_1;   // ram.v(3)
    wire ram_2_0;   // ram.v(3)
    wire ram_0_0;   // ram.v(3)
    wire ram_1_3;   // ram.v(3)
    wire ram_1_2;   // ram.v(3)
    wire ram_1_1;   // ram.v(3)
    wire ram_1_0;   // ram.v(3)
    wire ram_2_1;   // ram.v(3)
    wire ram_2_2;   // ram.v(3)
    wire ram_2_3;   // ram.v(3)
    wire ram_3_0;   // ram.v(3)
    wire ram_3_1;   // ram.v(3)
    wire ram_3_2;   // ram.v(3)
    wire ram_3_3;   // ram.v(3)
    
    wire n21, n22, n23, n24, n25, n26, n27, n28, n29, n34, 
        n39, n44, n49, n54, n59, n64, n69, n74, n79, n84, 
        n89, n94, n99, n104;
    
    Mux_2u_4u Mux_18 (.sel({addr1}), .data({ram_3_3, ram_2_3, ram_1_3, 
            ram_0_3}), .o(n25));   // ram.v(10)
    EnabledDecoder_2 EnabledDecoder_17 (.en(write), .i({addr}), .o({n21, 
            n22, n23, n24}));   // ram.v(6)
    VERIFIC_DFFRS i9 (.d(n27), .clk(clk), .s(1'b0), .r(1'b0), .q(out[1]));   // ram.v(11)
    VERIFIC_DFFRS i10 (.d(n26), .clk(clk), .s(1'b0), .r(1'b0), .q(out[2]));   // ram.v(11)
    VERIFIC_DFFRS i11 (.d(n25), .clk(clk), .s(1'b0), .r(1'b0), .q(out[3]));   // ram.v(11)
    Mux_2u_4u Mux_19 (.sel({addr1}), .data({ram_3_2, ram_2_2, ram_1_2, 
            ram_0_2}), .o(n26));   // ram.v(10)
    VERIFIC_DFFRS i8 (.d(n28), .clk(clk), .s(1'b0), .r(1'b0), .q(out[0]));   // ram.v(11)
    Mux_2u_4u Mux_20 (.sel({addr1}), .data({ram_3_1, ram_2_1, ram_1_1, 
            ram_0_1}), .o(n27));   // ram.v(10)
    Mux_2u_4u Mux_21 (.sel({addr1}), .data({ram_3_0, ram_2_0, ram_1_0, 
            ram_0_0}), .o(n28));   // ram.v(10)
    assign n29 = n24 ? data[0] : ram_0_0;   // ram.v(3)
    assign n34 = n24 ? data[1] : ram_0_1;   // ram.v(3)
    VERIFIC_DFFRS i26 (.d(n29), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_0_0));   // ram.v(3)
    assign n39 = n24 ? data[2] : ram_0_2;   // ram.v(3)
    VERIFIC_DFFRS i31 (.d(n34), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_0_1));   // ram.v(3)
    assign n44 = n24 ? data[3] : ram_0_3;   // ram.v(3)
    VERIFIC_DFFRS i36 (.d(n39), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_0_2));   // ram.v(3)
    assign n49 = n23 ? data[0] : ram_1_0;   // ram.v(3)
    VERIFIC_DFFRS i41 (.d(n44), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_0_3));   // ram.v(3)
    assign n54 = n23 ? data[1] : ram_1_1;   // ram.v(3)
    VERIFIC_DFFRS i46 (.d(n49), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_1_0));   // ram.v(3)
    assign n59 = n23 ? data[2] : ram_1_2;   // ram.v(3)
    VERIFIC_DFFRS i51 (.d(n54), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_1_1));   // ram.v(3)
    assign n64 = n23 ? data[3] : ram_1_3;   // ram.v(3)
    VERIFIC_DFFRS i56 (.d(n59), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_1_2));   // ram.v(3)
    assign n69 = n22 ? data[0] : ram_2_0;   // ram.v(3)
    VERIFIC_DFFRS i61 (.d(n64), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_1_3));   // ram.v(3)
    assign n74 = n22 ? data[1] : ram_2_1;   // ram.v(3)
    VERIFIC_DFFRS i66 (.d(n69), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_2_0));   // ram.v(3)
    assign n79 = n22 ? data[2] : ram_2_2;   // ram.v(3)
    VERIFIC_DFFRS i71 (.d(n74), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_2_1));   // ram.v(3)
    assign n84 = n22 ? data[3] : ram_2_3;   // ram.v(3)
    VERIFIC_DFFRS i76 (.d(n79), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_2_2));   // ram.v(3)
    assign n89 = n21 ? data[0] : ram_3_0;   // ram.v(3)
    VERIFIC_DFFRS i81 (.d(n84), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_2_3));   // ram.v(3)
    assign n94 = n21 ? data[1] : ram_3_1;   // ram.v(3)
    VERIFIC_DFFRS i86 (.d(n89), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_3_0));   // ram.v(3)
    assign n99 = n21 ? data[2] : ram_3_2;   // ram.v(3)
    VERIFIC_DFFRS i91 (.d(n94), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_3_1));   // ram.v(3)
    assign n104 = n21 ? data[3] : ram_3_3;   // ram.v(3)
    VERIFIC_DFFRS i96 (.d(n99), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_3_2));   // ram.v(3)
    VERIFIC_DFFRS i101 (.d(n104), .clk(clk), .s(1'b0), .r(1'b0), .q(ram_3_3));   // ram.v(3)
    
endmodule

//
// Verific Verilog Description of OPERATOR Mux_2u_4u
//

module Mux_2u_4u (sel, data, o);
    input [1:0]sel;
    input [3:0]data;
    output o;
    
    
    wire n1, n2;
    
    assign n1 = sel[0] ? data[1] : data[0];
    assign n2 = sel[0] ? data[3] : data[2];
    assign o = sel[1] ? n2 : n1;
    
endmodule

//
// Verific Verilog Description of OPERATOR EnabledDecoder_2
//

module EnabledDecoder_2 (en, i, o);
    input en;
    input [1:0]i;
    output [3:0]o;
    
    
    wire n1, n2, n3, n4;
    
    not (n1, i[0]) ;
    not (n2, i[1]) ;
    and (n3, en, i[0]) ;
    and (n4, en, n1) ;
    and (o[2], n4, i[1]) ;
    and (o[0], n4, n2) ;
    and (o[3], n3, i[1]) ;
    and (o[1], n3, n2) ;
    
endmodule