[TOC] # 1. Parallel to Serial ## Top Function (Kernel) ### In HLS ``` cpp= void parallel2serial ( ap_uint<N> a, bool &d, bool &serial_start, bool &serial_end, bool begin ) { #pragma HLS INTERFACE ap_none port=a #pragma HLS INTERFACE ap_none port=d #pragma HLS INTERFACE ap_none port=serial_start #pragma HLS INTERFACE ap_none port=serial_end #pragma HLS INTERFACE ap_none port=begin #pragma HLS INTERFACE ap_ctrl_none port=return static int count = N; //32-bit register if (begin == 1) { count = 0; } if (count == 0) { serial_start = 1; serial_end = 0; } else if (count == N-1) { serial_start = 0; serial_end = 1; d = a[count]; count = N; } else if (count < N-1) { serial_start = 0; serial_end = 0; d = a[count++]; } else { serial_start = 0; serial_end = 0; count = N; } } ``` #### Code Explanation - `a` is the N-bit parallel input signal - `d` is the serial output signal - When `begin` rise, `serial_start` pulse. - The 32-bit register `count` start counting. - Wait until the MSB of `a` is transferred to serial, `serial_end` rise. - When the system start to transfer parallel signal to serial, `begin` should be 0. #### Output ![](https://hackmd.io/_uploads/Syxu0bes3.png) #### Utilization in HLS ![](https://hackmd.io/_uploads/B1mRtkei3.png) - 33 FF's. 32 for 32-bit register `count`, and 1 is added by HLS. #### Waveform in HLS ![](https://hackmd.io/_uploads/HkDhdJgo3.png) - The HLS code executes in every clock cycle. - At the first clock cycle, `begin` pulse, `start` pulse, the LSB of `a` transferred to `d`. - At the 8th clock cycle, transfer has finished, `serial_end` pulse. ### In Verilog ``` verilog= `define PARALLEL_N 32'd8 module parallel2serial ( input clk, input rst, input begin_r, input [7:0] a, output reg d, output reg serial_start, output reg serial_end ); reg [31:0] count; // 32-bit register reg [31:0] next_count; always @* begin if (begin_r ==1'b1) begin count = 32'd0; end if (count == 32'd0) begin serial_start = 1'b1; serial_end = 1'b0; next_count = count + 1'b1; d = a[count]; end else if (count == `PARALLEL_N - 1'b1) begin serial_start = 1'b0; serial_end = 1'b1; next_count = `PARALLEL_N; d = a[count]; end else if (count < `PARALLEL_N - 1'b1) begin serial_start = 1'b0; serial_end = 1'b0; next_count = count + 1'b1; d = a[count]; end else begin serial_start = 1'b0; serial_end = 1'b0; next_count = `PARALLEL_N; d = 'bx; end end always @(posedge clk) begin if (rst) count <= `PARALLEL_N; else count <= next_count; end endmodule ``` ## Testbench - Testbench in Verilog ``` verilog= `define PARALLEL_N 32'd8 module VIC_TESTBENCH(); reg clk; // period: 10ns reg rst; // active high, synchronous reg begin_r; // the begin signal reg [7:0] in_parallel; // parallel input wire d_hw; // output each clk cycle wire serial_start; // the start signal wire serial_end; // the end signal reg [7:0] serial_out; // serial output integer i; // include the design under test design_1_wrapper DUT0 (.a(in_parallel), .ap_clk(clk), .ap_rst(rst), .begin_r(begin_r), .d(d_hw), .serial_start(serial_start), .serial_end(serial_end)); /* parallel2serial DUT1 (.a(in_parallel) .clk(clk), .rst(rst), .begin_r(begin_r), .d(d_hw), .serial_start(serial_start), .serial_end(serial_end)); */ // 10ns clock generator initial begin clk = 1; forever begin #5 clk = ~clk; end end // main function of testbench initial begin in_parallel = 8'b11010011; serial_out = 8'b00000000; // initial value // reset active high rst = 1'b1; begin_r = 1'b0; // reset fall, begin to transfer parallel signal to serial. #10 rst = 1'b0; #0 @(posedge clk) begin_r <= 1'b1; // for loop for (i = 0; i < `PARALLEL_N; i = i + 1) begin @(posedge clk) begin begin_r <= 1'b0; serial_out[i] <= d_hw; $display("d = %b, serial_start = %b, serial_end = %b", d_hw, serial_start, serial_end); end end // Compare the result #1 if (in_parallel != serial_out) begin $display("Error, in_parallel = %b, output = %b". in_parallel, serial_out); end else begin $display("Test Passed!"); end end endmodule ``` ### DUT (IP) - Export RTL IP and create block design. ![](https://hackmd.io/_uploads/BJtDkMli2.png) - Then, use verilog to write a testbench. #### Output ![](https://hackmd.io/_uploads/r1qooWgs2.png) #### Utilization ![](https://hackmd.io/_uploads/HJdm6Wgjn.png) - 32 FF's for 32-bit register #### Waveform ![](https://hackmd.io/_uploads/HyD-oZxs2.png) - Same as the waveform of HLS ### DUT (Verilog) #### Utilization ![](https://hackmd.io/_uploads/r1Zfyqwjn.png) - 32 FF's for registers. #### Waveform ![](https://hackmd.io/_uploads/SJsXJ5Po3.png) - Same as the waveform of DUT(IP). -------------------------------------------------- # 2. Serial to Parallel ## Top Function (Kernel) ### In HLS ``` cpp= void serial2parallel(bool serial_start, bool &end_conversion, bool d, ap_uint<N> &a) { #pragma HLS INTERFACE ap_none port=serial_start #pragma HLS INTERFACE ap_none port=end_conversion #pragma HLS INTERFACE ap_none port=d #pragma HLS INTERFACE ap_none port=a #pragma HLS INTERFACE ap_ctrl_none port=return static ap_uint<N> state_reg = 0; static ap_uint<N> a_reg_out = 0; static unsigned int counter = N; unsigned int next_counter; ap_uint<N> next_state = state_reg; next_counter = counter; if (serial_start == 1) { next_counter = 0; } if (next_counter < N-1) { next_state = (next_state >> 1) | (d, (ap_uint<N-1>)0);; next_counter++; end_conversion = 0; } else if (next_counter == N-1) { next_state = (next_state >> 1) | (d, (ap_uint<N-1>)0);; next_counter++; a_reg_out = next_state; end_conversion = 1; } else { end_conversion = 0; } counter = next_counter; state_reg = next_state; a = a_reg_out; } ``` #### Code Explanation - `d` is the serial input, `a` is the N-bit parallel output. - `serial_start` rise, start transfering serial input to parallel. - `end_conversion` will rise after finished the transfer. #### Output ![](https://hackmd.io/_uploads/S19i4nlj2.png) #### Utilization in HLS ![](https://hackmd.io/_uploads/HkbnEnxsn.png) - 49 FF's. 32 for 32-bit register `counter`, 8 for`state_reg`, another 8 for `a_reg_out`, and 1 is adding by HLS. #### Waveform in HLS ![](https://hackmd.io/_uploads/Bk_3V3lsh.png) - As `serial_start` pulse, start passing value. - The parallel output `a[7:0]` shows up at the same time when `end_conversion` pulse. ### In Verilog ``` verilog= `define N 32'd8 module serial2parallel( input clk, input rst, input serial_start, input d, output reg end_conversion, output reg [7:0] a ); reg [7:0] a_reg; reg [3:0] counter; reg [3:0] next_counter; always @* begin if (serial_start == 1'b1) begin a_reg = {d, a_reg[7:1]}; next_counter = 4'd1; end_conversion = 1'b0; a = 8'd0; end else if (next_counter == `N - 1'b1) begin a_reg = {d, a_reg[7:1]}; next_counter = counter + 1'b1; end_conversion = 1'b0; a = 8'd0; end else if (next_counter == `N - 1'b1) begin a_reg = {d, a_reg[7:1]}; next_counter = counter + 1'b1; end_conversion = 1'b1; a = a_reg; end else begin a_reg = 8'd0; next_counter = `N; end_conversion = 1'b0; a = 8'd0; end end always @(posedge clk) begin if (rst) begin counter <= 4'd8; end else begin counter <= next_counter; end end endmodule ``` ## Testbench - Testbench in Verilog ``` verilog= `define WIDTH 32'd8 module VIC_TESTBENCH(); reg clk; // 10ns clk reg rst; // active high, synchronous reg [0:0] d; // serial input reg serial_start; // the start signal wire [`WIDTH-1:0] a; // parallel output wire end_conversion; // the end signal reg [`WIDTH-1:0] data; // the data which will transferred from serial to parallel integer i; // include the design under test design_1_wrapper DUT (.ap_clk(clk), .ap_rst(rst), .d(d), .serial_start(serial_start), .a(a), .end_conversion(end_conversion)); // 10ns clk generator initial begin clk = 1; forever begin #5 clk = ~clk; end end // main function of testbench initial begin // initial value d = 1'b0; data = 8'b01001101; // at the begining, rst stay high rst = 1'b1; serial_start = 1'b0; // after 10ns, rst fall, serial_start rise at the next clk cycle #10 rst = 0; #0 @(posedge clk) begin serial_start <= 1'b1; d <= data[0]; $display("%b", data[0]); // if we displayed 'd' here, it will // display the value of the last clk cycle. end // for-loop for (i = 1; i < `WIDTH; i = i + 1) begin @(posedge clk) begin serial_start <= 1'b0; d <= data[i]; $display("%b", data[i]); end end // Compare the value after a short delay #1 if (data != a) begin $display("Error, parallel output = %b, expected output = %b", a, data); end else begin $display("%b", a); $display("Test Passed!"); end end endmodule ``` ### DUT (IP) - Export RTL IP and create block design. ![](https://hackmd.io/_uploads/SkPGir-ih.png) - Then, use verilog to write a testbench. #### Output - LSB -> MSB ![](https://hackmd.io/_uploads/rympQGzi3.png) #### Utilization ![](https://hackmd.io/_uploads/rJL4jrbjh.png) - 47 FF's. 32 for 32-bit register `count`, 15 for other variables. #### Waveform ![](https://hackmd.io/_uploads/BkyroSZih.png) - Same as the waveform of HLS ### DUT (Verilog) #### Output ![](https://hackmd.io/_uploads/By9g5RCs2.png) #### Utilization ![](https://hackmd.io/_uploads/ByXB9RCon.png) - Since I only let `counter`, `next_counter` store values in FFs, there are only 4 registers for 4-bit `counter`. - #### Waveform ![](https://hackmd.io/_uploads/BkGIqR0ih.png) ----------------------------------------------------- # 3. Combination Lock ## Top Function (Kernel) ### In HLS - First, use `typedef` create 5 states ``` cpp= typedef enum {s0, s2, s23, s234, s2346} state_type; ``` - Then, create a function which generate the 8-bit code of 7-segment display. ``` cpp=15 ap_uint<8> get_seven_segment_code(state_type number) { #pragma HLS INLINE ap_uint<8> code = seven_segment_code[0]; switch(number) { case s0: code = seven_segment_code[0]; break; case s2: code = seven_segment_code[1]; break; case s23: code = seven_segment_code[2]; break; case s234: code = seven_segment_code[3]; break; case s2346: code = seven_segment_code[4]; break; default: break; } return code; } ``` - Where seven_segment_code is: - a: bit 0, b: bit 1....., h: bit 7. ``` cpp=2 const ap_uint<8> seven_segment_code[10] = { 0b00000011, //0 0b10011111, //1 0b00100101, //2 0b00001101, //3 0b10011001, //4 0b01001001, //5 0b01000001, //6 0b00011111, //7 0b00000001, //8 0b00001001 //9 }; ``` - Then, here is the main function. - Only when the `enter` is high can we input a password(2346) ``` cpp=42 void combination_lock( ap_uint<4> x, bool enter, bool &door_open, bool lock, ap_uint<8> &seven_segment_data, ap_uint<4> &seven_segment_enable) { #pragma HLS PIPELINE #pragma HLS INTERFACE ap_none port=x #pragma HLS INTERFACE ap_none port=enter #pragma HLS INTERFACE ap_none port=door_open #pragma HLS INTERFACE ap_none port=lock #pragma HLS INTERFACE ap_none port=seven_segment_data #pragma HLS INTERFACE ap_none port=seven_segment_enable #pragma HLS INTERFACE ap_ctrl_none port=return //--------state variables----------------------------- static state_type state = s0; state_type next_state; //--------temporary output variables------------------ bool door_open_local = 0; //--------switch case--------------------------------- switch(state) { case s0: if (enter == 1) { if (x == 2) { next_state = s2; } else { next_state = s0; } } else { next_state = s0; } door_open_local = 0; break; case s2: if (enter == 1) { if (x == 3) { next_state = s23; } else { next_state = s0; } } else { next_state = s2; } door_open_local = 0; break; case s23: if (enter == 1) { if (x == 4) { next_state = s234; } else { next_state = s0; } } else { next_state = s23; } door_open_local = 0; break; case s234: if (enter == 1) { if (x == 6) { next_state = s2346; door_open_local = 1; } else { next_state = s0; door_open_local = 0; } } else { next_state = s234; door_open_local = 0; } break; case s2346: if (lock == 1) { next_state = s0; door_open_local = 0; } else { next_state = s2346; door_open_local = 1; } break; default: break; } //--------state and output variable assignments------------ state = next_state; door_open = door_open_local; seven_segment_data = get_seven_segment_code(state); seven_segment_enable = 0b1110; } ``` #### Output in HLS ![](https://hackmd.io/_uploads/ry6Urjzo2.png) - Enter the passwords by: - 1 -> 2 -> 3 -> 1 -> 2 -> 3 -> 4 -> 6 -> ... - door unlock when password 2346 is input. - `door_open` return when it finished executing the function in kernel. If we try to get the return value at the same time we input our password in verilog, it will get the value of the last clock cycle, since we use register to store the state and then return the value of which state we are in. #### Utilization in HLS ![](https://hackmd.io/_uploads/rJ_CI_foh.png) - 9 FF's. #### Waveform in HLS ![](https://hackmd.io/_uploads/SyjSuufin.png) ### In Verilog ``` verilog= `define S0 4'd0 `define S2 4'd1 `define S23 4'd2 `define S234 4'd3 `define S2346 4'd4 mmodule cobination_lock ( input clk, input rst, input [3:0] x, input enter, input lock, output reg door_open, output reg [7:0] ssd_data, output reg [3:0] ssd_enable ); reg [3:0] state; reg [7:0] ssd_data; reg [0:0] next_door_open; always @* begin case (state) `S0: begin if (enter == 1'b1) begin if (x == 4'd2) begin next_state = `S2; end else begin next_state = `S0; end end else begin next_state = `S0; end next_door_open = 1'b0; end `S2: begin if (enter == 1'b1) begin if (x == 4'd3) begin next_state = `S23; end else begin next_state = `S0; end end else begin next_state = `S2; end next_door_open = 1'b0; end `S23: begin if (enter == 1'b1) begin if (x == 4'd4) begin next_state = `S234; end else begin next_state = `S0; end end else begin next_state = `S23; end next_door_open = 1'b0; end `S234: begin if (enter == 1'b1) begin if (x == 4'd6) begin next_state = `S2346; next_door_open = 1'b1; end else begin next_state = `S0; next_door_open = 1'b0; end end else begin next_state =`S234; next_door_open = 1'b0; end end `S2346: begin if (lock == 1'b1) begin next_state = `S0; next_door_open = 1'b0; end else begin next_state = `S2346; next_door_open = 1'b1; end end default: begin next_state = state; next_door_open = dor_open; end endcase ssd_data = get_ssd(state); ssd_enable = 4'b1110; end always @(posedge clk) begin if (rst) begin state <= `S0; door_open <= 1'b0; end else begin state <= next_state; door_open <= next_door_open; end end functon [7:0] get_ssd; input [3:0] state; begin case (state) 4'd0: get_ssd = 8'b00000011; 4'd1: get_ssd = 8'b10011111; 4'd2: get_ssd = 8'b00100101; 4'd3: get_ssd = 8'b00001101; 4'd4: get_ssd = 8'b10011001; 4'd5: get_ssd = 8'b01001001; 4'd6: get_ssd = 8'b01000001; 4'd7: get_ssd = 8'b00011111; 4'd8: get_ssd = 8'b00000001; 4'd9: get_ssd = 8'b00001001; default: get_ssd = 8'b00000011; endcase end endfunction endmodule ``` ## Testbench - Testbench in Verilog ``` verilog= module VIC_TESTBENCH(); reg clk; // 10ns clk reg rst; // reset reg [3:0] x; // input password reg enter; // enter the password reg lock; // if the door is unlocked, we can use this signal to lock the door. wire door_open; // to check whether the door is opened. wire [7:0] seven_segment_data; // the seven-segment display wire [3:0] seven_segment_enable; // the seven-segment display design_1_wrapper DUT (.ap_clk(clk), .ap_rst(rst), .x(x), .enter(enter), .lock(lock), .door_open(door_open), .seven_segment_data(seven_segment_data), .seven_segment_enable(seven_segment_enable)); /* combination_lock (.clk(clk), .rst(rst), .x(x), .enter(enter), .lock(lock), .door_open(door_open), .ssd_data(seven_segment_data), .ssd_enable(seven_segment_enable)); */ // 10ns clk generator initial begin clk = 1'b0; forever begin #5 clk = ~clk; end end // main function of testbench initial begin // initialize the value rst = 1'b1; x = 4'd0; enter = 1'b0; lock = 1'b0; // after 50ns, rst fall #50 rst = 1'b0; // Then input your password @(posedge clk) begin x <= 4'd1; enter <= 1'b1; end // Input as many times as you want. end endmodule ``` ### DUT (IP) - Export RTL IP and create block design ![](https://hackmd.io/_uploads/Bk8NHWVon.png) #### Utilization ![](https://hackmd.io/_uploads/SJ5-5_7jn.png) - 4 FF's #### Waveform ![](https://hackmd.io/_uploads/rJMu3nGo2.png) ![](https://hackmd.io/_uploads/HkGdhhfoh.png) - Same as the waveform of HLS ### DUT (Verilog) #### Utilization ![](https://hackmd.io/_uploads/SJId1fg22.png) #### Waveform ![](https://hackmd.io/_uploads/Sk6O1fx22.png) --- # 4. Timer ## Top Function (Kernel) ### In HLS ``` cpp= typedef enum{idle, running} timer_state_type; void timer(ap_uint<N> n, bool start, bool &end) { #pragma HLS INTERFACE ap_none port=start #pragma HLS INTERFACE ap_none port=end #pragma HLS INTERFACE ap_none port=n #pragma HLS INTERFACE ap_ctrl_none port=return static timer_state_type state = idle; static unsigned long long int timer_variable = 0; timer_state_type next_state; unsigned long long int next_timer_variable; bool end_local; switch(state) { case idle: if (start == 1) { next_state = running; end_local = 0; next_timer_variable = 0; } else { next_state = idle; end_local = 0; next_timer_variable = 0; } break; case running: if (timer_variable == n-1) { next_state = idle; end_local = 1; next_timer_variable = 0; } else { next_timer_variable = timer_variable + 1; next_state = running; end_local = 0; } break; default: break; } state = next_state; timer_variable = next_timer_variable; end = end_local; } ``` #### Code Explanation - If the `start` signal is 1, the `time_variable` start counting, when `time_variable` counted to `n`, `end` rise and change the state to `idle`. #### Output in HLS - Our goal is to inspect the signals and we don't have any specific computation, our testbench doesn't check the output. Therefore, the testbench always claims that the design is correct. ![](https://hackmd.io/_uploads/ByI0zbNih.png) - End when n = 20 #### Utilization in HLS ![](https://hackmd.io/_uploads/HkJCZb4o2.png) - 66 FF's #### Waveform in HLS ![](https://hackmd.io/_uploads/BkKbmWEin.png) - Takes 20 clk cycles (325ns-525ns). ### In Verilog ``` verilog= `define IDLE 1'b0 `define RUNNING 1'b1 module timer ( input clk, input rst, input [15:0] n, input start_r, output reg end_r ); reg [0:0] state; reg [0:0] next_state; reg [63:0] time_var; reg [63:0] next_time_var; always @* begin case (state) `IDLE: begin if (start_r == 1'b1) begin next_state = `RUNNING; next_time_var = 64'd0; end_r = 1'b0; end else begin next_state = `IDLE; next_time_var = 64'd0; end_r = 1'b0; end end `RUNNING: begin if (time_var == n = 1'b1) begin next_state = `IDLE; next_time_var = 64'd0; end_r = 1'b1; end else begin next_state = `RUNNING; next_time_var = time_var + 1'b1; end_r = 1'b0; end end endcase end always @(posedge clk) begin if (rst) begin state <= `IDLE; time_var <= 64'd0; end else begin state <= next-state; time_var <= next_time_var; end end endmodule ``` ## Testbench - We can use a blocking assignment in a procedural block in a Verilog testbench to identify our input. In a testbench, the primary purpose is to simulate and verify the functionality of the design under test (DUT). - It's important to remember that using blocking assignment in a preocedural block is specifically for testbenches and simulation purposes. In the actual hardware design, we should stick to using non-blocking assignments in sequential blocks to ensure correct and reliable simulation results. But for testbenches, using blocking assignments for input initialization is perfectly acceptable. ``` verilog= module VIC_TESTBENCH(); reg clk; // 10ns clk reg rst; // active high, synchronous reset reg [15:0] n; // input number reg timer_start; // start signal wire timer_end; // end signal integer i = 0; integer j = 0; // design under test design_1_wrapper DUT (.ap_clk(clk), .ap_rst(rst), .n(n), .start_r(timer_start), .end_r(timer_end)): // 10ns clk generator initial begin clk = 1'b1; forever begin #5 clk = ~clk; end end // main function of testbench initial begin // initialize the value rst = 1'b1; n = 16'd0; timer_start = 1'b0; // rst fall after 50ns #50 rst = 1'b0; for (i = 0; i < 20; i = i + 1) begin @(posedge clk) begin $display("Cycle %02d, Start signal: %b, End signal: %b", i, timer_start, timer_end); end end @(posedge clk) begin timer_start = 1'b1; $display("Cycle %02d, Start signal: %b, End signal: %b", j, timer_start, timer_end); end for (j = 0; j < 50; j = j + 1) begin @(posedge clk) begin timer_start = 1'b0; $display("Cycle %02d, Start signal: %b, End signal: %b", j, timer_start, timer_end); end end end endmodule ``` ### DUT (IP) - Export RTL IP and create block design. ![](https://hackmd.io/_uploads/rkPa4-4i2.png) #### Output ![](https://hackmd.io/_uploads/HkuOZWVin.png) - End when n = 20 #### Utilization ![](https://hackmd.io/_uploads/BJ-j-Z4oh.png) - 65 FF's #### Waveform ![](https://hackmd.io/_uploads/rJH2WWVsn.png) - Takes 20 clk cyces (250ns-450ns), same as the waveform of HLS design. ### DUT (Verilog) #### Utilization ![](https://hackmd.io/_uploads/r1igxZM32.png) - Same as IP #### Waveform ![](https://hackmd.io/_uploads/BJdbgZMnn.png) ----------------------------------------------------- # 4. Debouncer ## Top Function (Kernel) ### In HLS ``` cpp= #define DELAY_COUNTER 500L typedef enum{transfer, delay} debouncer_state_type; void debouncer(bool sw, bool &out) { #pragma HLS INTERFACE ap_none port=sw #pragma HLS INTERFACE ap_none port=out #pragma HLS INTERFACE ap_ctrl_none port=return static debouncer_state_type state = transfer; static unsigned long long int counter = DELAY_COUNTER; static bool previous_sw = 0; unsigned long long int next_counter; static debouncer_state_type next_state; bool out_tmp = 0; switch(state) { case transfer: if (previous_sw != sw) { next_state = delay; } else { next_state = transfer; } next_counter = DELAY_COUNTER; out_tmp = sw; break; case delay: if (counter == 0) { next_state = transfer; next_counter = DELAY_COUNTER; } else { next_counter = counter - 1; next_state = delay; } out_tmp = previous_sw; break; default: break; } previous_sw = out_tmp; state = next_state; counter = next_counter; out = out_tmp; } ``` #### Code Explanation - If the previous sw: `previous_sw` is not equal to the sw(now): `sw`, it means that the signal is bouncing. Change the state to `delay`, and stay when `DELAY_COUNTER` count to 0. #### Utilization in HLS ![](https://hackmd.io/_uploads/rya9TJHi2.png) - 67 FF's for registers. #### Waveform in HLS ![](https://hackmd.io/_uploads/Syun6JHon.png) - We can see that the area between 2 blue markers is the delay time. ### In Verilog ``` verilog= `define DELAY_COUNTER 64'd500 `define TRANSFER 1'b0 `define DELAY 1'b1 module debouncer ( input clk, input rst, input sd, output reg out_r ); reg [0:0] previous_sw; reg [0:0] out_tmp; reg [63:0] counter; reg [63:0] next_counter; reg [0:0] state; reg [0:0] next_state; always @* begin case (state) `TRANSFER: begin if (previous_sw != sw) begin next_state = `DELAY; end else begin next_state = `TRANSFER; end next_counter = `DELAY_COUNTER; out_tmp = sw; end `DELAY begin if (counter == 64'd0) begin next_state = `TRANSFER; next_counter = `DELAY_COUNTER; end else begin next_state = `DELAY; next_counter = counter - 1'b1; end out_tmp = previous_sw; end endcase end always @(posedge clk) begin if (rst) begin out_r <= 1'b0; state <= `TRANSFER; counter <= `DELAY_CONTER; end else begin out_r <= out_tmp; state <= next_state; counter <= next_counter; end end endmodule ``` ## Testbench - Testbench in Verilog ``` verilog= module VIC_TESTBENCH(); reg clk; // the 10ns clk reg rst; // active high, synchronous reseet reg sw; // the signal that hasn't been debounced wire debounced_out; // the debounced signal integer i; // design under test design_1_wrapper DUT (.ap_clk(clk), .ap_rst(rst), .sw(sw), .out_r(debounced_out)); // 10ns clk generator initial begin clk = 1'b1; forever begin #5 clk = ~clk; end end // main function of testbench initial begin // initialize the value rst = 1'b1; sw = 1'b0; // rst fall after 50ns #50 @(posedge clk) rst = 1'b0; // delay for a long time in order to check the debounced value more easier. #5000 // push the button, bouncing for (i = 0; i < 250; i = i + 1) begin @(posedge clk) sw = 1'b0; @(posedge clk) sw = 1'b1; end // stable for (i = 0; i < 5000; i = i + 1) begin @(posedge clk) sw = 1'b1; end // release the button, bouncing for (i = 0; i < 250; i = i + 1) begin @(posedge clk) sw = 1'b1; @(posedge clk) sw = 1'b0; end // stable at the end for (i = 0; i < 5000; i = i + 1) begin @(posedge clk) sw = 1'b0; end end endmodule ``` ### DUT (IP) - Export RTL IP and create block design in verilog ![](https://hackmd.io/_uploads/BJM4Ayrj3.png) #### Utilization ![](https://hackmd.io/_uploads/rJKW-grsh.png) - 66 FF's for registers. #### Waveform ![](https://hackmd.io/_uploads/rymlbgHih.png) - Same as the waveform of HLS ### DUT (Verilog) #### Utilization ![](https://hackmd.io/_uploads/ByNhZBX3n.png) #### Waveform ![](https://hackmd.io/_uploads/HJh3bB73h.png) ---------------------------------------------- # 6. Counter ## Top Function (Kernel) ### In HLS ``` cpp= typedef enum{wait_for_one, wait_for_zero} counter_state_type; void counter( bool count_button, ap_uint<8> &seven_segments_data, ap_uint<4> &seven_segments_enable) { #pragma HLS INTERFACE ap_ctrl_none port=return #pragma HLS INTERFACE ap_none port=count_button #pragma HLS INTERFACE ap_none port=seven_segments_data #pragma HLS INTERFACE ap_none port=seven_segments_enable static ap_uint<5> number = 0; static counter_state_type state = wait_for_one; ap_uint<5> next_number; counter_state_type next_state; bool out_local; switch(state) { case wait_for_one: if (count_button == 1) { if (number+1 == 10) { next_number = 0; } else { next_number = number+1; } next_state = wait_for_zero; } else { next_number = number; next_state = wait_for_one; } break; case wait_for_zero: if (count_button == 1) { next_number = number; next_state = wait_for_zero; } else { next_number = number; next_state = wait_for_one; } break; default: break; } number = next_number; state = next_state; // which will get the binary number of seven-segment code seven_segments_data = get_seven_segment_code(number); seven_segments_enable = 0b1110; } ``` #### Utilization in HLS ![](https://hackmd.io/_uploads/SylVyFijh.png) - Uses 7 FFs for registers #### Waveform in HLS ![](https://hackmd.io/_uploads/S1fSyYjo2.png) ### In Verilog ``` verilog= `define WAIT_FOR_ONE 1'b0 `define WAIT_FOR_ZERO 1'b0 module counter( input wire clk, input wire rst, input wire [0:0] count_button, output reg [7:0] seven_segments_data, output reg [3:0] seven_segments_enable ); reg [3:0] num; reg [3:0] next_num; reg [0:0] state; reg [0:0] next_state; // BCD to seven-segment function [7:0] bcd2ssd; input [3:0] number; begin case (number) 4'd0: bcd2ssd = 8'b11000000; 4'd1: bcd2ssd = 8'b11111001; 4'd2: bcd2ssd = 8'b10100100; 4'd3: bcd2ssd = 8'b10110000; 4'd4: bcd2ssd = 8'b10011001; 4'd5: bcd2ssd = 8'b10010010; 4'd6: bcd2ssd = 8'b10000010; 4'd7: bcd2ssd = 8'b11111000; 4'd8: bcd2ssd = 8'b10000000; 4'd9: bcd2ssd = 8'b10010000; default: bcd2ssd = 8'b11000000; endcase end endfunction // main function of the testbench always @* begin case (state) `WAIT_FOR_ONE: if (count_button == 1'b1) begin if (num + 1'b1 == 4'd10) begin next_num = 4'd0; end else begin next_num = num + 1'b1; end next_state = `WAIT_FOR_ZERO; end else begin next_num = num; next_state = `WAIR_FOR_ONE; end `WAIT_FOR_ZERO: if (count_button == 1'b1) begin next_num = num; next_state = `WAIT_FOR_ZERO; end else begin next_num = num; next_state = `WAIT_FOR_ONE; end default: begin next_num = num; next_state = state; end endcase seven_segments_data = bcd2ssd(next_num); seven_segments_enable = 4'b1110; end always @(posedge clk) begin if (rst) begin num <= 4'd0; state <= `WAIT_FOR_ONE; end else begin num <= next_num; state <= next_state; end end endmodule ``` ## Testbench - Testbench in Verilog ``` verilog= module VIC_TESTBENCH(); reg clk; reg rst; reg [0:0] button; wire [7:0] ssd_data; wire [3:0] ssd_enable; reg [3:0] ssd_number; integer i; // design under test design_1_wrapper DUT0 (.ap_clk(clk), .ap_rst(rst), .count_button(button), .seven_segments_data(ssd_data), .seven_segments_enable(ssd_enable)); /* count DUT1 (.ap_clk(clk), .ap_rst(rst), .count_button(button), .seven_segments_data(ssd_data), .seven_segments_enable(ssd_enable)); */ // 10ns clk generator initial begin clk = 1'b1; forever begin #5 clk = ~clk; end end // ssd number task ssd_number_generate; input [7:0] ssd_data; output [3:0] number; begin case (ssd_data) 8'b11000000: number = 4'd0; 8'b11111001: number = 4'd1; 8'b10100100: number = 4'd3; 8'b10011001: number - 4'd4; 8'b10010010: number = 4'd5; 8'b10000010: number = 4'd6; 8'b11111000: number = 4'd7; 8'b10000000: number = 4'd8; 8'b10010000: number = 4'd9; default: number = 4'd0; endcase end endtask // main function of the testbench initial begin // initialize the value rst = 1'b1; button = 1'b0; // rst fall #125 rst = 1'b0; for (i = 0; i < 10; i = i + 1) begin @(posedge clk) button <= 1'b1; #10 ssd_number_generate(ssd_data, ssd_number); $display("count_up = %b, output = %d", button, ssd_number); @(posedge clk) button <= 1'b0; #10 ssd_number_generate(ssd_data, ssd_number); $display("count_up = %b, output = %d", button, ssd_number); end end endmodule ``` ### DUT (IP) - Export RTL IP and create block design ![](https://hackmd.io/_uploads/ByL_yKjsn.png) #### Utilization ![](https://hackmd.io/_uploads/r1xK1Fjj2.png) - Uses 11 LUTs, and 6 FFs for registers. #### Waveform ![](https://hackmd.io/_uploads/S1yhyFsj3.png) ### DUT (Verilog) #### Utilization ![](https://hackmd.io/_uploads/SkUhJFssn.png) - Uses 10 LUTs, and 5 FFs for registers, which are less than IP. #### Waveform ![](https://hackmd.io/_uploads/SyinJKsjn.png) --------------------------------------------------- # 7. Clock Generator ## Top Function (Kernel) ### In HLS ``` cpp= #define CLOCK_FREQUENCY_DIVISOR 20 typedef enum{zero, one} clock_state_type; void clock_generator(bool &slow_clock_signal) { #pragma HLS INTERFACE ap_none port=slow_clock_signal #pragma HLS INTERFACE ap_ctrl_none port=return static clock_state_type state = zero; static unsigned int counter = CLOCK_FREQUENCY_DIVISOR /2-1; clock_state_type next_state; unsigned int next_counter; bool slow_clock_signal_local; switch(state) { case zero: if (counter == 0) { next_counter = CLOCK_FREQUENCY_DIVISOR /2-1; next_state = one; } else { next_counter = counter-1; next_state = zero; } slow_clock_signal_local = 0; break; case one: if (counter == 0) { next_counter = CLOCK_FREQUENCY_DIVISOR /2-1; next_state = zero; } else { next_counter = counter-1; next_state = one; } slow_clock_signal_local = 1; break; default: break; } state = next_state; counter = next_counter; slow_clock_signal = slow_clock_signal_local; } ``` - Utilization in HLS ![](https://hackmd.io/_uploads/SkGCS64nn.png) - Waveform of HLS waveform viewer ![](https://hackmd.io/_uploads/HkP0SpN3n.png) ### In Verilog ``` verilog= `define ZERO 1'b0 `define ONE 1'b1 `define CLK_FREQ_DIV 32'd20 module clock_generator ( input clk, input rst, output slow_clk_signal ); reg slow_clk_signal; reg tmp_clk_signal; reg [31:0] counter; reg [31:0] next_counter; reg [0:0] state; reg [0:0] next_state; always @* begin case (state) `ZERO: begin if (counter == 32'd0) begin next_counter = `CLK_FREQ_DIV / 2 - 1'b1; next_state = `ONE; end else begin next_counter = counter - 1'b1; next_state = `ZERO end tmp_clk_signal = 1'b0; end `ONE: begin if (counter == 32'd0) begin next_counter = `CLK_FREQ_DIV / 2 - 1'b1; next_state = `ZERO; end else begin next_counter = counter - 1'b1; next_state = `ONE; end tmp_clk_signal = 1'b1; end default: begin next_counter = `CLK_FREQ_DIV / 2 - 1'b1; next_state = `ZERO; tmp_clk_signal = 1'b0; end endcase end always @(posedge clk) begin if (rst) begin slow_clk_signal <= 1'b0; counter <= `CLK_FREQ_DIV /2 - 1'b1; state <= `ZERO; end else begin slow_clk_signal <= tmp_clk_signal; counter <= next_counter; state <= next_state; end end endmodule ``` ## Testbench - Testbench in Verilog ``` verilog= module VIC_TESTBENCH(); reg clk; reg rst; wire slow_clk_signal; integer i; // design under test design_1_wrapper DUT0 (.ap_clk(clk), .ap_rst(rst), .slow_clock_signal(slow_clk_signal)); /* clock_generator DUT1 (.clk(clk), .rst(rst), .slow_clk_signal(slow_clk_signal)); */ // 10ns clk generator initial begin clk = 1'b1; forever begin #5 clk = ~clk; end end // main function of testbench initial begin rst = 1'b1; #50 @(posedge clk) rst = 1'b0; for (i = 0; i < 100; i = i + 1) begin @(posedge clk) begin $display("%b", slow_clk_signal); end end end endmodule ``` ### DUP (IP) - Export RTL IP and create block design ![](https://hackmd.io/_uploads/HyH1UTNhh.png) #### Utilization ![](https://hackmd.io/_uploads/Syxq1LpVnn.png) #### Waveform ![](https://hackmd.io/_uploads/By01IT4nh.png) ### DUP (Verilog) #### Utilization ![](https://hackmd.io/_uploads/SkUg86Eh3.png) - More LUTs and FFs then DUT(IP). #### Wavefrom ![](https://hackmd.io/_uploads/BJoxLaN33.png) - clk appears 50ns later then DUT(IP). # 8. Pulse Generator ## Top Function (Kernel) ### In HLS ``` cpp= typedef enum{w1, w0} pulse_gen_states_type; void pulse_generator(bool input, bool &pulse) { #pragma HLS INTERFACE ap_none port=input #pragma HLS INTERFACE ap_none port=pulse #pragma HLS INTERFACE ap_ctrl_none port=return static pulse_gen_states_type state = w1; pulse_gen_states_type next_state; bool next_pulse; switch(state) { case w1: if (input == 1) { next_state = w0; next_pulse = 1; } else { next_state = w1; next_pulse = 0; } break; case w0: if (input == 1) { next_state = w0; next_pulse = 0; } else { next_state = w1; next_pulse = 0; } break; default: break; } state = next_state; pulse = next_pulse; } ``` #### Utilization in HLS ![](https://hackmd.io/_uploads/BJrXAp_3n.png) #### Waveform Viewer (from HLS) ![](https://hackmd.io/_uploads/ry6XRadn3.png) ### In Verilog ``` verilog= `define W0 1'b0 `define W1 1'b1 module pulse_generator ( input clk, input rst, input in_signal, output reg pulse ); reg state; reg next_state; always @* begin case (state) `W1: begin if (in_signal == 1'b1) begin next_state = W0; pulse = 1'b1; end else begin next_state = `W1; pulse = 1'b0; end end `W0: begin if (in_signal == 1'b1) begin next_state = `W0; pulse = 1'b0; end else begin next_state = `W1; pulse = 1'b0; end end default: begin next_state = `W1; pulse = 1'b0; end endcase end always @(posedge clk) begin if (rst) begin state <= `W1; end else begin state <= next_state; end end endmodule ``` ## Testbench - Testbench in Verilog ``` verilog= module VIC_TESTBENCH(); reg clk; reg rst; reg [0:0] in_signal; wire pulse; // design under test design_1_wrapper DUT0 (.ap_clk(clk), .ap_rst(rst), .input_r(in_signal), .pulse(pulse)); /* pulse_generator DUT1 (.clk(clk), .rst(rst), .in_signal(in_signal), .pulse(pulse)); */ // 10ns clk generator initial begin clk = 1'b1; forever begin #5 clk = ~clk; end end // main function of the testbench initial begin rst = 1'b1; in_signal = 1'b0; #125 @(posedge clk) rst = 1'b1; #50 @(posedge clk) in_signal <= 1'b1; #50 in_signal = 1'b0; end endmodule ``` ### DUT (IP) - Export RTL IP and create block design ![](https://hackmd.io/_uploads/rkwqe0_22.png) #### Utilization ![](https://hackmd.io/_uploads/r1Y2eCO3n.png) ![](https://hackmd.io/_uploads/H1N8eA_2h.png) #### Waveform ![](https://hackmd.io/_uploads/HyLqLMzTn.png) ### DUT (Verilog) #### Utilization ![](https://hackmd.io/_uploads/B1RoxC_3n.png) ![](https://hackmd.io/_uploads/r1z3lRdn3.png) - Same as HLS design #### Waveform ![](https://hackmd.io/_uploads/BkeiIfMTh.png) # 9. Single Cycle Regular Pulses ## Top Function (Kernel) ### In HLS ``` cpp= #define PULSE_PERIOD 20 typedef enum{zero, one} states_type; void single_cycle_regular_pulses(bool &periodic_pulses) { #pragma HLS INTERFACE ap_none port=periodic_pulses #pragma HLS INTERFACE ap_ctrl_none port=return static states_type state = zero; static unsigned int counter = PULSE_PERIOD-1; states_type next_state; unsigned int next_counter; bool periodic_pulses_local; switch(state) { case zero: if (counter == 1) { next_counter = counter-1; next_state = one; } else { next_counter = counter-1; next_state = zero; } periodic_pulses_local = 0; break; case one: next_counter = PULSE_PERIOD-1; next_state = zero; periodic_pulses_local = 1; break; default: break; } state = next_state; counter = next_counter; periodic_pulses = periodic_pulses_local; } ``` #### Utilization in HLS ![](https://hackmd.io/_uploads/B12oVGY22.png) #### Waveform Viewer ![](https://hackmd.io/_uploads/r1bhNzK3h.png) ### In Verilog ``` verilog= `define ZERO 1'b0 `define ONE 1'b1 `define PULSE_PERIOD 32'd20 module single_cycle_regular_pulse( input clk, input rst, output reg periodic_pulses ); reg [31:0] counter; reg [31:0] next_counter; reg [0:0] state; reg [0:0] next_state; always @* begin case (state) `ZERO: begin if (counter == 32'd1) begin next_counter = counter - 1'b1; next_state = `ONE; end else begin next_counter = counter - 1'b1; next_state = `ZERO; end periodic_pulses = 1'b0; end `ONE: begin next_counter = `PULSE_PERIOD - 1'b1; next_state = `ZERO; periodic_pulses = 1'b1; end default: begin next_counter = counter - 1'b1; next_state = `ZERO; periodic_pulses = 1'b1; end endcase end always @(posedge clk) begin if (rst) begin state <= `ZERO; counter <= `PULSE_PERIOD - 1'b1; end else begin state <= next_state; counter <= next_counter; end end endmodule ``` ## Testbench - Testbench in Verilog ``` verilog module VIC_TESTBENCH(); reg clk; reg rst; wire periodic_pulses; // design under test design_1_wrapper DUT0 (.ap_clk(clk), .ap_rst(rst), .periodic_pulses(periodic_pulses)); /* single_cycle_regular_pulse DUT1 (.clk(clk), .rst(rst), .periodic_pulses(periodic_pulses)); */ // 10ns clk generator initial begin clk = 1'b1; forever begin #5 clk = ~clk; end end // main function of the testbench initial begin rst = 1'b1 #100 @(posedge clk) rst = 1'b0; end endmodule ``` ### DUT (IP) - Export RTL IP and create block design in vivado ![](https://hackmd.io/_uploads/r1QqvMKn3.png) #### Utilization ![](https://hackmd.io/_uploads/ry95wzYnh.png) #### Waveforn ![](https://hackmd.io/_uploads/r11iDzK3n.png) ### DUT (Verilog) #### Utilization ![](https://hackmd.io/_uploads/HkxBsvfF3h.png) #### Waveform ![](https://hackmd.io/_uploads/B12iwMthh.png)