RC5 hardware design: RAM/ROM Init



//
// RAM initialization section of the RC5 cryptographic chip
// design.
//


`define READ  0
`define WRITE 1


`define BAD_STATE   0
`define RESET       1
`define CRYPT_INIT  2
`define INIT_DONE   3
`define SHIFT_SETUP 4
`define ENCRYPT     5



//
// RAM memory
//
module RamTable( clk, address, data_in, r_w, data_out );

parameter TableSize = 32;
parameter DataWidth = 32;
parameter BitsInAddr = 5;

input clk;
input [BitsInAddr-1 : 0] address;
input [DataWidth-1 : 0] data_in;
input r_w;
output [DataWidth-1 : 0] data_out;
reg [DataWidth-1 : 0] data_out;

reg [DataWidth-1:0] Table[TableSize-1:0];

  always @(posedge clk )
  begin

    // $write("%t: RamTable: address = %d", $time, address );
    if (r_w)  // do a write
    begin : if_block
      // $write(", data = %x", data_in );
      Table[ address ] <= data_in;
    end
    // $display("");
    data_out <= Table[ address ];
  end

  initial
  begin : init
    integer i;

    for (i = 0; i < TableSize; i = i + 1)
      Table[ i ] = 0;
  end

endmodule  // RamTable




module RAM_mux( rom_data, shift_data, crypt_data,  /* ram input data sources */
                rw_rom, rw_shift, rw_crypt,        /* input r/w controls */
                addr_rom, addr_shift, addr_crypt,  /* input addresses */
                chip_state,
                ram_data, /* input data to RAM */
                ram_rw,   /* RAM r/w control */
                ram_addr /* ram address */
              );
parameter DataWidth = 32;
parameter BitsInAddr = 5;
input [DataWidth-1 : 0] rom_data, shift_data, crypt_data;
input rw_rom, rw_shift, rw_crypt;
input [BitsInAddr-1 : 0] addr_rom, addr_shift, addr_crypt;
input [1:0] chip_state;
output [DataWidth-1 : 0] ram_data;
output ram_rw;
output [BitsInAddr-1 : 0] ram_addr;

reg [DataWidth-1 : 0] ram_data;
reg ram_rw;
reg [BitsInAddr-1 : 0] ram_addr;


  // data mux
  always @( chip_state or rom_data or shift_data or crypt_data )
  begin
    case (chip_state)
      `CRYPT_INIT  : ram_data = rom_data;
      `SHIFT_SETUP : ram_data = shift_data;
      `ENCRYPT     : ram_data = crypt_data;
      default      : ram_data = 32'hz;
    endcase
  end

  // rw mux
  always @( chip_state or rw_rom or rw_shift or rw_crypt )
  begin
    case (chip_state)
      `CRYPT_INIT  : ram_rw = rw_rom;
      `SHIFT_SETUP : ram_rw = rw_shift;
      `ENCRYPT     : ram_rw = rw_crypt;
      default      : ram_rw = 32'hz;
    endcase
  end

  // addr mux
  always @( chip_state or addr_rom or addr_shift or addr_crypt )
  begin
    case (chip_state)
      `CRYPT_INIT  : ram_addr = addr_rom;
      `SHIFT_SETUP : ram_addr = addr_shift;
      `ENCRYPT     : ram_addr = addr_crypt;
      default      : ram_addr = 32'hz;
    endcase
  end

endmodule  // RAM_mux




module Key( clk, reset, address, r_w, char_in, data_in, data_out );
parameter KeyBytes    = 16;
parameter BytesPerWord = 4;
parameter NumWords = KeyBytes / BytesPerWord;
parameter KeyBits = KeyBytes * 8;
parameter AddrWidth = 2;
parameter TRUE = 1;
parameter FALSE = 0;

input clk, reset;
input [ AddrWidth-1 : 0 ] address;
input r_w;
input [7 : 0] char_in;
input [ 31 : 0 ] data_in;
output [ 31 : 0 ] data_out;

reg [ 31 : 0 ] data_out;
reg [ KeyBits-1 : 0 ] crypt_key;

  always @(posedge clk or posedge reset)
  begin : always_scope
    reg [4:0] byte_cnt;
    reg init, first_time;

    if (reset == 1)
    begin
      first_time = TRUE;
      init = TRUE;
    end
    else if (clk)
    begin
      if (init)
      begin

        if (first_time)
        begin
          first_time = FALSE;
          byte_cnt = 0;
        end
        else 
        begin
          byte_cnt = byte_cnt + 1;
        end

        // byte address for the key
        case (byte_cnt)
        5'd0   : crypt_key[  7:  0 ] = char_in;
        5'd1   : crypt_key[ 15:  8 ] = char_in;
        5'd2   : crypt_key[ 23: 16] = char_in;
        5'd3   : crypt_key[ 31: 24] = char_in;
        5'd4   : crypt_key[ 39: 32] = char_in;
        5'd5   : crypt_key[ 47: 40] = char_in;
        5'd6   : crypt_key[ 55: 48] = char_in;
        5'd7   : crypt_key[ 63: 56] = char_in;
        5'd8   : crypt_key[ 71: 64] = char_in;
        5'd9   : crypt_key[ 79: 72] = char_in;
        5'd10  : crypt_key[ 87: 80] = char_in;
        5'd11  : crypt_key[ 95: 88] = char_in;
        5'd12  : crypt_key[103: 96] = char_in;
        5'd13  : crypt_key[111:104] = char_in;
        5'd14  : crypt_key[119:112] = char_in;
        5'd15  : crypt_key[127:120] = char_in;
        default: init = FALSE;
        endcase
      end
      else // ! init
      begin
        // word address for the key
        if (r_w == `READ)
          case (address)
            2'd0 : crypt_key[ 31 : 0 ] = data_in;
            2'd1 : crypt_key[ 63 : 32] = data_in;
            2'd2 : crypt_key[ 95 : 64] = data_in;
            2'd3 : crypt_key[127 : 96] = data_in;
          endcase
        else // r_w == `WRITE
          case (address)
            2'd0 : data_out = crypt_key[ 31 : 0 ];
            2'd1 : data_out = crypt_key[ 63 : 32];
            2'd2 : data_out = crypt_key[ 95 : 64];
            2'd3 : data_out = crypt_key[127 : 96];
          endcase
      end // !init
    end // clk
  end // always

