Assignment 6
Due Oct 29th
P1 Evaluate CORDIC implementations using Out of Context Synthesis
The first few pages of Chapter 15 discuss a CORDIC operation, which supports for instance computing sine. The input is an angle (360 degrees remapped to the input binary word integer range) and the outputs are normalized to the output word range. You don't need to know the theory behind it – the reference C code is the only specification you need right now.
C code based on Course Textbook Listing 15.1
#define AG_CONST 163008218
static const int angles[] = {
210828714, 124459457, 65760959, 33381289,
16755421, 8385878, 4193962, 2097109,
1048570, 524287, 262143, 131071,
65535, 32767, 16383, 8191,
4095, 2047, 1024, 511 };
void cordic(int target, int *rX, int*rY) {
int X, Y, T, current;
unsigned step;
X = AG_CONST;
Y = 0;
current = 0;
for (step=0; step<20 ; step++){
if (target > current) {
T = X - (Y>>step);
Y = (X >> step) + Y;
X = T;
current += angles[step];
} else {
T = X + (Y >> step);
Y = -(X >> step) + Y;
X = T;
current -= angles[step];
}
printf("target:%x,current:%x,X:%x,Y:%x\n",target,current,X,Y); //this line added
}
*rX = X;
*rY = Y;
}
int main(){
int x = 0,y=1;
int test_targets[4];
int target;
test_targets[0] = 210828714; // small positive
test_targets[1] = -124459457; // small negative
test_targets[2] = 65760959; // smaller positive
test_targets[3] = 33381289; // even smaller
//cordic(int target, int *rX, int*rY)
target = test_targets[0];
cordic(target, &x, &y);
printf("%x->%x,%x\n",target,x,y);
}
Reference Implementation and Testbench
Below is a fixed version of CORDIC from an a generative AI (2025 ChatGPT I think), based on that C code. Some AIs still haven't mastered use of blocking and non-blocking and need fixes like this and more
X /*T*/ <= X - (Y >>> step);
Y <= (X >>> step) + Y;
/*X <= T;*/
It could use more work, but here is the implementation and a testbench
//`timescale 1ns/1ps
// =============================================================
// Synthesizable Verilog RTL for 20-step CORDIC rotation
// Derived from given C reference
// =============================================================
module cordic (
input wire clk,
input wire rst_n,
input wire start,
input wire signed [32-1:0] target,
output reg signed [32-1:0] rX,
output reg signed [32-1:0] rY,
output reg done
);
localparam WIDTH = 32
// ---------------------------------------------------------
// Constants
// ---------------------------------------------------------
localparam signed [WIDTH-1:0] AG_CONST = 32'd163008218;
// Angles table (20 entries)
localparam signed [WIDTH-1:0] angles [0:19] = '{
32'd210828714, 32'd124459457, 32'd65760959, 32'd33381289,
32'd16755421, 32'd8385878, 32'd4193962, 32'd2097109,
32'd1048570, 32'd524287, 32'd262143, 32'd131071,
32'd65535, 32'd32767, 32'd16383, 32'd8191,
32'd4095, 32'd2047, 32'd1024, 32'd511
};
// ---------------------------------------------------------
// Internal registers
// ---------------------------------------------------------
reg signed [WIDTH-1:0] X, Y, T, current;
reg [4:0] step;
reg running;
// ---------------------------------------------------------
// Sequential CORDIC process
// ---------------------------------------------------------
always @(posedge clk) begin
if (!rst_n) begin
X <= 0;
Y <= 0;
T <= 0;
current <= 0;
step <= 0;
running <= 0;
done <= 0;
rX <= 0;
rY <= 0;
end else begin
done <= 0;
if (start && !running) begin
// Initialize CORDIC iteration
running <= 1;
step <= 0;
X <= AG_CONST;
Y <= 0;
current <= 0;
end else if (running) begin
// Perform one iteration per clock
if (target > current) begin
X /*T*/ <= X - (Y >>> step);
Y <= (X >>> step) + Y;
/*X <= T;*/
current <= current + angles[step];
end else begin
X /*T*/ <= X + (Y >>> step);
Y <= Y - (X >>> step);
/*X <= T;*/
current <= current - angles[step];
end
// Advance step
if (step == 5'd19) begin
// Finish
running <= 0;
done <= 1;
rX <= X;
rY <= Y;
end else begin
step <= step + 1;
end
end
end
end
endmodule // cordic
Here is a testbench that I also patched from CHATGPT
module cordic_tb;
`ifdef PERIOD
localparam half_period=(`PERIOD+1)/2;
`else
localparam half_period=50000;
`endif
// ---------------------------------------------------------
// Parameters and DUT I/O
// ---------------------------------------------------------
localparam WIDTH = 32;
reg clk;
reg rst_n;
reg start;
reg signed [WIDTH-1:0] target;
wire signed [WIDTH-1:0] rX;
wire signed [WIDTH-1:0] rY;
wire done;
// ---------------------------------------------------------
// Instantiate DUT
// ---------------------------------------------------------
//cordic #(.WIDTH(WIDTH)) dut (
cordic dut (
.clk(clk),
.rst_n(rst_n),
.start(start),
.target(target),
.rX(rX),
.rY(rY),
.done(done)
);
// ---------------------------------------------------------
// Clock generation
// ---------------------------------------------------------
initial clk = 0;
always #half_period clk = ~clk; // 100 MHz clock (10 ns period)
// ---------------------------------------------------------
// Test sequence
// ---------------------------------------------------------
integer i;
reg signed [WIDTH-1:0] test_targets [0:3];
initial begin
$dumpfile("waveform.vcd"); // Specifies the VCD file name
$dumpvars(0, dut);
// Preload test target angles (in same units as C code)
test_targets[0] = 32'd210828714; // small positive
test_targets[1] = -32'd124459457; // small negative
test_targets[2] = 32'd65760959; // smaller positive
test_targets[3] = 32'd33381289; // even smaller
// Initialize signals
rst_n <= 0;
start <= 0;
target <= 0;
// Apply reset
rst_n <= 1;
@(posedge clk);
@(posedge clk);
rst_n <= 0;
@(posedge clk);
@(posedge clk);
rst_n <= 1;
@(posedge clk);
@(posedge clk);
// -----------------------------------------------------
// Run through test cases
// -----------------------------------------------------
for (i = 0; i < 1; i = i + 1) begin
target = test_targets[i];
@(posedge clk);
start <= 1;
@(posedge clk);
start <= 0;
// Wait for done
//wait(done);
while(!done) begin
@(posedge clk);
$strobe("%010t, done = %b, X=%x,Y=%x,rX=%x,rY=%x", $time,done,dut.X,dut.Y,rX,rY);
end
$strobe("TEST %0d: target = %0d => rX = %0d, rY = %0d",
i, target, rX, rY);
$strobe("TEST %0d: target = %0x => rX = %0x, rY = %0x",
i, target, rX, rY);
end
@(posedge clk);
$display("All tests complete.");
$finish;
end
endmodule // tb_cordic
Your assignment is to create new implementations and report timing slack and utilization and demonstrate operation
Using Google Gemini Notebook create the following:
cordic_registered_output.sv: a combinational registered-output version the computes the results entirely in one clock cycle and only has registers for the final outputscordic_pipelined.sv: a piplelined version, the unlike the reference version can accept new inputs as the previous results are being calculated
For each of these two versions and the previous (three versions)
- perform Static Timing Analysis using a 100MHz design constraint
- Based on the worst slack reported, estimate the maximum clock frequency for operation.
For all three versions
- Generate a utilization report and summarize key the trade offs of each implementation for function, performance, and cost
Starter Scripts
Here is a generic template constraints file to support Out-of-Context Synthesis:
################################################################################
# Out-of-Context (OOC) Constraints File Generic
# Primary Clock Port: clk
################################################################################
# 1. Primary Clock Definition (100 MHz target -> 10.0 ns period, 50% duty cycle)
create_clock -name clk -period 10.000 -waveform {0.000 5.000} [get_ports clk]
# Assign a default global clock buffer site to enable clock insertion delay estimation
set_property HD.CLK_SRC BUFGCTRL_X0Y0 [get_ports clk]
# 2. Input / Output Delays for Standalone Boundary Timing Analysis
set_input_delay -clock clk 2.000 [get_ports -filter {DIRECTION == "IN" && NAME != "clk"} *]
set_output_delay -clock clk 2.000 [all_outputs]
The following is a starter script designed to be run from $PROJECT/build with source files appropriately in $PROJECT/src/tcl, $PROJECT/src/contraints, $PROJECT/src/scripts using the following command:
/umbc/software/scripts/launch_xilinx_vivado.sh -mode tcl -source ../src/scripts/cordic_registered_ooc_timing.tcl
# ==============================================================================
# Vivado Tcl Script for Out-of-Context (OOC) Synthesis & Timing Analysis
# Module: cordic (cordic.sv)
# Target Device: Nexys A7-100T (Artix-7 xc7a100tcsg324-1)
# ==============================================================================
# 1. Setup Target Part and Output Directory
set TOP_MODULE "cordic_piplelined"
set PART_NAME "xc7a100tcsg324-1"
set OUTPUT_DIR "../build/cordic_pipelined_ooc"
set sourceDir "../src"
set XDC_FILE_PATH "../src/constraints/generic_ooc.xdc"
set_part $PART_NAME
file mkdir $OUTPUT_DIR
puts "------------------------------------------------------------------------"
puts "Starting Out-of-Context Synthesis for module: $TOP_MODULE"
puts "Target Part: $PART_NAME"
puts "------------------------------------------------------------------------"
# 2. Read SystemVerilog RTL Source
read_verilog -sv $sourceDir/rtl/cordic_pipelined.sv
# 3. Read Out-of-Context Constraint File
read_xdc -mode out_of_context $XDC_FILE_PATH
# 4. Run Out-of-Context Synthesis
synth_design -top $TOP_MODULE -part $PART_NAME -mode out_of_context
# 5. Save Synthesized Design Checkpoint (DCP)
write_checkpoint -force $OUTPUT_DIR/${TOP_MODULE}_ooc.dcp
# 6. Generate Timing Analysis and Utilization Reports
report_timing_summary -delay_type min_max \
-report_unconstrained \
-check_timing_verbose \
-max_paths 10 \
-input_pins \
-file $OUTPUT_DIR/${TOP_MODULE}_timing_summary.rpt
report_utilization -file $OUTPUT_DIR/${TOP_MODULE}_utilization.rpt
puts "------------------------------------------------------------------------"
puts "OOC Synthesis Completed Successfully!"
puts "Reports generated in: $OUTPUT_DIR"
puts "------------------------------------------------------------------------"
P2 Physical Implementation of CORDIC reference version
(A) Skeleton Provided (get this working first)
This code includes python code to send and receive serial data, and a design that displays bytes transferred on LEDs and incomming words on the 7-segment array.
The next change that I might make is to use board switches as control to choose what is displayed on the seven segment LEDs, right now only the incomming 32-bit word is displayed.
Some of this was generated with the help of Gemini Notebook
- uart.sv -> src/rtl/ (a special uart version that uses one clock domain)
- top.sv -> src/rtl/
- uart_to_led_probe.sv -> src/rtl
- seven_seg_driver.sv -> src/rtl
- top.xdc -> src/contraints/ (based on https://raw.githubusercontent.com/Digilent/digilent-xdc/refs/heads/master/Nexys-A7-100T-Master.xdc)
- top.tcl -> src/scripts (to generate bitstream file, from ./build run
/umbc/software/scripts/launch_xilinx_vivado.sh -mode tcl -source ../src/scripts/top.tcl) - fpga_uart_comm.py -> src/software Python Test Code
Submission requirement: Hand-draw FSM diagram that documents the controller FSM implemented in this reference design and include it in your assignment submission.
(B) Integrate the reference CORDIC provided and demonstrate operation
- Integrate the provided CORDIC implementation into the skeleton.
- Document changes as hand-drawing for the controller FSM and implement those changes in the RTL.
- Modify the Python Test Code (it would be very useful to have this perform results verification, not just operation)
- Demonstrate Operation (share video with TA or live demonstration)
- Submit all source files and brief report
P3 (Based on Tuesday Oct 27th Lecture)
For this problem the UMBC Red Light policy for AI must be adhered to: (https://my3.my.umbc.edu/groups/provost/posts/155412/2/57c54c0c9cd5cd90136fccec0cc38d27/web/link?link=https://my3.my.umbc.edu/groups/provost/files/14081)
AI Use Not Permitted
All work must be entirely your own. The use of generative AI tools is not allowed
at any stage of the assignment, including brainstorming, experiments, coding,
research, writing, or revision. If you have any questions, feel free to reach out to
me. The use of AI tools will be treated as an academic integrity issue.
All work is expected to be handwritten with steps shown and performed with use only of basic calculator functions as would be practiced for an exam:
- Redo Example 3.4 pg 125 From the High-Speed Digital Design (1 pt) I posted a book section for class:
High-Speed-Digital-Design_Section3pt11.pdf( https://drive.google.com/a/umbc.edu/file/d/0B5MWE1meYfDbc0RHQmh4LUVnMVlSSmFqRlZnVFg3NXd1bG9j/view?usp=sharing ) - Work through the example up to calculating the MTBF for 35 MHz and 30MHz – submit your work and answers.
- Additionally, derive and report what would be the result of increasing the delay of the inverters by 1 ps in each case. Discuss the relationship of the 4 results.