Assignment 4
CMPE RSD FALL 2026 ASSIGNMENT 4

Ryan Robucci

UMBC-CSEE-LOGO

P1 Tutorial

Shell Prerequisite: bash

These instructions were tested on cadence1.cs.umbc.edu using a bash shell.

The following command reveals your shell

echo $0

if the result is tcsh, start a bash shell

exec bash -il

create assignment directory ➕📂 ~/CMPERSD/ASGMT4

The assumed directory for this tutorial is ~/CMPERSD/ASGMT4/P1

mkdir -p $HOME/CMPERSD/ASGMT4/P1
cd $HOME/CMPERSD/ASGMT4/P1
mkdir -p src/tb; mkdir -p src/rtl; mkdir -p src/constraints; mkdir -p docs; mkdir -p src/ip; mkdir -p scripts;

Create Verilog Design Files

Create RAM Module Verilog RTL file ➕📄 rams_sp_wf.v, in 📂 src/rtl :

`timescale 1ns/1ps
// Single-Port Block RAM Write-First Mode (recommended template)
// File: rams_sp_wf.v
module rams_sp_wf (clk, we, en, addr, di, dout);
   input clk;
   input we;
   input en;
   input [5:0] addr;
   input [9:0] di;
   output [9:0] dout;
   reg [9:0]    RAM [0:63];
   reg [9:0]    dout;

   always @(posedge clk) begin
      if (en) begin
    if (we) begin
    RAM[addr] <= di;
       dout <= di;
         end else begin
            dout <= RAM[addr];
         end
      end
   end
endmodule // rams_sp_wf

Create TOP (FPGA) module Verilog file ➕📄 top.sv, in 📂 src/rtl :

//file: top.sv
module top(LED, SW,BTNL,BTNR,/*CPU_RESETN,*/ CLK100MHZ);

   output [9:0] LED;
   input [15:0] SW;
   input        BTNR;
   input        BTNL;
   /*input   CPU_RESETN;*/
   input        CLK100MHZ;

   logic        rst;
   /*assign rst=~CPU_RESETN;*/
   rams_sp_wf ram_inst (.clk(CLK100MHZ),
                     .we(BTNR),
                     .en(BTNL),
                     .addr(SW[15:10]),
                     .di(SW[9:0]),
                     .dout(LED));
endmodule

Create Testbenches

Create RAM testbench ➕📄 rams_sp_wf_tb.sv, in 📂 src/tb

`timescale 1ns/1ps
//filename: rams_sp_wf_tb.sv

module rams_sp_wf_tb;

   /*input*/ logic [7:0] addr;
   /*input*/ logic clk;
   /*input*/ logic [15:0] di;
   /*output*/ logic [15:0] dout;
   /*input*/ logic en;
   /*input*/ logic we;

   rams_sp_wf dut(clk, we, en, addr, di, dout);

   initial begin
      // Arguments: (unit_number, precision_digits, suffix_string, minimum_field_width)
      // -9 = 1ns unit base
      //  3 = show 3 digits after the decimal point (e.g., .454 for picoseconds)
      $timeformat(-9, 3, " ns", 10);
   end

`ifdef XCELIUM
    initial begin
       // Arguments: ("path_to_sdf", testbench_instantiation_name_of_dut)
       $shm_open("waves.shm");      // Creates a waveform directory named "waves.shm"
       $shm_probe("AS");            // Dumps All Signals (A) and memories/mem-ports (S)
    end
`endif
   initial begin
      clk =0;
      #10; clk =1;     
      forever #5 clk = ~clk;     
   end


   initial begin

      $monitor("%t,clk %b, we %b , en %b, addr %0d , di %0d , dout %0d ",$realtime,clk, we, en, addr, di, dout);
      @(posedge clk);
      addr<=5;
      di<=50;
      //output logic [15:0] dout;
      en<=1;
      we<=1;

      repeat (20) @(posedge clk);

      @(posedge clk);
      addr<=9;
      di<=90;

      repeat (10) @(posedge clk);

      we<=0;

      repeat (10) @(posedge clk);
      addr<=5;
      repeat (10) @(posedge clk);

      $finish;
   end   

endmodule // rams_sp_wf_tb

Create TOP testbench ➕📄 top_tb.sv, in 📂 src/tb

This file can be used to test the FULL FPGA design, including connections to pins

`timescale 1ns/1ps
//filename: top_tb.sv

module top_tb;

   logic [9:0] LED;
   logic [15:0] SW;
   logic CLK100MHZ;
   logic BTNL;
   logic BTNR;

   top dut(.*);
   /* same as:
    top dut (
      .LED(LED),
      .SW(SW),
      .CLK100MHZ(CLK100MHZ),
      .BTNL(BTNL),
      .BTNR(BTNR)
      );
    */

   logic [9:0] dout;
   logic [5:0] addr;
   logic clk;
   logic [9:0] di;
   logic en;
   logic we;


   assign dout=LED;
   assign CLK100MHZ=clk;
   assign SW[9:0]=di;
   assign SW[15:10]=addr;
   assign BTNR=en;
   assign BTNL=we;   

   initial begin
      // Arguments: (unit_number, precision_digits, suffix_string, minimum_field_width)
      // -9 = 1ns unit base
      //  3 = show 3 digits after the decimal point (e.g., .454 for picoseconds)
      $timeformat(-9, 3, " ns", 10);
   end

`ifdef XCELIUM
    initial begin
       // Arguments: ("path_to_sdf", testbench_instantiation_name_of_dut)
       $shm_open("waves.shm");      // Creates a waveform directory named "waves.shm"
       $shm_probe("AS");            // Dumps All Signals (A) and memories/mem-ports (S)
    end