endmodule  // Key



module ROM( clk, address, data_out );
parameter TableSize = 32;
parameter DataWidth = 32;
parameter BitsInAddr = 5;

input clk;
input [BitsInAddr-1 : 0] address;
output [DataWidth-1 : 0] data_out;

reg [DataWidth-1 : 0] data_out;
reg [DataWidth-1:0] ROM[ TableSize-1 : 0 ];

  always @(posedge clk)
  begin
    // $display("%t: ROM: addr = %d", $time, address );
    // a ROM implemented as a large MUX with 
    // wired "magic" values
    case (address)
       0 : data_out <= 32'hb7e15163;
       1 : data_out <= 32'h5618cb1c; 
       2 : data_out <= 32'hf45044d5;
       3 : data_out <= 32'h9287be8e;
       4 : data_out <= 32'h30bf3847;
       5 : data_out <= 32'hcef6b200;
       6 : data_out <= 32'h6d2e2bb9;
       7 : data_out <= 32'h0b65a572;
       8 : data_out <= 32'ha99d1f2b;
       9 : data_out <= 32'h47d498e4;
      10 : data_out <= 32'he60c129d;
      11 : data_out <= 32'h84438c56;
      12 : data_out <= 32'h227b060f;
      13 : data_out <= 32'hc0b27fc8;
      14 : data_out <= 32'h5ee9f981;
      15 : data_out <= 32'hfd21733a;
      16 : data_out <= 32'h9b58ecf3;
      17 : data_out <= 32'h399066ac;
      18 : data_out <= 32'hd7c7e065;
      19 : data_out <= 32'h75ff5a1e;
      20 : data_out <= 32'h1436d3d7;
      21 : data_out <= 32'hb26e4d90;
      22 : data_out <= 32'h50a5c749;
      23 : data_out <= 32'heedd4102;
      24 : data_out <= 32'h8d14babb;
      25 : data_out <= 32'h2b4c3474;
      26 : data_out <= 32'hc983ae2d;
      27 : data_out <= 32'h67bb27e6;
      28 : data_out <= 32'h05f2a19f;
      29 : data_out <= 32'ha42a1b58;
      30 : data_out <= 32'h42619511;
      31 : data_out <= 32'he0990eca;
    endcase
  end

endmodule  // ROM



//
// RAM_init - RAM initialization control logic
//
module RAM_init( clk, reset, rom_addr, ram_init_addr, r_w, done );

parameter TableSize = 32;
parameter DataWidth = 32;
parameter BitsInAddr = 5;
parameter FALSE = 0;
parameter TRUE = 1;

