├── Bit_Serial_Adder ├── bit_serial_adder.sv └── tb_adder.sv ├── Counter_Ready_Valid ├── Readme.md ├── counter_ready_valid.sv └── formal_proprieties.sv ├── LICENSE ├── Multiply_Repeated_Addition ├── Readme.md ├── mult.png ├── mult.sv └── tb_mult.sv ├── Polynomial_Pipeline ├── Readme.md ├── cubic_poly_pipe.sv ├── seq_cubic.png ├── sequential_cube_poly.sv ├── tb_cubic_poly_pipe.sv ├── tb_seq_pply.sv └── waveform_pipeline.png ├── README.md ├── Register_File ├── Readme.md ├── reg_file.png ├── register_file.sv └── tb_register_file.sv ├── Round_Robin_Arbiter ├── Readme.md ├── rr.png ├── rr_arbiter.sv └── tb_rr_arbiter.sv └── Sync Memory ├── Readme.md ├── TB_mem.sv ├── sync_mem_rd_fwd.sv ├── timing_mem.png └── timing_mem_prv_write.png /Bit_Serial_Adder/bit_serial_adder.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Bit Serial Sequential Adder 3 | // Tradeoff Area for Time 4 | // 5 | module bit_serial_adder ( 6 | input logic clk, 7 | input logic rst_n, 8 | // 9 | input logic valid_in, 10 | input logic [3:0] in_a, 11 | input logic [3:0] in_b, 12 | output logic ready_out, 13 | // 14 | output logic [3:0] y_out, 15 | output logic valid_out 16 | ); 17 | 18 | logic [3:0] reg_a, reg_b; 19 | logic c_out; 20 | 21 | logic s_out; 22 | logic c_reg; 23 | 24 | logic [2:0] count; 25 | 26 | always_ff@(posedge clk, negedge rst_n) begin 27 | if (!rst_n) begin 28 | reg_a <= '0; 29 | reg_b <= '0; 30 | c_reg <= 0; 31 | count <= '0; 32 | ready_out <= 1; 33 | valid_out <= 0; 34 | end 35 | else if (valid_in && ready_out) begin 36 | reg_a <= in_a; 37 | reg_b <= in_b; 38 | count <= count + 1; 39 | ready_out <= 0; 40 | valid_out <= 0; 41 | end 42 | else if (count >= 3'b001) begin 43 | reg_a <= {s_out, reg_a[3:1]} ; 44 | reg_b <= reg_b >> 1; 45 | c_reg <= c_out; 46 | count <= count + 1; 47 | if (count == 3'b100) begin 48 | ready_out <= 1; 49 | valid_out <= 1; 50 | count <= '0; 51 | end 52 | end 53 | end 54 | 55 | assign y_out = reg_a; 56 | 57 | assign {c_out, s_out} = reg_a[0] + reg_b[0] + c_reg; 58 | 59 | 60 | // 61 | // ------------------ SVA ------------- 62 | // 63 | 64 | // 1 65 | property ready_valid_in_P; 66 | @(posedge clk) disable iff (!rst_n) 67 | valid_in && !ready_out |-> ##1 valid_in && $stable(in_a) && $stable(in_b); 68 | endproperty 69 | 70 | // 2 71 | logic [3:0] in_1, in_2; 72 | logic [3:0] sum_out; 73 | always_ff@(posedge clk, negedge rst_n) begin 74 | if (!rst_n) begin 75 | in_1 <= '0; 76 | in_2 <= '0; 77 | end 78 | else if (valid_in && ready_out) begin 79 | in_1 <= in_a; 80 | in_2 <= in_b; 81 | end 82 | end 83 | 84 | assign sum_out = in_1 + in_2; 85 | 86 | property out_check_P; 87 | @(posedge clk) disable iff (!rst_n) 88 | valid_out |-> (y_out == sum_out); 89 | endproperty 90 | 91 | 92 | // assert the properties 93 | 94 | assume property(ready_valid_in_P) $display($time, " PASS-1"); 95 | else $display($time, " FAILED-1"); 96 | 97 | assert property(out_check_P) $display($time, " PASS-2"); 98 | else $display($time, " FAILED-2"); 99 | 100 | 101 | 102 | 103 | endmodule 104 | -------------------------------------------------------------------------------- /Bit_Serial_Adder/tb_adder.sv: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | logic clk; 4 | logic rst_n; 5 | // 6 | logic valid_in; 7 | logic [3:0] in_a; 8 | logic [3:0] in_b; 9 | // 10 | logic [3:0] y_out; 11 | logic valid_out, ready_out; 12 | 13 | 14 | 15 | bit_serial_adder DUT ( 16 | clk, 17 | rst_n, 18 | // 19 | valid_in, 20 | in_a, 21 | in_b, 22 | ready_out, 23 | // 24 | y_out, 25 | valid_out 26 | ); 27 | 28 | initial begin 29 | clk = 0; 30 | rst_n = 0; 31 | valid_in = 0; 32 | @(negedge clk) rst_n = 1; 33 | in_a = 4'ha; in_b = 4'h4; valid_in = 1; 34 | 35 | @(negedge clk) in_a = 4'h2; in_b = 4'h8; valid_in = 1; 36 | 37 | repeat(5) @(negedge clk); 38 | valid_in = 0; 39 | 40 | #20 $finish; 41 | end 42 | 43 | always #20 clk = ~clk; 44 | 45 | 46 | endmodule 47 | -------------------------------------------------------------------------------- /Counter_Ready_Valid/Readme.md: -------------------------------------------------------------------------------- 1 | # Formal Verification of a Counter [SystemVerilog] 2 | The design is a counter that counts down from a start value to zero. The start value is fixed and is set to 4'ha. 3 | The counter follows a ready/valid protocol at the input interface. 4 | 5 | The detailed description for formal verification of the counter is shown in my blog: https://www.autonomousvision.io/blog/formal-verification-symbiyosys 6 | 7 | I use Symbiyosys formal tool to implement the formal property verification environment. 8 | 9 | SVA based properties for counter: 10 | - Reset value checks: After reset, the outputs should default to reset values. 11 | - Ready/Valid interface: We will follow the ready/valid specification for the input interface. 12 | - DUT Functionality: When the counter accepts a valid input request it should start with the correct start value and decrement until it goes to 0. 13 | Should not accept any new incoming requests when it is busy. 14 | - Data Integrity: For this design, we don't have data integrity verification 15 | -------------------------------------------------------------------------------- /Counter_Ready_Valid/counter_ready_valid.sv: -------------------------------------------------------------------------------- 1 | module counter_ready_valid ( 2 | input logic clk, 3 | input logic rst, 4 | // Input interface 5 | input logic valid_in, 6 | output logic ready_out, 7 | // 8 | output logic [3:0] counter_out 9 | ); 10 | 11 | always_ff @( posedge clk) begin 12 | if (rst) begin 13 | counter_out <= '0; 14 | end 15 | 16 | else begin 17 | if (valid_in && ready_out) begin 18 | counter_out <= 4'ha; 19 | end 20 | else if (counter_out != '0) begin 21 | counter_out <= counter_out - 1; 22 | end 23 | end 24 | end 25 | 26 | assign ready_out = (counter_out == 0); 27 | 28 | 29 | 30 | // --------------------------------- FORMAL VERIFICATION -------------------// 31 | // 32 | 33 | `ifdef FORMAL 34 | 35 | initial begin 36 | assume(rst); 37 | assume (!valid_in); 38 | end 39 | 40 | logic past_check; 41 | initial past_check = 0; 42 | always_ff@(posedge clk) begin 43 | past_check <= 1; 44 | if (!past_check) assume(rst); 45 | end 46 | 47 | // // deassert the reset 48 | // always_ff@(posedge clk) begin 49 | // if (past_check) assume(!rst); 50 | // end 51 | 52 | // reset assertion on output 53 | // rst |-> ##1 (ready_out==1) && (counter_out == '0); 54 | always_ff@(posedge clk) begin 55 | if (past_check && $past(rst)) begin 56 | assert(ready_out); 57 | assert(counter_out == '0); 58 | end 59 | end 60 | 61 | // --------- Input interrface -------------// 62 | // assume: valid_in && !ready_out |-> ##1 valid_in; 63 | always_ff@(posedge clk) begin 64 | if (past_check && !rst && $past(valid_in) && $past(!ready_out)) begin 65 | assume(valid_in); 66 | end 67 | end 68 | 69 | // assert valid_in && !ready_out |-> ##[1:10] ready_out; 70 | logic [3:0] req_delay; 71 | initial req_delay = '0; 72 | always_ff@(posedge clk) begin 73 | if (rst) req_delay <= '0; 74 | 75 | else if ((valid_in) && (ready_out)) begin 76 | req_delay <= '0; 77 | end 78 | 79 | else if((valid_in) && !(ready_out)) begin 80 | req_delay <= req_delay + 1; 81 | end 82 | end 83 | always_ff@(posedge clk) begin 84 | if (past_check && !$past(rst) && $past(valid_in) && !$past(ready_out)) begin 85 | assert(req_delay <= 4'd10); 86 | end 87 | end 88 | 89 | // Specification checking // 90 | // !ready_out |-> ##1 (counter == $past(counter) -1); 91 | // valid_in && ready_out |-> ##1 (counter_out == 4'ha) && !ready_out; 92 | // counter_out >= '0; 93 | always_ff@(posedge clk) begin 94 | if(past_check && !$past(rst) && !$past(ready_out)) begin 95 | assert(counter_out == $past(counter_out) - 1 ); 96 | end 97 | 98 | if (past_check && !$past(rst) && $past(valid_in) && $past(ready_out)) begin 99 | assert(counter_out == 4'ha); 100 | assert(!ready_out); 101 | end 102 | 103 | if(past_check) begin 104 | assert(counter_out >= 0); 105 | assert(counter_out <= 4'ha); 106 | end 107 | end 108 | 109 | // Cover properties to make sure we don't overconstraint our signals 110 | 111 | // ready_out |-> ##1 !ready_out 112 | always_ff@(posedge clk) begin 113 | if (!$past(rst) && past_check) begin 114 | cover( $past(!ready_out) && ready_out); 115 | cover($past(req_delay == 4'd2) && (req_delay == '0)); 116 | cover(); 117 | end 118 | end 119 | 120 | 121 | 122 | `endif 123 | 124 | 125 | endmodule 126 | -------------------------------------------------------------------------------- /Counter_Ready_Valid/formal_proprieties.sv: -------------------------------------------------------------------------------- 1 | module formal_properties ( 2 | input logic clk, 3 | input logic rst, 4 | // Input interface 5 | input logic valid_in, 6 | input logic ready_out, 7 | // 8 | input logic [3:0] counter_out 9 | ); 10 | 11 | 12 | initial begin 13 | assume(rst); 14 | assume (!valid_in); 15 | end 16 | 17 | logic past_check; 18 | initial past_check = 0; 19 | always_ff@(posedge clk) begin 20 | past_check <= 1; 21 | if (!past_check) assume(rst); 22 | end 23 | 24 | // // deassert the reset 25 | // always_ff@(posedge clk) begin 26 | // if (past_check) assume(!rst); 27 | // end 28 | 29 | // reset assertion on output 30 | // rst |-> ##1 (ready_out==1) && (counter_out == '0); 31 | always_ff@(posedge clk) begin 32 | if (past_check && $past(rst)) begin 33 | assert(ready_out); 34 | assert(counter_out == '0); 35 | end 36 | end 37 | 38 | // --------- Input interrface -------------// 39 | // assume: valid_in && !ready_out |-> ##1 valid_in; 40 | always_ff@(posedge clk) begin 41 | if (past_check && !rst && $past(valid_in) && $past(!ready_out)) begin 42 | assume(valid_in); 43 | end 44 | end 45 | 46 | // assert valid_in && !ready_out |-> ##[1:10] ready_out; 47 | logic [3:0] req_delay; 48 | initial req_delay = '0; 49 | always_ff@(posedge clk) begin 50 | if (rst) req_delay <= '0; 51 | 52 | else if ((valid_in) && (ready_out)) begin 53 | req_delay <= '0; 54 | end 55 | 56 | else if((valid_in) && !(ready_out)) begin 57 | req_delay <= req_delay + 1; 58 | end 59 | end 60 | always_ff@(posedge clk) begin 61 | if (past_check && !$past(rst) && $past(valid_in) && !$past(ready_out)) begin 62 | assert(req_delay <= 4'd10); 63 | end 64 | end 65 | 66 | // Specification checking // 67 | // !ready_out |-> ##1 (counter == $past(counter) -1); 68 | // valid_in && ready_out |-> ##1 (counter_out == 4'ha) && !ready_out; 69 | // counter_out >= '0; 70 | always_ff@(posedge clk) begin 71 | if(past_check && !$past(rst) && !$past(ready_out)) begin 72 | assert(counter_out == $past(counter_out) - 1 ); 73 | end 74 | 75 | if (past_check && !$past(rst) && $past(valid_in) && $past(ready_out)) begin 76 | assert(counter_out == 4'ha); 77 | assert(!ready_out); 78 | end 79 | 80 | if(past_check) begin 81 | assert(counter_out >= 0); 82 | assert(counter_out <= 4'ha); 83 | end 84 | end 85 | 86 | // Cover properties to make sure we don't overconstraint our signals 87 | 88 | // ready_out |-> ##1 !ready_out 89 | always_ff@(posedge clk) begin 90 | if (!$past(rst) && past_check) begin 91 | cover( $past(!ready_out) && ready_out); 92 | cover($past(req_delay == 4'd2) && (req_delay == '0)); 93 | cover(); 94 | end 95 | end 96 | 97 | 98 | 99 | endmodule 100 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Abhishek Vashist 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Multiply_Repeated_Addition/Readme.md: -------------------------------------------------------------------------------- 1 | # RTL Design of Multiplication using Repeated Addition Algorithm [SystemVerilog] 2 | 3 | Multiplication is one of the fundamental arithmetic operation that most of the hardware need to implement. 4 | Multiplication can be done suing many algorithms, in this design I present hardware design using a simple 5 | repeated addition algorithm to multiply two 4-bit unsigned input integers. 6 | 7 | The design follows Ready/Valid protocol at the input interface and the RTL is designed as a Finite State Machine (FSM). 8 | 9 | Here's the EDAPlayground link for the implemented design: https://www.edaplayground.com/x/FFLL 10 | 11 | To understand working of Ready/Valid protocol refer my block at: https://www.autonomousvision.io/blog/formal-approach-to-verification 12 | 13 | The waveform below shows the working of the implement algorithm. We see after first set of inputs are applied we get an output of 0x0a at 9ns. 14 | The second input combination produces an output at 41ns. The number of clock cycles will depend on the number of times we have to perform the 15 | repeated addition. 16 | 17 | ![My Image](mult.png) 18 | -------------------------------------------------------------------------------- /Multiply_Repeated_Addition/mult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avashist003/SystemVerilog_Design_Verification/afbb6d6e715bca009c625faf1e8f90c510abe946/Multiply_Repeated_Addition/mult.png -------------------------------------------------------------------------------- /Multiply_Repeated_Addition/mult.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Multiplication using repeated addition 3 | // y = a*b = a + a + ... + a (i.e. b times) 4 | // 5 | 6 | 7 | module multiplication_algo ( 8 | input logic clk, 9 | input logic rst_n, 10 | input logic [3:0] in_a, 11 | input logic [3:0] in_b, 12 | input logic valid_in, 13 | output logic ready_out, 14 | // 15 | output logic [7:0] mult_out, 16 | output logic valid_out 17 | ); 18 | 19 | logic [3:0] reg_a, reg_b; 20 | logic [7:0] product_tmp; 21 | 22 | always_ff@(posedge clk, negedge rst_n) begin 23 | if (!rst_n) begin 24 | product_tmp <= '0; 25 | valid_out <= 0; 26 | ready_out <= 1; 27 | end 28 | else if (valid_in && ready_out) begin 29 | reg_a <= in_a; 30 | reg_b <= in_b; 31 | valid_out <= 0; 32 | product_tmp <= '0; 33 | ready_out <= 0; 34 | end 35 | else if (reg_b != 0) begin 36 | reg_b <= reg_b -1 ; 37 | product_tmp <= product_tmp + reg_a; 38 | if(reg_b == 1) begin 39 | valid_out <= 1; 40 | ready_out <= 1; 41 | end 42 | end 43 | end 44 | 45 | assign mult_out = product_tmp; 46 | 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /Multiply_Repeated_Addition/tb_mult.sv: -------------------------------------------------------------------------------- 1 | 2 | module test; 3 | 4 | logic clk; 5 | logic rst_n; 6 | logic [3:0] in_a; 7 | logic [3:0] in_b; 8 | logic valid_in; 9 | logic ready_out; 10 | // 11 | logic [7:0] mult_out; 12 | logic valid_out; 13 | 14 | 15 | multiplication_algo DUT (clk, rst_n, in_a, in_b, 16 | valid_in, ready_out, 17 | mult_out, valid_out); 18 | 19 | initial begin 20 | clk = 0; 21 | rst_n = 0; 22 | valid_in = 0; 23 | in_a = 0; 24 | in_b = 0; 25 | @(negedge clk) rst_n = 1; 26 | 27 | @(negedge clk) in_a = 4'h5; in_b = 4'h2; valid_in = 1; 28 | @(negedge clk) in_a = 4'h2; in_b = 4'hf; valid_in = 1; 29 | 30 | repeat(3) @(negedge clk); 31 | valid_in = 0; 32 | 33 | #50 $finish; 34 | 35 | end 36 | 37 | // 50 MHz clock 38 | always #20 clk = ~clk; 39 | 40 | // -------- SVA ------------------// 41 | 42 | logic [7:0] ref_mult_out; 43 | logic [3:0] in_1, in_2; 44 | 45 | always_ff@(posedge clk, negedge rst_n) begin 46 | if (!rst_n) begin 47 | in_1 <= '0; 48 | in_2 <= '0; 49 | end 50 | else if (valid_in && ready_out) begin 51 | in_1 = in_a; 52 | in_2 = in_b; 53 | end 54 | end 55 | // reference output 56 | assign ref_mult_out = in_1 * in_2; 57 | 58 | property out_check_P; 59 | @(posedge clk) disable iff (!rst_n) 60 | valid_out |-> (mult_out == ref_mult_out); 61 | endproperty 62 | 63 | property valid_ready_in_P; 64 | @(posedge clk) disable iff (!rst_n) 65 | valid_in && !ready_out |-> ##1 valid_in && $stable(in_a) && $stable(in_b); 66 | endproperty 67 | 68 | assume property(valid_ready_in_P) $display($time, " PASS ready/valid"); 69 | else $display($time, " FAILED ready/valid"); 70 | 71 | assert property(out_check_P) $display($time, " PASS out check"); 72 | else $display($time, " FAILED out check %h %h", mult_out, ref_mult_out); 73 | 74 | 75 | endmodule 76 | -------------------------------------------------------------------------------- /Polynomial_Pipeline/Readme.md: -------------------------------------------------------------------------------- 1 | # Pipleline RTL Implementation of a Cubic Polynomial Function [SystemVerilog] 2 | 3 | Pipelining is one of most common and powerful approach for designing high speed ASIC/FPGA logic. 4 | 5 | Here, I design a cubic equation y = x^3 + k, where x is the input and k is a constant value. 6 | If you synthesize and run the testbench, you will notice three cycle initial latency and after 7 | we have achieved steady state i.e. pipeline is full, the result is generated every clock cycle. 8 | Thereby achieving increased single cycle throughput. 9 | 10 | Here's a quick way to run the design using EDAPlayground: https://www.edaplayground.com/x/RNXY 11 | 12 | Below we show the waveform after running the EDAPlayground link. 13 | We apply the first input after the first clock and get an output for the first input after the forth clock (0x09). 14 | But we get the next output in the fifth clock (0x1c) and so on. 15 | 16 | ![My Image](waveform_pipeline.png) 17 | 18 | A sequential implementation of y = x^3 is also designed, for each input it takes three clock to produce an output. 19 | Below we show the waveform for the sequential logic of ploynomial. We see a 3-clock cyles delay between the outputs 0x08 and 0x1b. 20 | 21 | ![My Image](seq_cubic.png) 22 | -------------------------------------------------------------------------------- /Polynomial_Pipeline/cubic_poly_pipe.sv: -------------------------------------------------------------------------------- 1 | // Pipeline implementation // 2 | // Polynomial: y = x^3 + k; 3 | // 4 | // After pipeline is full, we get result every clock cycle :-) 5 | // 6 | 7 | 8 | module cubic_poly_pipe ( 9 | input logic clk, 10 | input logic rst_n, 11 | input logic [1:0] x_in, 12 | input logic [1:0] x_in_c, 13 | output logic [5:0] result_out, 14 | output logic start 15 | ); 16 | 17 | 18 | logic [1:0] x_stage_1, x_stage_2; 19 | logic [1:0] x_s_1_c,x_s_2_c; 20 | logic [5:0] x_rel_1, x_rel_2; 21 | 22 | always_ff@(posedge clk, negedge rst_n) begin 23 | if (!rst_n) begin 24 | x_stage_1 <= '0; 25 | x_rel_1 <= '0; 26 | x_s_1_c <= '0; 27 | end 28 | else if (start) begin 29 | x_stage_1 <= x_in; 30 | x_rel_1 <= x_in; 31 | x_s_1_c <= x_in_c; 32 | end 33 | end 34 | 35 | always_ff@(posedge clk, negedge rst_n) begin 36 | if (!rst_n) begin 37 | x_stage_2 <='0; 38 | x_rel_2 <= '0; 39 | x_s_2_c <= '0; 40 | end 41 | else begin 42 | x_stage_2 <= x_stage_1; 43 | x_rel_2 <= x_stage_1 * x_rel_1; // x*x 44 | x_s_2_c <= x_s_1_c; 45 | 46 | end 47 | end 48 | 49 | always_ff@(posedge clk, negedge rst_n) begin 50 | if (!rst_n) begin 51 | result_out <='0; 52 | end 53 | else begin 54 | result_out <= (x_rel_2 * x_stage_2) + x_s_2_c; // final output x^2*x + c 55 | end 56 | end 57 | 58 | endmodule 59 | 60 | -------------------------------------------------------------------------------- /Polynomial_Pipeline/seq_cubic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avashist003/SystemVerilog_Design_Verification/afbb6d6e715bca009c625faf1e8f90c510abe946/Polynomial_Pipeline/seq_cubic.png -------------------------------------------------------------------------------- /Polynomial_Pipeline/sequential_cube_poly.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Sequential implementation y = x^3 // 3 | // We get result every 3rd clock cyle 4 | // 5 | 6 | 7 | module seq_cube_poly (clk, rst_n, x_in, result_out, start, finish); 8 | input logic clk, rst_n; 9 | input logic [1:0] x_in; 10 | input logic start; 11 | output logic finish; 12 | output logic [5:0] result_out; 13 | 14 | logic [1:0] counter; 15 | logic [5:0] tmp; 16 | 17 | assign finish = (counter == '0); 18 | 19 | always_ff@(posedge clk, negedge rst_n) begin 20 | if (!rst_n) begin 21 | counter <= '0; 22 | tmp <= '0; 23 | end 24 | else begin 25 | if (start) begin 26 | counter <= 2'b10; 27 | result_out <= x_in; 28 | tmp <= x_in; 29 | end 30 | else if (!finish) begin 31 | counter <= counter - 1'b1; 32 | result_out <= tmp * result_out; 33 | end 34 | end 35 | end 36 | 37 | endmodule 38 | -------------------------------------------------------------------------------- /Polynomial_Pipeline/tb_cubic_poly_pipe.sv: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | logic clk, rst_n; 4 | logic [1:0] x_in; 5 | logic start; 6 | logic [1:0] x_in_c; 7 | 8 | logic [5:0] result_out; 9 | 10 | 11 | 12 | cubic_poly_pipe DUT (clk, rst_n, x_in, x_in_c, result_out, start); 13 | 14 | 15 | initial begin 16 | clk = 0; 17 | rst_n = 0; 18 | start = 0; 19 | @(negedge clk) rst_n = 1; 20 | x_in = 2'b10; 21 | x_in_c = 2'b01; 22 | start = 1; 23 | @(negedge clk) x_in = 2'b11; 24 | @(negedge clk) start = 0; 25 | # 10 $finish; 26 | end 27 | 28 | // 50 MHz clock 29 | always #20 clk = ~clk; 30 | 31 | endmodule 32 | -------------------------------------------------------------------------------- /Polynomial_Pipeline/tb_seq_pply.sv: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | reg clk, rst_n; 4 | reg [1:0] x_in; 5 | reg start; 6 | 7 | wire [5:0] result_out; 8 | 9 | 10 | // blow one for the sequentail version 11 | x_cube_v DUT (clk, rst_n, x_in, result_out, start, finish); 12 | 13 | initial begin 14 | clk = 0; 15 | rst_n = 0; 16 | start = 0; 17 | @(negedge clk) rst_n = 1; 18 | x_in = 2'b10; 19 | start = 1; 20 | 21 | @(negedge clk) x_in = 2'b11; 22 | @(negedge clk); 23 | @(negedge clk); 24 | 25 | 26 | @(negedge clk); start = 0; 27 | # 50 $finish; 28 | end 29 | 30 | // 50 MHz clock 31 | always #20 clk = ~clk; 32 | 33 | endmodule 34 | -------------------------------------------------------------------------------- /Polynomial_Pipeline/waveform_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avashist003/SystemVerilog_Design_Verification/afbb6d6e715bca009c625faf1e8f90c510abe946/Polynomial_Pipeline/waveform_pipeline.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SystemVerilog Design & Verification 2 | 3 | The designs are linked to my blog that explains many techniques on how to write good RTL [Blog Link](https://www.autonomousvision.io/blog). 4 | 5 | In this repository I include various RTL designs using SystemVerilog HDL. Futher, I build verification environment using Yosys formal suite along with the simulation based testbench. 6 | This will follow my #100DaysofRTL challenge on [LinkedIn](https://www.linkedin.com/feed/hashtag/?keywords=100daysofrtl). 7 | 8 | Each of the design blocks contain their own separate documention. 9 | 10 | - This repository is continuously maintained and updated. When you fork, make sure to pull frequently. 11 | -------------------------------------------------------------------------------- /Register_File/Readme.md: -------------------------------------------------------------------------------- 1 | # RTL Implementation of Register File [SystemVerilog] 2 | 3 | Register File is one of the fundamental datapath component in CPU/GPU architecture design. 4 | It act as a fast high speed storage for the CPU results. 5 | 6 | Typically the first location is always set ot a value of 0. 7 | The location-1 can never be written to a new value. The update happens at the positive edge of the clock and the 8 | read is combinational. 9 | 10 | 11 | Here's EDAPlayground link to run the design: https://www.edaplayground.com/x/a4Ff 12 | 13 | Below an example timing waveform is shown where we first perform the write operation and then the read operation. 14 | 15 | ![My Image](reg_file.png) 16 | -------------------------------------------------------------------------------- /Register_File/reg_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avashist003/SystemVerilog_Design_Verification/afbb6d6e715bca009c625faf1e8f90c510abe946/Register_File/reg_file.png -------------------------------------------------------------------------------- /Register_File/register_file.sv: -------------------------------------------------------------------------------- 1 | // Register File 2 | // SPECIFICATIONS 3 | // Two read and one write port Register File 4 | // Parameterized for Width and Depth 5 | // Register 0 cannot be written and is always set to 0 6 | // Reading is combinational i.e. available in same cycle 7 | 8 | module register_file 9 | #(parameter DATA_WIDTH = 8, 10 | // locations = 2**DEPTH 11 | parameter DEPTH = 2 12 | ) ( 13 | input logic clk, 14 | input logic rst_n, 15 | // read ports 16 | input logic [DEPTH-1:0] in_rd_addr1, 17 | input logic [DEPTH-1:0] in_rd_addr2, 18 | output logic [DATA_WIDTH-1:0] out_rd_data1, 19 | output logic [DATA_WIDTH-1:0] out_rd_data2, 20 | // write enable 21 | input logic in_we, 22 | // write ports 23 | input logic [DEPTH-1:0] in_wr_addr, 24 | input logic [DATA_WIDTH-1:0] in_wr_data 25 | ); 26 | 27 | // Registers in our register-file 28 | logic [DATA_WIDTH-1:0] reg_file [2**DEPTH-1:0]; 29 | 30 | always_ff@(posedge clk, negedge rst_n) begin 31 | if (!rst_n) begin 32 | for(integer i= 0; i < 2**DEPTH; i=i+1) begin 33 | reg_file[i] <= '0; 34 | end 35 | end 36 | // Decoder logic to select the register to write the data 37 | else begin 38 | if (in_we && (in_wr_addr != '0)) begin 39 | reg_file[in_wr_addr] <= in_wr_data; 40 | end 41 | end 42 | end 43 | 44 | 45 | // combinational Reads, MUXs with read addr as select 46 | assign out_rd_data1 = (in_rd_addr1 == '0) ? '0 : reg_file[in_rd_addr1]; 47 | assign out_rd_data2 = (in_rd_addr2 == '0) ? '0 : reg_file[in_rd_addr2]; 48 | 49 | // 50 | // 51 | // --------------------- SVA ----------------------- // 52 | // -------------------------------------------------- // 53 | // 1 Localtion-1 is never writeen and always set to 0 54 | property first1_location_zero_P; 55 | @(posedge clk) disable iff (!rst_n) 56 | in_rd_addr1 == '0 |-> (out_rd_data1 == '0); 57 | endproperty 58 | 59 | property first2_location_zero_P; 60 | @(posedge clk) disable iff (!rst_n) 61 | in_rd_addr2 == '0 |-> (out_rd_data2 == '0); 62 | endproperty 63 | 64 | 65 | first1_location_zero_A: assert property(first1_location_zero_P) 66 | else $display($time, " Failed"); 67 | 68 | first2_location_zero_A: assert property(first2_location_zero_P) 69 | else $display($time, " Failed"); 70 | 71 | endmodule 72 | -------------------------------------------------------------------------------- /Register_File/tb_register_file.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Simple Test Bench for Register File 3 | // Showing usage of systemverilog tasks in test-benches 4 | // 5 | // write_file is a task that writes to the register file 6 | // read_data is a task that reads from the register file 7 | // 8 | module tb_reg_file; 9 | 10 | parameter DEPTH = 3; 11 | parameter DATA_WIDTH = 8; 12 | 13 | 14 | logic clk, rst_n; 15 | logic in_we; 16 | logic [DEPTH-1:0] in_wr_addr; 17 | logic [DATA_WIDTH-1:0] in_wr_data; 18 | 19 | logic [DEPTH-1:0] in_rd_addr1, in_rd_addr2; 20 | logic [DATA_WIDTH-1:0] out_rd_data1, out_rd_data2; 21 | 22 | // Instantiate the DUT // 23 | register_file #(DATA_WIDTH, DEPTH) DUT 24 | (clk, rst_n, in_rd_addr1, in_rd_addr2, out_rd_data1, 25 | out_rd_data2, in_we, in_wr_addr, in_wr_data); 26 | 27 | logic [DATA_WIDTH-1:0] write_data_TB [2**DEPTH-1:0]; 28 | 29 | // Write data task 30 | task write_file; 31 | for(int i = 0; i < 2**DEPTH; i=i+1) begin 32 | @(negedge clk); 33 | in_we = 1; 34 | in_wr_addr = i; 35 | in_wr_data = $random; 36 | @(posedge clk) write_data_TB[i] = in_wr_data; 37 | end 38 | endtask 39 | 40 | // Read Data task with quick assertion checks 41 | task read_data; 42 | for(int i = 0; i < 2**DEPTH; i=i+1) begin 43 | @(negedge clk); 44 | in_rd_addr1 = i; 45 | in_rd_addr2 = i; 46 | @(posedge clk); 47 | if (i != 0) begin 48 | assert(out_rd_data2 == write_data_TB[i]); 49 | assert(out_rd_data2 == write_data_TB[i]); 50 | end 51 | else if (i == 0) begin 52 | assert(out_rd_data2 == '0); 53 | assert(out_rd_data2 == '0); 54 | end 55 | 56 | $display("rd addr %h, rd data %h",in_rd_addr1, out_rd_data1 ); 57 | $display("rd addr %h, rd data %h",in_rd_addr2, out_rd_data2 ); 58 | end 59 | endtask 60 | 61 | initial begin 62 | clk = 0; 63 | rst_n = 0; 64 | in_rd_addr1 = '0; 65 | in_rd_addr2 = '0; 66 | @(negedge clk) rst_n = 1; 67 | write_file; 68 | @(negedge clk) in_we = 0; 69 | for(int i = 0; i < 2**DEPTH; i++) begin 70 | $display("reg file %0h ", write_data_TB[i]); 71 | end 72 | // read task 73 | read_data; 74 | #10 $finish; 75 | end 76 | 77 | // 50 MHz clock 78 | always #20 clk = ~clk; 79 | 80 | endmodule 81 | -------------------------------------------------------------------------------- /Round_Robin_Arbiter/Readme.md: -------------------------------------------------------------------------------- 1 | # RTL Design of a 4-I/P Round Robin Arbiter [SystemVerilog] 2 | 3 | In many hardware designs we need a module that can arbitrate between multiple inputs (requests) to enable sharing of a common resource. 4 | Arbiter implements that functionality. 5 | 6 | 7 | Round robin arbiter further enables more fair sharing policy among multiple requesters. Here, I implement a simple 4-input round robin arbiter. 8 | The arbiter grant access to the inputs in a round-robin fashion. 9 | 10 | Here's EDAPlaygroud link to run the implemented system: https://www.edaplayground.com/x/knck 11 | 12 | Below is a snapshop of timing waveform with the implemented design. 13 | 14 | 15 | ![My Image](rr.png) 16 | -------------------------------------------------------------------------------- /Round_Robin_Arbiter/rr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avashist003/SystemVerilog_Design_Verification/afbb6d6e715bca009c625faf1e8f90c510abe946/Round_Robin_Arbiter/rr.png -------------------------------------------------------------------------------- /Round_Robin_Arbiter/rr_arbiter.sv: -------------------------------------------------------------------------------- 1 | // 2 | // 4 Input Round-Robin Arbiter 3 | // 4 | module rr_arbiter 5 | ( 6 | input logic clk, 7 | input logic rst, 8 | // first requester = req[0] 9 | // second requester = req[1] and so on ... 10 | input logic [3:0] req, 11 | // first grant = grant[0] 12 | // second grant = grant[1] and so on ... 13 | output logic [3:0] grant 14 | ); 15 | 16 | // pointer for next request to be granted 17 | logic [1:0] ptr; 18 | logic [3:0] grant_next; 19 | 20 | // grant combinational logic 21 | always_comb begin 22 | grant_next = '0; 23 | case(ptr) 24 | 2'b00: begin 25 | if (req[0]) begin 26 | grant_next = 4'b0001; 27 | end 28 | else if (req[1]) begin 29 | grant_next = 4'b0010; 30 | end 31 | else if (req[2]) begin 32 | grant_next = 4'b0100; 33 | end 34 | else if (req[3]) begin 35 | grant_next = 4'b1000; 36 | end 37 | end 38 | 2'b01: begin 39 | if (req[1]) begin 40 | grant_next = 4'b0010; 41 | end 42 | else if (req[2]) begin 43 | grant_next = 4'b0100; 44 | end 45 | else if (req[3]) begin 46 | grant_next = 4'b1000; 47 | end 48 | else if (req[0]) begin 49 | grant_next = 4'b001; 50 | end 51 | end 52 | 53 | 2'b10: begin 54 | if (req[2]) begin 55 | grant_next = 4'b0100; 56 | end 57 | else if (req[3]) begin 58 | grant_next = 4'b1000; 59 | end 60 | else if (req[0]) begin 61 | grant_next = 4'b001; 62 | end 63 | else if (req[1]) begin 64 | grant_next = 4'b0010; 65 | end 66 | end 67 | 68 | 2'b11: begin 69 | if (req[3]) begin 70 | grant_next = 4'b1000; 71 | end 72 | else if (req[0]) begin 73 | grant_next = 4'b001; 74 | end 75 | else if (req[1]) begin 76 | grant_next = 4'b0010; 77 | end 78 | else if (req[2]) begin 79 | grant_next = 4'b0100; 80 | end 81 | 82 | end 83 | 84 | endcase 85 | end 86 | 87 | // register the Grant Output 88 | always_ff@(posedge clk) begin 89 | if (rst) grant <= '0; 90 | else grant <= grant_next; 91 | end 92 | 93 | // update pointer based on the grant received 94 | always_ff@(posedge clk) begin 95 | if (rst) begin 96 | ptr <= 0; 97 | end 98 | else begin 99 | case(grant_next) 100 | 4'b0001: ptr <= 2'b01; 101 | 4'b0010: ptr <= 2'b10; 102 | 4'b0100: ptr <= 2'b11; 103 | 4'b1000: ptr <= 2'b00; 104 | endcase 105 | end 106 | end 107 | 108 | endmodule 109 | 110 | -------------------------------------------------------------------------------- /Round_Robin_Arbiter/tb_rr_arbiter.sv: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | logic clk; 4 | logic rst; 5 | logic [3:0] req; 6 | logic [3:0] grant; 7 | 8 | 9 | rr_arbiter DUT (clk, rst, req, grant); 10 | 11 | initial begin 12 | rst = 1; 13 | clk = 0; 14 | req = 4'b0000; 15 | @(negedge clk) rst = 0; 16 | 17 | // x req, o/p: x 18 | @(negedge clk) req = 4'b0001; 19 | // y req, o/p: y 20 | @(negedge clk) req = 4'b0010; 21 | // x req, o/p: x 22 | @(negedge clk) req = 4'b1000; 23 | // req x & y, o/p: y 24 | @(negedge clk) req = 4'b1011; 25 | 26 | // req x & y, o/p: x 27 | //@(negedge clk) req = 4'b0011; 28 | @(negedge clk); 29 | @(negedge clk); 30 | @(negedge clk); 31 | @(negedge clk) rst = 1; 32 | 33 | 34 | #20 $finish; 35 | end 36 | 37 | // 50 MHz clock 38 | always #20 clk = ~clk; 39 | 40 | 41 | endmodule 42 | -------------------------------------------------------------------------------- /Sync Memory/Readme.md: -------------------------------------------------------------------------------- 1 | # Synchronous Memory with Data Forwarding [SystemVerilog] 2 | 3 | The implemented synchronous memory IP performs the read and the write to locations. 4 | - Reading and writing to the same location results in new write value at the output. 5 | - This is implemented internally by performing data forwarding. 6 | 7 | EDAPlayground link to access the simulation: https://www.edaplayground.com/x/C84c 8 | 9 | Below, the timing diagram is shown where read and write to the same address is checked. 10 | 11 | 12 | ![My Image](timing_mem_prv_write.png) 13 | 14 | Above, we see at location 0x5 we write value 0x11. Later, as shown below, after a few clock cycles we update the value at 0x5 and perform the read at the same time. 15 | 16 | 17 | ![My Image](timing_mem.png) 18 | 19 | Here, at the marker, we write data 0xFF at location 0x5 and also provide read address 0x5. We see at the next clock 20 | cycle, the read outoputs the 0xFF value. 21 | -------------------------------------------------------------------------------- /Sync Memory/TB_mem.sv: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | parameter ADDR_WIDTH = 4; 4 | parameter DATA_WIDTH = 8; 5 | 6 | logic clk; 7 | logic rst; 8 | logic [ADDR_WIDTH-1:0] wr_addr_in; 9 | logic [DATA_WIDTH-1:0] wr_data_in; 10 | logic wr_en; 11 | logic [ADDR_WIDTH-1:0] rd_addr_in; 12 | logic [DATA_WIDTH-1:0] rd_data_out; 13 | 14 | 15 | 16 | sync_mem_rd_fwd #(ADDR_WIDTH, DATA_WIDTH) DUT ( 17 | clk, rst, wr_addr_in, wr_data_in, wr_en, 18 | rd_addr_in, rd_data_out); 19 | 20 | initial begin 21 | clk = 0; 22 | rst = 1; 23 | wr_en = 0; 24 | @(negedge clk) rst = 0; 25 | // write 26 | wr_en = 1; wr_addr_in = 4'ha; wr_data_in = 8'haa; 27 | // 28 | @(negedge clk) wr_en = 1; wr_addr_in = 4'h0; wr_data_in = 8'hcc; 29 | // 30 | @(negedge clk) wr_en = 0; rd_addr_in = 4'h0; 31 | // 32 | @(negedge clk) wr_en = 1; wr_addr_in = 4'h5; wr_data_in = 8'h11; 33 | // 34 | @(negedge clk) wr_en = 0; rd_addr_in = 4'ha; 35 | 36 | // Read and write to same location will give 37 | // new value for read output at the next clock 38 | @(negedge clk) 39 | wr_en = 1; wr_addr_in = 4'h5; wr_data_in = 8'hff; 40 | rd_addr_in = 4'h5; 41 | 42 | 43 | 44 | #100 $finish; 45 | end 46 | 47 | // clock generator 48 | always #25 clk = ~clk; 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /Sync Memory/sync_mem_rd_fwd.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Synchronous memory module with dual ports 3 | // Read and write to same address in the same cycle will result in 4 | // reading forwarded new value in the next clock. 5 | // 6 | module sync_mem_rd_fwd #( 7 | parameter ADDR_WIDTH = 8, 8 | parameter DATA_WIDTH = 8 9 | )( 10 | input logic clk, 11 | input logic rst, 12 | // write port 13 | input logic [ADDR_WIDTH-1:0] wr_addr_in, 14 | input logic [DATA_WIDTH-1:0] wr_data_in, 15 | input logic wr_en, 16 | // read port 17 | input logic [ADDR_WIDTH-1:0] rd_addr_in, 18 | output logic [DATA_WIDTH-1:0] rd_data_out 19 | ); 20 | 21 | // declare the memory -- flip flop based 22 | localparam DEPTH = 1 << ADDR_WIDTH; 23 | 24 | logic [DATA_WIDTH-1:0] mem [DEPTH-1:0]; 25 | 26 | 27 | always_ff@(posedge clk) begin 28 | if (wr_en) begin 29 | mem[wr_addr_in] <= wr_data_in; 30 | end 31 | end 32 | 33 | // forwarding if rd_addr is equal to wr_addr and wr-en is asserted 34 | // Use a MUX to control the forewarding 35 | logic [DATA_WIDTH-1:0] rd_data_tmp; 36 | 37 | always_ff@(posedge clk) begin 38 | if (rst) begin 39 | rd_data_tmp <= '0; 40 | end 41 | // Use an equaity comparator and and operation then use it as MUX select 42 | else if ((rd_addr_in == wr_addr_in) && wr_en) begin 43 | rd_data_tmp <= wr_data_in; 44 | end 45 | else begin 46 | rd_data_tmp <= mem[rd_addr_in]; 47 | end 48 | end 49 | 50 | // assign the read output 51 | assign rd_data_out = rd_data_tmp; 52 | 53 | 54 | 55 | endmodule 56 | -------------------------------------------------------------------------------- /Sync Memory/timing_mem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avashist003/SystemVerilog_Design_Verification/afbb6d6e715bca009c625faf1e8f90c510abe946/Sync Memory/timing_mem.png -------------------------------------------------------------------------------- /Sync Memory/timing_mem_prv_write.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avashist003/SystemVerilog_Design_Verification/afbb6d6e715bca009c625faf1e8f90c510abe946/Sync Memory/timing_mem_prv_write.png --------------------------------------------------------------------------------