I realized an AES-256 algorithm which encrypts a 128-bit std_logic_vector (plain_text) with a 256-bit std_logic_vector (master_key). I made a test-bench in order to verify the behavior of the encryption process, and now I would like to implement this algorithm on my Basys3 board (I use Vivado as IDE). My questions are:

How can I map the input vectors? Should I declare signals in my architecture, knowing that I do not have enough I/O ports?

  • \$\begingroup\$ How will the 128bit plain text vector get into the FPGA? \$\endgroup\$
    – po.pe
    Commented Jun 20, 2018 at 7:03
  • 1
    \$\begingroup\$ Make a serial communication interface (e.g. USB, SPI, I2C, etc.) to write to registers on your FPGA. \$\endgroup\$
    – HKOB
    Commented Jun 20, 2018 at 7:19

2 Answers 2


A serial interface uses the least amount of pins. From all the serial interfaces SPI is the easiest to implement. (I think it is about five lines of code). As an SPI interface streams data in and out at the same time you can also use it to read the result.

Ok, I just tried and it was a bit more then five lines mostly dealing with the synchronisation of the SPI signals to an (internal higher frequency) system clock.

The following code was quickly hacked together and seems to work:

// Simple dumb SPI interface:
// one big long shift register
// Relies on a system clock which is 
// much faster then the SPI clock
// User MUST send the right amount of bits in one go.

module spi_dumb 
#(parameter DW   = 128) // Number of internal data bits
    // Usual system signals
    input  clk,     // system clock
    input  reset_n, // system reset

    // SPI interface
    input  sclk,
    input  sel_n,
    input  mosi,
    output miso,

    // Internal data interface
    input      [DW-1:0] par_tx, // Data to transmit
    output reg [DW-1:0] par_rx, // Data received
    output reg          valid   // Data has arrived

reg  sclk_meta,sclk_sync,sclk_prev;
reg  seln_meta,seln_sync,seln_prev;
wire clock_edge;

//   assign clock_edge = ~sclk_prev &  sclk_sync; // Rising edge
   assign clock_edge =  sclk_prev & ~sclk_sync; // Falling edge

   always @(posedge clk or negedge reset_n)
      if (!reset_n)
         valid     <= 1'b0;
         sclk_meta <= 1'b0;
         sclk_sync <= 1'b0;
         sclk_prev <= 1'b0;
         seln_meta <= 1'b0;
         seln_sync <= 1'b0;
         seln_prev <= 1'b0;
         // Sychronise the clkc and select
         sclk_meta <= sclk;
         sclk_sync <= sclk_meta;
         sclk_prev <= sclk_sync;
         seln_meta <= sel_n;
         seln_sync <= seln_meta;
         seln_prev <= seln_sync;

         // On falling edge SPI-Select load the shift register
         if (seln_prev & ~seln_sync)
            par_rx <= par_tx;
            valid  <= 1'b0;

         // On rising edge SPI-Select mark the data as valid
         if (~seln_prev & seln_sync)
            valid  <= 1'b1;

         // If SPI select is low and we have a clock edge pick up the data
         // We assume the mosi data is stable by then
         // (~Two system clocks after SPI clock edge)
         if (!seln_prev && clock_edge)
           par_rx <= {par_rx[DW-2:0],mosi};

   assign miso = par_rx[DW-1];


 * Auto generated testbench, generated Wed Jun 20 11:04:23 2018
 * post edited

module spi_dumb_test;

localparam CLK_PERIOD=100;

localparam DW= 128;

    // Usual system signals
reg           clk; // system clock
reg           reset_n; // system reset

    // SPI interface
reg           sclk;
reg           sel_n;
reg           mosi;
wire          miso;

    // Internal data interface
reg  [DW-1:0] par_tx; // Data to transmit
wire [DW-1:0] par_rx; // Data received
wire          valid;

integer bit_count;
reg  [DW-1:0] master_tx; // Data to transmit
reg  [DW-1:0] master_rx; // Data received

    // Usual system signals
      reset_n  = 1'b0;

    // SPI interface
      sclk     = 1'b0;
      sel_n    = 1'b1;
      mosi     = 1'b0;

    // Internal data interface
      par_tx   = 'b0;
      #(5*CLK_PERIOD) reset_n=1'b1;

      #(5*CLK_PERIOD) sel_n = 1'b0;

      par_tx    = 128'h12345678_11111111_87654321_A5C33C5A;
      master_tx = 128'h23242526_34353637_45464748_56575859;

      for (bit_count=0; bit_count<128; bit_count=bit_count+1)
         #(5*CLK_PERIOD) ;

         // Tx & RX master emulation, MS bits first
         mosi = master_tx[DW-bit_count-1];
         master_rx[DW-bit_count-1] = miso;
         sclk = 1'b1;
         #(5*CLK_PERIOD) ;
         sclk = 1'b0;
      #(5*CLK_PERIOD) ;
      sel_n = 1'b1;

      #(50*CLK_PERIOD) $stop;

   #( .DW (DW) ) // parameters
spi_dumb_0 (

    // Usual system signals
      .clk    (clk),     // system clock
      .reset_n(reset_n), // system reset

    // SPI interface
      .sclk   (sclk),
      .sel_n  (sel_n),
      .mosi   (mosi),
      .miso   (miso),

    // Internal data interface
      .par_tx (par_tx),  // Data to transmit
      .par_rx (par_rx),  // Data received
      .valid  (valid) 

   // Generate clock.
      clk = 1'b0;
         #(CLK_PERIOD/2) clk = ~clk;


Post edit 2-7-18: found that begin end pair was missing.

  • \$\begingroup\$ This obviously shouldn't become a "compare all serial protocols" thread, but the reason I wouldn't advise SPI to beginners is because the world still hasn't decided on what the SPI protocol is. It'd work, but require more fiddling than other, more standardized protocols. Also: writing it the easy, terse way tends to lead to clock domain transitions. That all being said: +1, of course. \$\endgroup\$
    – DonFusili
    Commented Jun 20, 2018 at 8:46
  • \$\begingroup\$ I started writing one and have updated my answer. I might post the code once it is verified. (Which takes 10x longer then writing the code) \$\endgroup\$
    – Oldfart
    Commented Jun 20, 2018 at 9:00
  • \$\begingroup\$ Thank you very much, I appreciate your help. I will look for further information about SPI ! \$\endgroup\$
    – Cedric
    Commented Jun 20, 2018 at 9:37

The Basys3 board has a USB to UART interface. Use this to implement a UART link with your computer. I haven't yet seen a computer running windows or Linux that doesn't support UART over COM/tty.

There are a number of open source UART cores, but I'd advise writing it yourself, most of them are not worth much and a UART isn't hard to write anyway.

(De)serializing is the same as filling/emptying a shift register over the UART.

  • \$\begingroup\$ Thank you for your reply, then I will start to study how UART works ! \$\endgroup\$
    – Cedric
    Commented Jun 20, 2018 at 9:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.