input clk, reset;
output [BitsInAddr-1 : 0] rom_addr, ram_init_addr;
output r_w, done;

reg [BitsInAddr-1 : 0] rom_addr, ram_init_addr;
reg r_w, done;

reg [3:0] state;
reg first_time;

  //
  // Send address to ROM
  // 
  always @(posedge clk or posedge reset)
  begin
    if (reset == 1)
    begin
      r_w = `READ;
      state = `CRYPT_INIT;
      done = FALSE;
      rom_addr = 0;
      ram_init_addr = 0;
      first_time = TRUE;
    end
    else if (state == `CRYPT_INIT)
    begin
      r_w = `WRITE;
      if (first_time)
        first_time = FALSE;
      else
        ram_init_addr <= ram_init_addr + 1;

      rom_addr <= rom_addr + 1;
      
      if (ram_init_addr == TableSize )
      begin
        done = TRUE;
        state = `INIT_DONE;
      end
    end // if CRYPT_INIT
    //$display("%t: RAM_init: rom_addr = %d, ram_addr = %d", $time,
    //         rom_addr, ram_init_addr );
  end  // always

endmodule  // RAM_init



/*

  This design is intended to be part of a larger design.  So signals
  exist that are not driven, since those pieces of the design are not
  present here.

 */
module RC5_chip( clk, reset, char_in, char_out );
parameter TableSize = 32;
parameter DataWidth = 32;
parameter BitsInAddr = 5;
input clk, reset;
input [7:0] char_in;
output [7:0] char_out;

wire [BitsInAddr-1 : 0] address, rom_addr, ram_init_addr, addr_shift, addr_crypt;
wire [DataWidth-1 : 0] data_in, rom_data, shift_data, crypt_data;
wire [DataWidth-1 : 0] data_out;
wire ram_init_done, shift_done;
wire r_w, rw_rom, rw_shift, rw_crypt;

wire [ 31 : 0 ] key_data_in;
wire [ 31 : 0 ] key_data_out;
reg [ 1 : 0 ] key_addr;
wire ram_clk;

  // RAM is basicly clocked on the negedge of system clock
  assign ram_clk = ~clk;

// reg [DataWidth-1 : 0] shift_data, crypt_data;

reg [1:0] chip_state;

  // make sure that all undriven signals are grounded
  // to avoid pruning by evil Xilinks tools.
  assign shift_data = 0,
         crypt_data = 0,
         rw_shift = 0,
         rw_crypt = 0,
         addr_shift = 0,
         addr_crypt = 0,
         shift_done = 0;
  
  RamTable tbl       ( ram_clk, address, data_in, r_w, data_out );

  RAM_mux  ram_bus   ( rom_data, shift_data, crypt_data, 
                       rw_rom, rw_shift, rw_crypt,
                       ram_init_addr, addr_shift, addr_crypt,
                       chip_state, 
                       data_in,
                       r_w,
                       address );

  ROM      rom       ( clk, rom_addr, rom_data );
  RAM_init init_cntl ( clk, reset, rom_addr, ram_init_addr, rw_rom, ram_init_done );

  Key      crypt_key ( clk, reset, key_addr, r_w, char_in, key_data_in, key_data_out );

  always @(posedge ram_init_done or posedge shift_done or posedge reset)
  begin
    if (ram_init_done == 1)
       chip_state = `SHIFT_SETUP;
    else if (shift_done == 1)
       chip_state = `ENCRYPT;
    else if (reset == 1)
      chip_state = `CRYPT_INIT;
  end

endmodule



module check_key( go, key_passed );
parameter TableSize = 32;
parameter FALSE = 0;
parameter TRUE = 1;
input go;
output key_passed;

reg key_passed;

  always @(posedge go)
  begin : check_key_block
    integer i;

    key_passed = TRUE;

    // check that the key was properly initialized
    for (i = 0; i <= TableSize; i = i + 1)
    begin
        case (i)
        5'd0   : if (testbench.design.crypt_key.crypt_key[  7:  0 ] != testbench.key[15])
                    key_passed = FALSE;
        5'd1   : if (testbench.design.crypt_key.crypt_key[ 15:  8 ] != testbench.key[14])
                    key_passed = FALSE;
        5'd2   : if (testbench.design.crypt_key.crypt_key[ 23: 16] != testbench.key[13])
                    key_passed = FALSE;
        5'd3   : if (testbench.design.crypt_key.crypt_key[ 31: 24] != testbench.key[12])
                    key_passed = FALSE;
        5'd4   : if (testbench.design.crypt_key.crypt_key[ 39: 32] != testbench.key[11])
                    key_passed = FALSE;
        5'd5   : if (testbench.design.crypt_key.crypt_key[ 47: 40] != testbench.key[10])
                    key_passed = FALSE;
        5'd6   : if (testbench.design.crypt_key.crypt_key[ 55: 48] != testbench.key[9])
                    key_passed = FALSE;
        5'd7   : if (testbench.design.crypt_key.crypt_key[ 63: 56] != testbench.key[8])
                    key_passed = FALSE;
        5'd8   : if (testbench.design.crypt_key.crypt_key[ 71: 64] != testbench.key[7])
                    key_passed = FALSE;
        5'd9   : if (testbench.design.crypt_key.crypt_key[ 79: 72] != testbench.key[6])
                    key_passed = FALSE;
        5'd10  : if (testbench.design.crypt_key.crypt_key[ 87: 80] != testbench.key[5])
                    key_passed = FALSE;
        5'd11  : if (testbench.design.crypt_key.crypt_key[ 95: 88] != testbench.key[4])
                    key_passed = FALSE;
        5'd12  : if (testbench.design.crypt_key.crypt_key[103: 96] != testbench.key[3])
                    key_passed = FALSE;
        5'd13  : if (testbench.design.crypt_key.crypt_key[111:104] != testbench.key[2])
                    key_passed = FALSE;
        5'd14  : if (testbench.design.crypt_key.crypt_key[119:112] != testbench.key[1])
                    key_passed = FALSE;
        5'd15  : if (testbench.design.crypt_key.crypt_key[127:120] != testbench.key[0])
                    key_passed = FALSE;
        endcase
    end

    if (! key_passed)
    begin
      $display("key improperly initialized");
    end
  end  // always

endmodule  // check_key



module check_ram( go, table_passed );
parameter TableSize = 32;
parameter FALSE = 0;
parameter TRUE = 1;
input go;
output table_passed;

reg table_passed;

  always @(posedge go)
  begin : check_ram_block
    integer i;

    table_passed = TRUE;

    // make sure that the RAM table was initialized properly.
    for (i = 0; (i < TableSize) && table_passed; 
	i = (table_passed) ? i + 1 : i )
    begin
      case (i)
         0 : if (testbench.design.tbl.Table[i] != 32'hb7e15163)
                table_passed = FALSE;
         1 : if (testbench.design.tbl.Table[i] != 32'h5618cb1c)
                table_passed = FALSE;
         2 : if (testbench.design.tbl.Table[i] != 32'hf45044d5)
                table_passed = FALSE;
         3 : if (testbench.design.tbl.Table[i] != 32'h9287be8e)
                table_passed = FALSE;
         4 : if (testbench.design.tbl.Table[i] != 32'h30bf3847)
                table_passed = FALSE;
         5 : if (testbench.design.tbl.Table[i] != 32'hcef6b200)
                table_passed = FALSE;
         6 : if (testbench.design.tbl.Table[i] != 32'h6d2e2bb9)
                table_passed = FALSE;
         7 : if (testbench.design.tbl.Table[i] != 32'h0b65a572)
                table_passed = FALSE;
         8 : if (testbench.design.tbl.Table[i] != 32'ha99d1f2b)
                table_passed = FALSE;
         9 : if (testbench.design.tbl.Table[i] != 32'h47d498e4)
                table_passed = FALSE;
        10 : if (testbench.design.tbl.Table[i] != 32'he60c129d)
                table_passed = FALSE;
        11 : if (testbench.design.tbl.Table[i] != 32'h84438c56)
                table_passed = FALSE;
        12 : if (testbench.design.tbl.Table[i] != 32'h227b060f)
                table_passed = FALSE;
        13 : if (testbench.design.tbl.Table[i] != 32'hc0b27fc8)
                table_passed = FALSE;
        14 : if (testbench.design.tbl.Table[i] != 32'h5ee9f981)
                table_passed = FALSE;
        15 : if (testbench.design.tbl.Table[i] != 32'hfd21733a)
                table_passed = FALSE;
        16 : if (testbench.design.tbl.Table[i] != 32'h9b58ecf3)
                table_passed = FALSE;
        17 : if (testbench.design.tbl.Table[i] != 32'h399066ac)
                table_passed = FALSE;
        18 : if (testbench.design.tbl.Table[i] != 32'hd7c7e065)
                table_passed = FALSE;
        19 : if (testbench.design.tbl.Table[i] != 32'h75ff5a1e)
                table_passed = FALSE;
        20 : if (testbench.design.tbl.Table[i] != 32'h1436d3d7)
                table_passed = FALSE;
        21 : if (testbench.design.tbl.Table[i] != 32'hb26e4d90)
                table_passed = FALSE;
        22 : if (testbench.design.tbl.Table[i] != 32'h50a5c749)
                table_passed = FALSE;
        23 : if (testbench.design.tbl.Table[i] != 32'heedd4102)
                table_passed = FALSE;
        24 : if (testbench.design.tbl.Table[i] != 32'h8d14babb)
                table_passed = FALSE;
        25 : if (testbench.design.tbl.Table[i] != 32'h2b4c3474)
                table_passed = FALSE;
        26 : if (testbench.design.tbl.Table[i] != 32'hc983ae2d)
                table_passed = FALSE;
        27 : if (testbench.design.tbl.Table[i] != 32'h67bb27e6)
                table_passed = FALSE;
        28 : if (testbench.design.tbl.Table[i] != 32'h05f2a19f)
                table_passed = FALSE;
        29 : if (testbench.design.tbl.Table[i] != 32'ha42a1b58)
                table_passed = FALSE;
        30 : if (testbench.design.tbl.Table[i] != 32'h42619511)
                table_passed = FALSE;
        31 : if (testbench.design.tbl.Table[i] != 32'he0990eca)
                table_passed = FALSE;
      endcase
    end

    if (! table_passed)
    begin
      $display("encryption table improperly initialized");
      $display("testbench.design.tbl.Table[%d] = %h", i, testbench.design.tbl.Table[i] );
    end

  end // always

endmodule  // check_ram


//
// Master module to control the write of ROM to RAM and
// to verify that data was written correctly.
//
module testbench;
parameter FALSE = 0;
parameter TRUE = 1;
parameter TableSize = 32;
reg [7:0] key[ 15:0];
reg master_clock, reset;
reg [7:0] char_in;
wire [7:0] char_out;

reg do_key_check, do_ram_check;
wire key_check_rslt, ram_check_rslt;

  RC5_chip design ( master_clock, reset, char_in, char_out );

  check_key u1 ( do_key_check, key_check_rslt );
  check_ram u2 ( do_ram_check, ram_check_rslt );

  initial
  begin : init
    reg passed, key_passed, table_passed;
    integer i;

/*
    $gr_waves("ram_clk",  design.tbl.clk,
	      "ram_adr",  design.tbl.address,
	      "ram_rw",   design.tbl.r_w,
              "ram_din",  design.tbl.data_in,
              "rom_clk",  design.rom.clk,
              "rom_adr",  design.rom.address,
	      "rom_data", design.rom.data_out );
*/
	
    key_passed = TRUE;
    table_passed = TRUE;
    passed = TRUE;

    key[ 0 ] = "o";
    key[ 1 ] = "n";
    key[ 2 ] = "e";
    key[ 3 ] = "s";
    key[ 4 ] = "t";
    key[ 5 ] = "e";
    key[ 6 ] = "p";
    key[ 7 ] = "o";
    key[ 8 ] = "v";
    key[ 9 ] = "e";
    key[10 ] = "r";
    key[11 ] = "t";
    key[12 ] = "h";
    key[13 ] = "e";
    key[14 ] = "l";
    key[15 ] = "n";

    $display("ram_rom_init.v: this test takes a while in software simulation");

    master_clock = 1;  // start with a negedge clock transition
    reset = 0;         // toggle the reset line
    #1
    reset = ~reset;                // reset = 1
    master_clock = ~master_clock;  // clk == 0
    #1;
    reset = 0;
    // clock the ROM to RAM transfer
    for (i = 0; i <= TableSize; i = i + 1)
    begin
      if (i < 16)
         char_in = key[ 15 - i ];
      master_clock = ~master_clock;
      #1;
      master_clock = ~master_clock;
      #1;
    end

    // check that the key and RAM were initialized properly
    do_key_check = 0;
    #1 do_key_check = ~do_key_check;

    do_ram_check = 0;
    #1 do_ram_check = ~do_ram_check;

    #1;

    if (! ram_check_rslt )
    begin
      for (i = 0; i < TableSize; i = i + 1)
      begin
        $display("design.tbl.Table[%d] = %h", i, design.tbl.Table[i] );
      end
    end

    if (passed)
      passed = ram_check_rslt & key_check_rslt;

    if (passed)
      $display("Test passed");
    else
      $display("Test failed");

     $finish;
  end

endmodule  // testbench

back to C as a hardware design language