// Code for reading and writing any byte in a 32-bit word.

// Using in LSU EE 4702-1 Spring 2000

// Modules named part_select read the BYTE of WORD specified by PART.
// Modules named part_write write the BYTE of WORD specified by PART on CLK.

// All of the modules work, the number of gates synthesized by Leonardo
// is given in the comments.  They are organized from best to worst.

// If anyone can do better, please let me know.


//`define S
`define Cl

//
// Read a byte.
//

`ifdef S
// Optimize area:  Number of gates :                     205
module part_select(byte,part,word);
   input part, word;
   output byte;

   wire [1:0] part;
   wire [31:0] word;
   wire [7:0]  byte;

   assign      byte = word >> {part,3'b0};

endmodule // part_select
`endif

`ifdef Sb
// Optimize area: Number of gates :                     205
module part_select(byte,part,word);
   input part, word;
   output byte;

   wire [1:0] part;
   wire [31:0] word;
   wire [7:0]  byte;

   assign byte = { word[{part,3'd7}], word[{part,3'd6}],
                   word[{part,3'd5}], word[{part,3'd4}],
                   word[{part,3'd3}], word[{part,3'd2}],
                   word[{part,3'd1}], word[{part,3'd0}]};

endmodule // part_select
`endif

`ifdef C
// Optimize area: Number of gates :                     205
module part_select(byte,part,word);
   input part, word;
   output byte;

   wire [1:0] part;
   wire [31:0] word;
   reg [7:0]  byte;

   always @( part or word )
       case( part )
         0: byte = word[7:0];
         1: byte = word[15:8];
         2: byte = word[23:16];
         3: byte = word[31:24];
       endcase // case( head_word )
endmodule // part_select
`endif // ifdef C

//
// Write a byte.
//

`ifdef Cl
// Optimize area: Number of gates :                     312, 910 MHz
module part_write(byte,part,word,clk);
   input part, byte, clk;
   output word;

   wire [1:0] part;
   reg [31:0] word;
   wire [7:0] byte;

   // exemplar translate_off
   initial word = 0;
   // exemplar translate_on

   // Note: Since hardware should not be synthesized for i it would be
   // good style to declare it an integer, however Leonardo doesn't
   // allow bit selects on integers.
   reg [6:0] i;

   always @( posedge clk ) 
     for(i=0; i<31; i=i+1) if( i[4:3] === part ) word[i] = byte[i[2:0]];

endmodule // part_select
`endif

`ifdef Cw
// Optimize area: Number of gates :                     316, 910 MHz
module part_write(byte,part,word,clk);
   input part, byte, clk;
   output word;

   wire [1:0] part;
   reg [31:0] word;
   wire [7:0] byte;

   // exemplar translate_off
   initial word = 0;
   // exemplar translate_on

   always @( posedge clk )
     case( part )
       0: word[7:0] = byte;
       1: word[15:8] = byte;
       2: word[23:16] = byte;
       3: word[31:24] = byte;
     endcase // case( part )

endmodule 
`endif


`ifdef Sw
// Optimize Area: Number of gates :                     477,  710.6 MHz
module part_write(byte,part,word,clk);
   input part, byte, clk;
   output word;

   wire [1:0] part;
   reg [31:0] word;
   wire [7:0] byte;

   // exemplar translate_off
   initial word = 0;
   // exemplar translate_on

   always @( posedge clk )
     word = ( word & ~( 8'hff << {part,3'b0} ) ) | (byte << {part,3'b0});

endmodule 
`endif


`ifdef Wb
// Optimize Area: Number of gates :                     552, 513.1 MHz
module part_write(byte,part,word,clk);
   input part, byte, clk;
   output word;

   wire [1:0] part;
   reg [31:0] word;
   wire [7:0]  byte;

   always @( posedge clk )
     { word[{part,3'd7}], word[{part,3'd6}],
       word[{part,3'd5}], word[{part,3'd4}],
       word[{part,3'd3}], word[{part,3'd2}],
       word[{part,3'd1}], word[{part,3'd0}] } = byte;

endmodule 
`endif


`ifdef Cb
// Optimize area: Number of gates :                     751, 407 MHz
module part_write(byte,part,word,clk);
   input part, byte, clk;
   output word;

   wire [1:0] part;
   reg [31:0] word;
   wire [7:0] byte;

   // exemplar translate_off
   initial word = 0;
   // exemplar translate_on

//   reg        [31:-32] bigword;  // Leo can't handle negative indices
   reg        [63:0] bigword;

   always @( byte or part or word )
     begin
        bigword = {word,32'd0} >> { part, 3'b0 };
        bigword[39:32] = byte;
        bigword = bigword << { part, 3'b0 };
     end
   
   always @( posedge clk ) word = bigword[63:32];
   
endmodule 
`endif


// exemplar translate_off
module test_ps();

   reg [1:0] p,p2;
   reg [31:0] w;
   wire [31:0] w2;
   wire [7:0] n;
   reg [7:0] n2;
   reg        clk;
   
   part_select ps(n,p,w);
   part_write pw(n2,p2,w2,clk);

   integer    i;

   initial begin

      w = 0;
      n2 = 0;
      p2 = 0; clk = 0;
      
      for(i=0;i<4;i=i+1) begin
         w=w>>8;w[31:24] = i;
         n2 = i; p2 = i; #1; clk = 1; #1; clk = 0;
      end

      if( w2 !== w ) begin $display("Unexpected output."); $stop; end
      
      p = 0;
      
      begin:F forever begin
         #1;
         if( n != p ) begin $display("Unexpected output."); $stop; end
         #1;
         p = p + 1;
         if( !p ) disable F;
      end end
      
   end

endmodule // test_ps
// exemplar translate_on