`endif



   initial begin
      clk =0;
      #10; clk =1;     
      forever #5 clk = ~clk;     
   end


   initial begin


`ifdef RSD_PRIMARY_INPUT_DELAY 
   $display("RSD_PRIMARY_INPUT_DELAY:%f",`RSD_PRIMARY_INPUT_DELAY);  
`endif

`ifdef RSD_POST_IMPLEMENTATION_SIM
      //structure is not preserved through synthesis and implemenation, so access testbench scope signals only
      $monitor("%t, *tb clk:%b en:%b we:%b addr:%0d di:%0d dout:%0d,     *top LED:%8d SW:%06b(%03d)_%010b(%03d) CLK100MHZ:%0b BTNL:%b BTNR:%b",$realtime,clk, en, we, addr, di, dout, LED, SW[15:10],SW[15:10],SW[9:0],SW[9:0],CLK100MHZ,BTNL,BTNR);
`else
      $monitor("%t, *ram clk:%b en:%b we:%b addr:%0d di:%0d dout:%0d,     *top LED:%8d SW:%06b(%03d)_%010b(%03d) CLK100MHZ:%0b BTNL:%b BTNR:%b",$realtime,dut.ram_inst.clk, dut.ram_inst.en, dut.ram_inst.we, dut.ram_inst.addr, dut.ram_inst.di, dut.ram_inst.dout, LED, SW[15:10],SW[15:10],SW[9:0],SW[9:0],CLK100MHZ,BTNL,BTNR);
`endif

      @(posedge clk);
`ifdef RSD_PRIMARY_INPUT_DELAY 
      #`RSD_PRIMARY_INPUT_DELAY
`endif     
      addr<=5;
      di<=50;
      //output logic [15:0] dout;
      en<=1;
      we<=1;

      repeat (20) @(posedge clk);

      @(posedge clk);
`ifdef RSD_PRIMARY_INPUT_DELAY 
      #`RSD_PRIMARY_INPUT_DELAY
`endif
      addr<=9;
      di<=90;

      repeat (10) @(posedge clk);


      we<=0;

      repeat (10) @(posedge clk);
`ifdef RSD_PRIMARY_INPUT_DELAY 
      #`RSD_PRIMARY_INPUT_DELAY
`endif
      addr<=5;
      repeat (10) @(posedge clk);

      $finish;
   end   

endmodule // top_tb

Create constraints (xdf) file ➕📄 Nexys-4-DDR-Master.xdc , in 📂 src/constraints

Xilinx defines a format called Xilinx Design Constraints File (xdf) for defining things like port to physical pin connections and clock frequency constraints.

We will learn more about timing/frequency constraints later. Novices sometimes incorrectly assume that changing the clock frequency in this file somehow actually changes the physical operation of the of the system clock, but that is not so. It does not represent an instruction to program an oscillator, it mearly informs the design tool of target frequency for the design, which is defined by the actual preexisting clock installed on the board. The development board that you are using provides the FPGA with a system clock of 100 MHz. If the optimized design can not operate at the target frequency, then the tool will notify the designer.

## This file is a general .xdc for the Nexys A7-100T
## To use it in a project:
## - uncomment the lines corresponding to used pins
## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project
## Note: As the Nexys 4 DDR was rebranded to the Nexys A7 with no substantial changes, this XDC file will also work for the Nexys 4 DDR.

## Clock signal
set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports CLK100MHZ]
create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports CLK100MHZ]

##Switches
set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports {SW[0]}]
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports {SW[1]}]
set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS33} [get_ports {SW[2]}]
set_property -dict {PACKAGE_PIN R15 IOSTANDARD LVCMOS33} [get_ports {SW[3]}]
set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {SW[4]}]
set_property -dict {PACKAGE_PIN T18 IOSTANDARD LVCMOS33} [get_ports {SW[5]}]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports {SW[6]}]
set_property -dict {PACKAGE_PIN R13 IOSTANDARD LVCMOS33} [get_ports {SW[7]}]
set_property -dict {PACKAGE_PIN T8 IOSTANDARD LVCMOS18} [get_ports {SW[8]}]
set_property -dict {PACKAGE_PIN U8 IOSTANDARD LVCMOS18} [get_ports {SW[9]}]
set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS33} [get_ports {SW[10]}]
set_property -dict {PACKAGE_PIN T13 IOSTANDARD LVCMOS33} [get_ports {SW[11]}]
set_property -dict {PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports {SW[12]}]
set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {SW[13]}]
set_property -dict {PACKAGE_PIN U11 IOSTANDARD LVCMOS33} [get_ports {SW[14]}]
set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {SW[15]}]

## LEDs
set_property -dict { PACKAGE_PIN H17   IOSTANDARD LVCMOS33 } [get_ports { LED[0] }]; #IO_L18P_T2_A24_15 Sch=led[0]
set_property -dict { PACKAGE_PIN K15   IOSTANDARD LVCMOS33 } [get_ports { LED[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1]
set_property -dict { PACKAGE_PIN J13   IOSTANDARD LVCMOS33 } [get_ports { LED[2] }]; #IO_L17N_T2_A25_15 Sch=led[2]
set_property -dict { PACKAGE_PIN N14   IOSTANDARD LVCMOS33 } [get_ports { LED[3] }]; #IO_L8P_T1_D11_14 Sch=led[3]
set_property -dict { PACKAGE_PIN R18   IOSTANDARD LVCMOS33 } [get_ports { LED[4] }]; #IO_L7P_T1_D09_14 Sch=led[4]
set_property -dict { PACKAGE_PIN V17   IOSTANDARD LVCMOS33 } [get_ports { LED[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5]
set_property -dict { PACKAGE_PIN U17   IOSTANDARD LVCMOS33 } [get_ports { LED[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6]
set_property -dict { PACKAGE_PIN U16   IOSTANDARD LVCMOS33 } [get_ports { LED[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7]
set_property -dict { PACKAGE_PIN V16   IOSTANDARD LVCMOS33 } [get_ports { LED[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8]
set_property -dict { PACKAGE_PIN T15   IOSTANDARD LVCMOS33 } [get_ports { LED[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9]
#set_property -dict { PACKAGE_PIN U14   IOSTANDARD LVCMOS33 } [get_ports { LED[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10]
#set_property -dict { PACKAGE_PIN T16   IOSTANDARD LVCMOS33 } [get_ports { LED[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11]
#set_property -dict { PACKAGE_PIN V15   IOSTANDARD LVCMOS33 } [get_ports { LED[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12]
#set_property -dict { PACKAGE_PIN V14   IOSTANDARD LVCMOS33 } [get_ports { LED[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13]
#set_property -dict { PACKAGE_PIN V12   IOSTANDARD LVCMOS33 } [get_ports { LED[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14]
#set_property -dict { PACKAGE_PIN V11   IOSTANDARD LVCMOS33 } [get_ports { LED[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15]

## RGB LEDs
#set_property -dict { PACKAGE_PIN R12   IOSTANDARD LVCMOS33 } [get_ports { LED16_B }]; #IO_L5P_T0_D06_14 Sch=led16_b
#set_property -dict { PACKAGE_PIN M16   IOSTANDARD LVCMOS33 } [get_ports { LED16_G }]; #IO_L10P_T1_D14_14 Sch=led16_g
#set_property -dict { PACKAGE_PIN N15   IOSTANDARD LVCMOS33 } [get_ports { LED16_R }]; #IO_L11P_T1_SRCC_14 Sch=led16_r
#set_property -dict { PACKAGE_PIN G14   IOSTANDARD LVCMOS33 } [get_ports { LED17_B }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b
#set_property -dict { PACKAGE_PIN R11   IOSTANDARD LVCMOS33 } [get_ports { LED17_G }]; #IO_0_14 Sch=led17_g
#set_property -dict { PACKAGE_PIN N16   IOSTANDARD LVCMOS33 } [get_ports { LED17_R }]; #IO_L11N_T1_SRCC_14 Sch=led17_r

##7 segment display
#set_property -dict { PACKAGE_PIN T10   IOSTANDARD LVCMOS33 } [get_ports { CA }]; #IO_L24N_T3_A00_D16_14 Sch=ca
#set_property -dict { PACKAGE_PIN R10   IOSTANDARD LVCMOS33 } [get_ports { CB }]; #IO_25_14 Sch=cb
#set_property -dict { PACKAGE_PIN K16   IOSTANDARD LVCMOS33 } [get_ports { CC }]; #IO_25_15 Sch=cc
#set_property -dict { PACKAGE_PIN K13   IOSTANDARD LVCMOS33 } [get_ports { CD }]; #IO_L17P_T2_A26_15 Sch=cd
#set_property -dict { PACKAGE_PIN P15   IOSTANDARD LVCMOS33 } [get_ports { CE }]; #IO_L13P_T2_MRCC_14 Sch=ce
#set_property -dict { PACKAGE_PIN T11   IOSTANDARD LVCMOS33 } [get_ports { CF }]; #IO_L19P_T3_A10_D26_14 Sch=cf
#set_property -dict { PACKAGE_PIN L18   IOSTANDARD LVCMOS33 } [get_ports { CG }]; #IO_L4P_T0_D04_14 Sch=cg
#set_property -dict { PACKAGE_PIN H15   IOSTANDARD LVCMOS33 } [get_ports { DP }]; #IO_L19N_T3_A21_VREF_15 Sch=dp
#set_property -dict { PACKAGE_PIN J17   IOSTANDARD LVCMOS33 } [get_ports { AN[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0]
#set_property -dict { PACKAGE_PIN J18   IOSTANDARD LVCMOS33 } [get_ports { AN[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1]
#set_property -dict { PACKAGE_PIN T9    IOSTANDARD LVCMOS33 } [get_ports { AN[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2]
#set_property -dict { PACKAGE_PIN J14   IOSTANDARD LVCMOS33 } [get_ports { AN[3] }]; #IO_L19P_T3_A22_15 Sch=an[3]
#set_property -dict { PACKAGE_PIN P14   IOSTANDARD LVCMOS33 } [get_ports { AN[4] }]; #IO_L8N_T1_D12_14 Sch=an[4]
#set_property -dict { PACKAGE_PIN T14   IOSTANDARD LVCMOS33 } [get_ports { AN[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5]
#set_property -dict { PACKAGE_PIN K2    IOSTANDARD LVCMOS33 } [get_ports { AN[6] }]; #IO_L23P_T3_35 Sch=an[6]
#set_property -dict { PACKAGE_PIN U13   IOSTANDARD LVCMOS33 } [get_ports { AN[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7]

##Buttons
##CPU Reset Button
#set_property -dict { PACKAGE_PIN C12   IOSTANDARD LVCMOS33 } [get_ports { CPU_RESETN }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn

#set_property -dict { PACKAGE_PIN N17   IOSTANDARD LVCMOS33 } [get_ports { BTNC }]; #IO_L9P_T1_DQS_14 Sch=btnc
#set_property -dict { PACKAGE_PIN M18   IOSTANDARD LVCMOS33 } [get_ports { BTNU }]; #IO_L4N_T0_D05_14 Sch=btnu
set_property -dict { PACKAGE_PIN P17   IOSTANDARD LVCMOS33 } [get_ports { BTNL }]; #IO_L12P_T1_MRCC_14 Sch=btnl
set_property -dict { PACKAGE_PIN M17   IOSTANDARD LVCMOS33 } [get_ports { BTNR }]; #IO_L10N_T1_D15_14 Sch=btnr
#set_property -dict { PACKAGE_PIN P18   IOSTANDARD LVCMOS33 } [get_ports { BTND }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd

##Pmod Headers
##Pmod Header JA
#set_property -dict { PACKAGE_PIN C17   IOSTANDARD LVCMOS33 } [get_ports { JA[1] }]; #IO_L20N_T3_A19_15 Sch=ja[1]
#set_property -dict { PACKAGE_PIN D18   IOSTANDARD LVCMOS33 } [get_ports { JA[2] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2]
#set_property -dict { PACKAGE_PIN E18   IOSTANDARD LVCMOS33 } [get_ports { JA[3] }]; #IO_L21P_T3_DQS_15 Sch=ja[3]
#set_property -dict { PACKAGE_PIN G17   IOSTANDARD LVCMOS33 } [get_ports { JA[4] }]; #IO_L18N_T2_A23_15 Sch=ja[4]
#set_property -dict { PACKAGE_PIN D17   IOSTANDARD LVCMOS33 } [get_ports { JA[7] }]; #IO_L16N_T2_A27_15 Sch=ja[7]
#set_property -dict { PACKAGE_PIN E17   IOSTANDARD LVCMOS33 } [get_ports { JA[8] }]; #IO_L16P_T2_A28_15 Sch=ja[8]
#set_property -dict { PACKAGE_PIN F18   IOSTANDARD LVCMOS33 } [get_ports { JA[9] }]; #IO_L22N_T3_A16_15 Sch=ja[9]
#set_property -dict { PACKAGE_PIN G18   IOSTANDARD LVCMOS33 } [get_ports { JA[10] }]; #IO_L22P_T3_A17_15 Sch=ja[10]

##Pmod Header JB
#set_property -dict { PACKAGE_PIN D14   IOSTANDARD LVCMOS33 } [get_ports { JB[1] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1]
#set_property -dict { PACKAGE_PIN F16   IOSTANDARD LVCMOS33 } [get_ports { JB[2] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2]
#set_property -dict { PACKAGE_PIN G16   IOSTANDARD LVCMOS33 } [get_ports { JB[3] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3]
#set_property -dict { PACKAGE_PIN H14   IOSTANDARD LVCMOS33 } [get_ports { JB[4] }]; #IO_L15P_T2_DQS_15 Sch=jb[4]
#set_property -dict { PACKAGE_PIN E16   IOSTANDARD LVCMOS33 } [get_ports { JB[7] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7]
#set_property -dict { PACKAGE_PIN F13   IOSTANDARD LVCMOS33 } [get_ports { JB[8] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8]
#set_property -dict { PACKAGE_PIN G13   IOSTANDARD LVCMOS33 } [get_ports { JB[9] }]; #IO_0_15 Sch=jb[9]
#set_property -dict { PACKAGE_PIN H16   IOSTANDARD LVCMOS33 } [get_ports { JB[10] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10]

##Pmod Header JC
#set_property -dict { PACKAGE_PIN K1    IOSTANDARD LVCMOS33 } [get_ports { JC[1] }]; #IO_L23N_T3_35 Sch=jc[1]
#set_property -dict { PACKAGE_PIN F6    IOSTANDARD LVCMOS33 } [get_ports { JC[2] }]; #IO_L19N_T3_VREF_35 Sch=jc[2]
#set_property -dict { PACKAGE_PIN J2    IOSTANDARD LVCMOS33 } [get_ports { JC[3] }]; #IO_L22N_T3_35 Sch=jc[3]
#set_property -dict { PACKAGE_PIN G6    IOSTANDARD LVCMOS33 } [get_ports { JC[4] }]; #IO_L19P_T3_35 Sch=jc[4]
#set_property -dict { PACKAGE_PIN E7    IOSTANDARD LVCMOS33 } [get_ports { JC[7] }]; #IO_L6P_T0_35 Sch=jc[7]
#set_property -dict { PACKAGE_PIN J3    IOSTANDARD LVCMOS33 } [get_ports { JC[8] }]; #IO_L22P_T3_35 Sch=jc[8]
#set_property -dict { PACKAGE_PIN J4    IOSTANDARD LVCMOS33 } [get_ports { JC[9] }]; #IO_L21P_T3_DQS_35 Sch=jc[9]
#set_property -dict { PACKAGE_PIN E6    IOSTANDARD LVCMOS33 } [get_ports { JC[10] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10]

##Pmod Header JD
#set_property -dict { PACKAGE_PIN H4    IOSTANDARD LVCMOS33 } [get_ports { JD[1] }]; #IO_L21N_T3_DQS_35 Sch=jd[1]
#set_property -dict { PACKAGE_PIN H1    IOSTANDARD LVCMOS33 } [get_ports { JD[2] }]; #IO_L17P_T2_35 Sch=jd[2]
#set_property -dict { PACKAGE_PIN G1    IOSTANDARD LVCMOS33 } [get_ports { JD[3] }]; #IO_L17N_T2_35 Sch=jd[3]
#set_property -dict { PACKAGE_PIN G3    IOSTANDARD LVCMOS33 } [get_ports { JD[4] }]; #IO_L20N_T3_35 Sch=jd[4]
#set_property -dict { PACKAGE_PIN H2    IOSTANDARD LVCMOS33 } [get_ports { JD[7] }]; #IO_L15P_T2_DQS_35 Sch=jd[7]
#set_property -dict { PACKAGE_PIN G4    IOSTANDARD LVCMOS33 } [get_ports { JD[8] }]; #IO_L20P_T3_35 Sch=jd[8]
#set_property -dict { PACKAGE_PIN G2    IOSTANDARD LVCMOS33 } [get_ports { JD[9] }]; #IO_L15N_T2_DQS_35 Sch=jd[9]
#set_property -dict { PACKAGE_PIN F3    IOSTANDARD LVCMOS33 } [get_ports { JD[10] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10]

##Pmod Header JXADC
#set_property -dict { PACKAGE_PIN A14   IOSTANDARD LVCMOS33 } [get_ports { XA_N[1] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1]
#set_property -dict { PACKAGE_PIN A13   IOSTANDARD LVCMOS33 } [get_ports { XA_P[1] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1]
#set_property -dict { PACKAGE_PIN A16   IOSTANDARD LVCMOS33 } [get_ports { XA_N[2] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2]
#set_property -dict { PACKAGE_PIN A15   IOSTANDARD LVCMOS33 } [get_ports { XA_P[2] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2]
#set_property -dict { PACKAGE_PIN B17   IOSTANDARD LVCMOS33 } [get_ports { XA_N[3] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3]
#set_property -dict { PACKAGE_PIN B16   IOSTANDARD LVCMOS33 } [get_ports { XA_P[3] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3]
#set_property -dict { PACKAGE_PIN A18   IOSTANDARD LVCMOS33 } [get_ports { XA_N[4] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4]
#set_property -dict { PACKAGE_PIN B18   IOSTANDARD LVCMOS33 } [get_ports { XA_P[4] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4]

##VGA Connector
#set_property -dict {PACKAGE_PIN A3 IOSTANDARD LVCMOS33} [get_ports {VGA_R[0]}]
#set_property -dict {PACKAGE_PIN B4 IOSTANDARD LVCMOS33} [get_ports {VGA_R[1]}]
#set_property -dict {PACKAGE_PIN C5 IOSTANDARD LVCMOS33} [get_ports {VGA_R[2]}]
#set_property -dict {PACKAGE_PIN A4 IOSTANDARD LVCMOS33} [get_ports {VGA_R[3]}]
#set_property -dict {PACKAGE_PIN C6 IOSTANDARD LVCMOS33} [get_ports {VGA_G[0]}]
#set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports {VGA_G[1]}]
#set_property -dict {PACKAGE_PIN B6 IOSTANDARD LVCMOS33} [get_ports {VGA_G[2]}]
#set_property -dict {PACKAGE_PIN A6 IOSTANDARD LVCMOS33} [get_ports {VGA_G[3]}]
#set_property -dict {PACKAGE_PIN B7 IOSTANDARD LVCMOS33} [get_ports {VGA_B[0]}]
#set_property -dict {PACKAGE_PIN C7 IOSTANDARD LVCMOS33} [get_ports {VGA_B[1]}]
#set_property -dict {PACKAGE_PIN D7 IOSTANDARD LVCMOS33} [get_ports {VGA_B[2]}]
#set_property -dict {PACKAGE_PIN D8 IOSTANDARD LVCMOS33} [get_ports {VGA_B[3]}]
#set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS33} [get_ports VGA_HS]
#set_property -dict {PACKAGE_PIN B12 IOSTANDARD LVCMOS33} [get_ports VGA_VS]

##Micro SD Connector
#set_property -dict { PACKAGE_PIN E2    IOSTANDARD LVCMOS33 } [get_ports { SD_RESET }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset
#set_property -dict { PACKAGE_PIN A1    IOSTANDARD LVCMOS33 } [get_ports { SD_CD }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd
#set_property -dict { PACKAGE_PIN B1    IOSTANDARD LVCMOS33 } [get_ports { SD_SCK }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck
#set_property -dict { PACKAGE_PIN C1    IOSTANDARD LVCMOS33 } [get_ports { SD_CMD }]; #IO_L16N_T2_35 Sch=sd_cmd
#set_property -dict { PACKAGE_PIN C2    IOSTANDARD LVCMOS33 } [get_ports { SD_DAT[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0]
#set_property -dict { PACKAGE_PIN E1    IOSTANDARD LVCMOS33 } [get_ports { SD_DAT[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1]
#set_property -dict { PACKAGE_PIN F1    IOSTANDARD LVCMOS33 } [get_ports { SD_DAT[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2]
#set_property -dict { PACKAGE_PIN D2    IOSTANDARD LVCMOS33 } [get_ports { SD_DAT[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3]

##Accelerometer
#set_property -dict { PACKAGE_PIN E15   IOSTANDARD LVCMOS33 } [get_ports { ACL_MISO }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso
#set_property -dict { PACKAGE_PIN F14   IOSTANDARD LVCMOS33 } [get_ports { ACL_MOSI }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi
#set_property -dict { PACKAGE_PIN F15   IOSTANDARD LVCMOS33 } [get_ports { ACL_SCLK }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk
#set_property -dict { PACKAGE_PIN D15   IOSTANDARD LVCMOS33 } [get_ports { ACL_CSN }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn
#set_property -dict { PACKAGE_PIN B13   IOSTANDARD LVCMOS33 } [get_ports { ACL_INT[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1]
#set_property -dict { PACKAGE_PIN C16   IOSTANDARD LVCMOS33 } [get_ports { ACL_INT[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2]

##Temperature Sensor
#set_property -dict { PACKAGE_PIN C14   IOSTANDARD LVCMOS33 } [get_ports { TMP_SCL }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl
#set_property -dict { PACKAGE_PIN C15   IOSTANDARD LVCMOS33 } [get_ports { TMP_SDA }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda
#set_property -dict { PACKAGE_PIN D13   IOSTANDARD LVCMOS33 } [get_ports { TMP_INT }]; #IO_L6N_T0_VREF_15 Sch=tmp_int
#set_property -dict { PACKAGE_PIN B14   IOSTANDARD LVCMOS33 } [get_ports { TMP_CT }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct

##Omnidirectional Microphone
#set_property -dict { PACKAGE_PIN J5    IOSTANDARD LVCMOS33 } [get_ports { M_CLK }]; #IO_25_35 Sch=m_clk
#set_property -dict { PACKAGE_PIN H5    IOSTANDARD LVCMOS33 } [get_ports { M_DATA }]; #IO_L24N_T3_35 Sch=m_data
#set_property -dict { PACKAGE_PIN F5    IOSTANDARD LVCMOS33 } [get_ports { M_LRSEL }]; #IO_0_35 Sch=m_lrsel

##PWM Audio Amplifier
#set_property -dict { PACKAGE_PIN A11   IOSTANDARD LVCMOS33 } [get_ports { AUD_PWM }]; #IO_L4N_T0_15 Sch=aud_pwm
#set_property -dict { PACKAGE_PIN D12   IOSTANDARD LVCMOS33 } [get_ports { AUD_SD }]; #IO_L6P_T0_15 Sch=aud_sd

##USB-RS232 Interface
#set_property -dict { PACKAGE_PIN C4    IOSTANDARD LVCMOS33 } [get_ports { UART_TXD_IN }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in
#set_property -dict { PACKAGE_PIN D4    IOSTANDARD LVCMOS33 } [get_ports { UART_RXD_OUT }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out
#set_property -dict { PACKAGE_PIN D3    IOSTANDARD LVCMOS33 } [get_ports { UART_CTS }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts
#set_property -dict { PACKAGE_PIN E5    IOSTANDARD LVCMOS33 } [get_ports { UART_RTS }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts

##USB HID (PS/2)
#set_property -dict { PACKAGE_PIN F4    IOSTANDARD LVCMOS33 } [get_ports { PS2_CLK }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk

#set_property -dict { PACKAGE_PIN B2    IOSTANDARD LVCMOS33 } [get_ports { PS2_DATA }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data

##SMSC Ethernet PHY
#set_property -dict { PACKAGE_PIN C9    IOSTANDARD LVCMOS33 } [get_ports { ETH_MDC }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc
#set_property -dict { PACKAGE_PIN A9    IOSTANDARD LVCMOS33 } [get_ports { ETH_MDIO }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio
#set_property -dict { PACKAGE_PIN B3    IOSTANDARD LVCMOS33 } [get_ports { ETH_RSTN }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn
#set_property -dict { PACKAGE_PIN D9    IOSTANDARD LVCMOS33 } [get_ports { ETH_CRSDV }]; #IO_L6N_T0_VREF_16 Sch=eth_crsdv
#set_property -dict { PACKAGE_PIN C10   IOSTANDARD LVCMOS33 } [get_ports { ETH_RXERR }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr
#set_property -dict { PACKAGE_PIN C11   IOSTANDARD LVCMOS33 } [get_ports { ETH_RXD[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0]
#set_property -dict { PACKAGE_PIN D10   IOSTANDARD LVCMOS33 } [get_ports { ETH_RXD[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1]
#set_property -dict { PACKAGE_PIN B9    IOSTANDARD LVCMOS33 } [get_ports { ETH_TXEN }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen
#set_property -dict { PACKAGE_PIN A10   IOSTANDARD LVCMOS33 } [get_ports { ETH_TXD[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0]
#set_property -dict { PACKAGE_PIN A8    IOSTANDARD LVCMOS33 } [get_ports { ETH_TXD[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1]
#set_property -dict { PACKAGE_PIN D5    IOSTANDARD LVCMOS33 } [get_ports { ETH_REFCLK }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk
#set_property -dict { PACKAGE_PIN B8    IOSTANDARD LVCMOS33 } [get_ports { ETH_INTN }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn

##Quad SPI Flash
#set_property -dict { PACKAGE_PIN K17   IOSTANDARD LVCMOS33 } [get_ports { QSPI_DQ[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0]
#set_property -dict { PACKAGE_PIN K18   IOSTANDARD LVCMOS33 } [get_ports { QSPI_DQ[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1]
#set_property -dict { PACKAGE_PIN L14   IOSTANDARD LVCMOS33 } [get_ports { QSPI_DQ[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2]
#set_property -dict { PACKAGE_PIN M14   IOSTANDARD LVCMOS33 } [get_ports { QSPI_DQ[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3]
#set_property -dict { PACKAGE_PIN L13   IOSTANDARD LVCMOS33 } [get_ports { QSPI_CSN }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn

Verify Directory

use command tree to verify your directory

tree
.
├── docs
├── scripts
└── src
    ├── constraints
    │   └── Nexys-4-DDR-Master.xdc
    ├── ip
    ├── rtl
    │   ├── rams_sp_wf.v
    │   └── top.sv
    └── tb
        ├── rams_sp_wf_tb.sv
        └── top_tb.sv

Simulate RTL model using cadence Xcelium (xrun)

create clean build dir and enter it for performing work

cd ~/CMPERSD/ASGMT4/P1 
rm -Rf build
mkdir -p build
cd build

Run simulation for build directory

/umbc/software/scripts/launch_cadence_xrun.sh -clean -access +r ../src/rtl/rams_sp_wf.v -sv ../src/tb/rams_sp_wf_tb.sv

The -clean option was provided above, though normally it is more efficient to omit it and let Xcelium smartly decide what to rebuild

if you should need to more forcibly clean away your cadence build/working/library directory, use the following command

/bin/rm -Rf xcelium.d/

GUI for exploring results

the testbench included commands for saving a waveform

├── waves.shm
│   ├── waves.dsn
│   └── waves.trn

run Cadence Simvision to view the waveforms:

cd ~/CMPERSD/ASGMT4/build
/umbc/software/scripts/launch_cadence_simvision.sh waves.shm

2026-08-09-08-36-EDT.png

I strongly encourage developing skills and habits for methodical testbench design with well-designed logging alongside designs of RTL modules, while the designs and concerns are fresh in the mind, but waveform visualization can be useful for exploring operation of complex, unfamiliar designs.

Now Simulate the TOP, representing the entire FPGA

cd ~/CMPERSD/ASGMT4/build
/umbc/software/scripts/launch_cadence_xrun.sh -clean -access +r ../src/rtl/rams_sp_wf.v -sv ../src/rtl/top.sv ../src/tb/top_tb.sv

verify that the results are as-expected

Vivado build

Use Vivado to build post-synthesis and post-implemenation models, and the final bitstream for programming

Start Vivado in interactive tcl mode

cd ~/CMPERSD/ASGMT4/P1/build
/umbc/software/scripts/launch_xilinx_vivado.sh -mode tcl

The following commands build the bitstream, and create the additional simulation models

The lines can be entered individually in the Vivado tcl console.

set topmodule top
set outputDir ../build
set sourceDir ../src
set xdcFilepath ../src/constraints/Nexys-4-DDR-Master.xdc
set part xc7a100tcsg324-1
set_part $part
read_verilog $sourceDir/rtl/rams_sp_wf.v $sourceDir/rtl/top.sv
read_xdc $xdcFilepath
synth_design -top $topmodule -part $part
write_sdf -mode timesim -force $outputDir/post_synth_sim.sdf
write_verilog -mode timesim -sdf_anno true -force $outputDir/post_synth_sim.v
opt_design
place_design
phys_opt_design
route_design
write_sdf -mode timesim -force $outputDir/post_route_sim.sdf
write_verilog -mode timesim -sdf_anno true -force $outputDir/post_route_sim.v
write_bitstream -force $outputDir/$topmodule.bit

Logs and Journals

  • vivado.log

    vivado creates a file vivado.log where you can review log messages from the console output for instance, there you can find a log from the synthesis mentioning the components inferred from the RTL design

    ---------------------------------------------------------------------------------
    Start RTL Component Statistics 
    ---------------------------------------------------------------------------------
    Detailed RTL Component Info : 
    +---Registers : 
    10 Bit    Registers := 1     
    +---RAMs : 
    640 Bit	(64 X 10 bit)          RAMs := 1     
    +---Muxes : 
    2 Input   10 Bit        Muxes := 1     
    ---------------------------------------------------------------------------------
    Finished RTL Component Statistics 
    ---------------------------------------------------------------------------------
    
  • vivado.jou

    Vivado save a history of the tcl commands from the most recent session

    you can copy/rename the file with a new name, like vivado.tcl, and repeat the commands again it can be executed using the tcl console source vivado.tcl or from the command line

    /umbc/software/scripts/launch_xilinx_vivado.sh -mode tcl -source vivado.tcl
    

Simulation with Post-Synthesis /Post-Implementation (Post-Route) Models

/umbc/software/courses/cmpersd/xilinx/fix_sdf.py post_synth_sim.sdf post_synth_sim.sdf
/umbc/software/scripts/launch_cadence_xrun.sh -clean   -access +rwc post_synth_sim.v ../src/tb/top_tb.sv -cdslib /umbc/software/courses/cmpersd/xilinx/cds.lib  -define RSD_POST_IMPLEMENTATION_SIM
/umbc/software/courses/cmpersd/xilinx/fix_sdf.py post_route_sim.sdf post_route_sim.sdf
/umbc/software/scripts/launch_cadence_xrun.sh -clean  -access +rwc post_route_sim.v ../src/tb/top_tb.sv -cdslib /umbc/software/courses/cmpersd/xilinx/cds.lib -define RSD_POST_IMPLEMENTATION_SIM

note the timing warnings

This testbench was instrumented with a delay to model a finite lag of primary input updates from the clock edge. Try the following to use that delay by specifying a custom symbol RSD_PRIMARY_INPUT_DELAY from the command line using -define:

/umbc/software/scripts/launch_cadence_xrun.sh -clean  -access +rwc post_route_sim.v ../src/tb/top_tb.sv -cdslib /umbc/software/courses/cmpersd/xilinx/cds.lib -define RSD_POST_IMPLEMENTATION_SIM -define RSD_PRIMARY_INPUT_DELAY=1

the warnings should be gone

Programming FPGA

Using ITE 375 lab

Plug USB cable from front USB port on the computer to the PROG-UART USB port on the FPGA board.

Run this command to see if it connection is processed

dmesg -T
[Tue Sep 29 15:52:57 2026] usb 1-1: new high-speed USB device number 4 using xhci_hcd
[Tue Sep 29 15:52:57 2026] usb 1-1: New USB device found, idVendor=0403, idProduct=6010, bcdDevice= 7.00
[Tue Sep 29 15:52:57 2026] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[Tue Sep 29 15:52:57 2026] usb 1-1: Product: Digilent USB Device
[Tue Sep 29 15:52:57 2026] usb 1-1: Manufacturer: Digilent
[Tue Sep 29 15:52:57 2026] usb 1-1: SerialNumber: 210292C0AE64
[Tue Sep 29 15:52:57 2026] usbcore: registered new interface driver ftdi_sio
[Tue Sep 29 15:52:57 2026] usbserial: USB Serial support registered for FTDI USB Serial Device
[Tue Sep 29 15:52:57 2026] ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected
[Tue Sep 29 15:52:57 2026] usb 1-1: Detected FT2232H
[Tue Sep 29 15:52:57 2026] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0
[Tue Sep 29 15:52:57 2026] ftdi_sio 1-1:1.1: FTDI USB Serial Device converter detected
[Tue Sep 29 15:52:57 2026] usb 1-1: Detected FT2232H
[Tue Sep 29 15:52:57 2026] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB1
cd $HOME/CMPERSD/ASGMT4/build
/umbc/software/scripts/xilinx_prog_fpga.sh top.bit

At home

  • Windows
    • If you are using Windows,
      • download Vivado Lab Edition (Vivado Lab Solutions) from https://www.amd.com/en/support/downloads/adaptive-socs-and-fpgas/development-tools/2026-1.html
      • For the Windows version, look under Vivadoâ„¢ Lab Solutions – 2026.1 – Jun 23, 2026 for Vivado 2026.1: Lab Edition - Windows
      • Install the downloaded tool
      • You can transfer the file top.bit from the build directory to your computer using your preferred means, and then use the GUI provided by this tool to program your FGPA. The TA is available to assist you with this.
  • Linux (Ubuntu 2026)
    • The instructions that follow are for Linux, but can be adapted for Windows
    • You can download the full Version of Vivado and use it, but herein is an explanation of how to use the lighter Lab Version
    • download Vivado Lab Edition (Vivado Lab Solutions) from https://www.amd.com/en/support/downloads/adaptive-socs-and-fpgas/development-tools/2026-1.html
    • I downloaded the Update 1 version: Vivado_Lab_2026.1.1_0904_0832.tar
    • extract the archive
    • run xsetup, and when prompted use as the install path /opt/Xilinx , which will create /opt/Xilinx/2026.1.1/, /opt/Xilinx/2026.1.1/Vivado_Lab, etc.
    • Ubuntu 2026 hack fix:
      • The Vivado tool expects some legacy libraries, like /usr/lib/x86_64-linux-gnu/libtinfo.so.5, which are not provided
      • A hack that happens to work today, but shouldn't always be expected, is to use the .6 versions by providing aliases as .5 versions
      • Create a directory for the links

        mkdir ~/vivado_lib_hack
        

        Create the aliases

        ln -s /usr/lib/x86_64-linux-gnu/libncurses.so.6 $HOME/vivado_lib_hack/libncurses.so.5
        ln -s /usr/lib/x86_64-linux-gnu/libncursesw.so.6  $HOME/vivado_lib_hack/libncursesw.so.5
        ln -s /usr/lib/x86_64-linux-gnu/libtinfo.so.6  $HOME/vivado_lib_hack/libtinfo.so.5
        

        This directory will be used by the shell script later

    • Create a tcl script and shell script for programming I create a tools directory $HOME/tools

      mkdir $HOME/tools
      
    • Create ➕📄 xilinx_prog_fpga.tcl , IN 📂 $HOME/tools/

      #typical use: /umbc/software/scripts/launch_xilinx_vivado.sh -mode tcl -source script.tcl
      
      if {[info exists env(BITSTREAM_FP)]} {
          # okay, it's there, use it
          set bitstream_fp $env(BITSTREAM_FP)
      } else {
          # the environment var isn't set, use a default
          puts "environment variable BITSTREAM_FP must be set"
          exit
      }
      
      
      # Connect to the Digilent Cable on localhost:3121
      
      open_hw_manager
      
      connect_hw_server -url localhost:3121
      
      #current_hw_target [get_hw_targets */xilinx_tcf/Digilent/12345]
      current_hw_target [get_hw_targets *]
      #localhost:3121/xilinx_tcf/Digilent/210292B9D085A
      
      open_hw_target
      
      # Program and Refresh the XC7K325T Device
      
      current_hw_device [lindex [get_hw_devices] 0]
      
      refresh_hw_device -update_hw_probes false [lindex [get_hw_devices] 0]
      
      set_property PROGRAM.FILE $bitstream_fp [lindex [get_hw_devices] 0]
      
      #set_property PROBES.FILE {C:/design.ltx} [lindex [get_hw_devices] 0]
      
      program_hw_devices [lindex [get_hw_devices] 0]
      
      refresh_hw_device [lindex [get_hw_devices] 0]
      
      exit
      
    • Create ➕📄 xilinx_prog_fpga.sh , IN 📂 $HOME/tools/

      #!/bin/bash
      export BITSTREAM_FP=$1
      
      SCRIPT_DIR=$( cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd )
      
      source /opt/Xilinx/2026.1.1/Vivado_Lab/settings64.sh
      export LD_LIBRARY_PATH="~/vivado_lib_hack/:$LD_LIBRARY_PATH"
      /opt/Xilinx/2026.1.1/Vivado_Lab/bin/vivado_lab -mode tcl -source "${SCRIPT_DIR}/xilinx_prog_fpga.tcl"
      
    • The following command can be used to program the FPGA with a bit file:

      $HOME/tools/xilinx_prog_fpga.sh top.bit
      

What to submit 🎯 for P1

  • your report must have a statement that the tutorial is completed
  • a listing of the final simulation output must be included in the report
  • you should demonstrate the FPGA operation to the TA by sharing a video

P2 Sort 2 RTL

make another set of directories

mkdir -p $HOME/CMPERSD/ASGMT4/P2/src/rtl
mkdir -p $HOME/CMPERSD/ASGMT4/P2/src/tb
mkdir -p $HOME/CMPERSD/ASGMT4/P2/src/docs

You should repeat this practice for the other problems.

create a combinational sorting module, using always_comb procedural code

module sort2 (input logic [31:0] iA, input logic [31:0] iB, output logic [31:0] oMax, output logic [31:0] oMin);

example design: sort.svg

make a build directory, then start vivado from that directory

mkdir -p $HOME/CMPERSD/ASGMT4/P2/build
cd  $HOME/CMPERSD/ASGMT4/P2/build
/umbc/software/scripts/launch_xilinx_vivado.sh -mode tcl

enter these commands in the Vivado tcl console

commands to run in vivado
set topmodule sort2
set sourceDir ../src
set part xc7a100tcsg324-1
set_part $part
read_verilog $sourceDir/rtl/sort2.sv
synth_design -top $topmodule -part $part -mode out_of_context

familiarize yourself with the logs/output

now, genrerate report files by issuing these commands in the Vivado tcl console

file mkdir reports
report_utilization -file reports/post_synth_utilization.rpt
exec cat reports/post_synth_utilization.rpt
report_timing -file reports/post_synth_timing.rpt
exec cat  reports/post_synth_timing.rpt
report_ram_utilization -file reports/post_synth_ram.rpt
exec cat  reports/post_synth_ram.rpt

What to submit 🎯 within the submission document (PDF report)

  • a listing of the source code (sort2.sv for P2)
  • a listing of the testbench (sort2_tb.sv for P2)
  • a listing of the pre-synthesis simulation log/output from Xcelium (generated from the testbench+rtl code)
  • In your submission documents, include the full listing of the three reports for each problem P2,P3,P4,….
  • in each problem discuss the following, especially differences that contrast the various implementations from a previous problem
    • from the synth_design output (full listing not submitted), specifically note/discuss the RTL Component Statistics Example listing:

      ---------------------------------------------------------------------------------
      Start RTL Component Statistics 
      ---------------------------------------------------------------------------------
      Detailed RTL Component Info : 
      +---Registers : 
      32 Bit    Registers := 128   
      +---Muxes : 
      2 Input   32 Bit        Muxes := 160   
      ---------------------------------------------------------------------------------
      Finished RTL Component Statistics 
      ---------------------------------------------------------------------------------
      
    • from the utilization report, specifically discuss 1. Slice Logic, 2. Memory, 3. DSP, 7. Primitives (note that CARRY4 Primitives indicate adder-like structures being implemented)
    • from the timing report, specifically discuss the path delay (last cumulative row in column Path(ns))
    • from the RAM utilization report, specially discuss any RAM utilization

P3 RTL extended to 16 words

Create a module that sorts 16 words, using RTL code. demonstrate its operation with a testbench

module sort16rtl (input logic [31:0] v_in [16], output logic [31:0] v_sorted [16]);

files: sort16rtl.sv, sort16rtl_tb.sv

(I'll save you the time and provided an AI-generated version here)

`timescale 1ns/1ps
module sort16rtl (
                  input logic [31:0]  v_in [16],
                  output logic [31:0] v_sorted [16]
                  );

   always_comb begin
      // Copy inputs to output array
      v_sorted = v_in;

      // Combinational sorting logic (selection/bubble sort)
      for (int i = 0; i < 16; i++) begin
         for (int j = i + 1; j < 16; j++) begin
            if (v_sorted[i] > v_sorted[j]) begin
               logic [31:0] temp;
               temp        = v_sorted[i];
               v_sorted[i] = v_sorted[j];
               v_sorted[j] = temp;
            end
         end
      end
   end

endmodule

Again, use Vivado to synthesize the design and generate reports

Start Vivado in interactive tcl mode

mkdir -p $HOME/ASGMT4/P3/build
cd $HOME/CMPERSD/ASGMT4/P3/build
/umbc/software/scripts/launch_xilinx_vivado.sh -mode tcl
commands to run in vivado
set topmodule sort16rtl
set sourceDir ../src
set part xc7a100tcsg324-1
set_part $part
read_verilog $sourceDir/rtl/sort16rtl.sv
synth_design -top $topmodule -part $part -mode out_of_context

familiarize yourself with the logs/output

now, generate report files by issuing these commands in the Vivado tcl console

file mkdir reports
report_utilization -file reports/post_synth_utilization.rpt
exec cat reports/post_synth_utilization.rpt
report_timing -file reports/post_synth_timing.rpt
exec cat  reports/post_synth_timing.rpt
report_ram_utilization -file reports/post_synth_utilization.rpt
exec cat  reports/post_synth_utilization.rpt

What to submit 🎯 within the submission document

see P2

P4 Structural expansion to 16 words

  • This time, use many instances of the sort2 module to create a combinational logic module that sorts 16 words
module sort16struct (input logic [31:0] v_in [16], output logic [31:0] v_sorted [16]);

demonstrate its operation with a testbench.

You can use the previous version as a model, but this version should have no new procedural code, only instances of sort2. for…generate constructs are allowed

new source files: sort16struct.sv, sort16struct_tb.sv

Use Vivado for synthesis and generate reports as before

This time, youll need to have two source files read. You can copy sort2.sv from the a problem

read_verilog $sourceDir/rtl/sort16struct.sv
read_verilog $sourceDir/rtl/sort2.sv

What to submit 🎯 within the submission document

see P2

P5 RTL Pipeline

Create a module that sorts 16 words, but this time modify the RTL procedural code version sort16trl and pipeline registers after EVERY TWO layers of sorting (no more than a two sort2 modules in a combinational chain, potentially creating an 8-stage pipeline if the previously provided code is used as a start)

module sort16rtlp (input logic [31:0] v_in [16], output logic [31:0] v_sorted [16], input clk);

new source files: sort16rtlp_.sv, sort16rtlp_tb.sv

Use Vivado for synthesis and generate reports as before

What to submit 🎯 within the submission document

see P2

P6 Manual Structural Pipelining

In the next assignment (ASGMT 5), automated pipelining using registers planted for retiming will be explored. For now, the work will be done manually.

Recreate another variant of the sort16sturct model module that sorts 16 words using instances of but this time insert pipeline registers after EVERY TWO layers of sorting (8 stage pipeline)

module sort16structp (input logic [31:0] v_in [16], output logic [31:0] v_sorted [16], input clk);

new source files sort16structp.sv, sort16structp_tb.sv

Use Vivado for synthesis and generate reports as before

What to submit 🎯 within the submission document

see P2

P7 FSM+Datapath, use of Xilinx Memory Blocks

This time, use a memory block for the design, along with a state machine.

Create a read-first single port ram of size 16 using the example from AMD/Xilinx (also in my Datapath notes): rams_sp_rf

Create a module that accepts 16 words sequentially from a 32-bit input port, and then outputs the 16 words in-order.

  • The module should use the memory module as storage and use as few registers as possible for working memory.
    • (Imagine that I asked you to perform an operation on a MUCH, MUCH LARGER SET)
  • a case-statement-based state machine should be implemented in the module for control to load values into the memory, perform the sorting, and output the results

Create a testbench and simulate the RTL design (pre-synthesis) for verification synthesize the design in Vivado and generate reports

What to submit 🎯 within the submission document

see P2

Submission Requirements

You must maintain a working copy of your work directories until the homework is graded, but it does not need to be submitted unless asked for during grading

  • You should email the TA one PDF report file with your account name in the filename
  • You should share one video with the TA for P1

Author: Dr. Ryan Robucci

Created: 2026-09-30 Wed 17:55

Validate