Repository: alexforencich/verilog-lfsr Branch: master Commit: c1f86d036745 Files: 54 Total size: 191.6 KB Directory structure: gitextract_d0iwnulu/ ├── .github/ │ └── workflows/ │ └── regression-tests.yml ├── .gitignore ├── AUTHORS ├── COPYING ├── README.md ├── rtl/ │ ├── lfsr.v │ ├── lfsr_crc.v │ ├── lfsr_descramble.v │ ├── lfsr_prbs_check.v │ ├── lfsr_prbs_gen.v │ └── lfsr_scramble.v ├── tb/ │ ├── lfsr/ │ │ ├── Makefile │ │ └── test_lfsr.py │ ├── lfsr_crc/ │ │ ├── Makefile │ │ └── test_lfsr_crc.py │ ├── lfsr_descramble/ │ │ ├── Makefile │ │ └── test_lfsr_descramble.py │ ├── lfsr_prbs_check/ │ │ ├── Makefile │ │ └── test_lfsr_prbs_check.py │ ├── lfsr_prbs_gen/ │ │ ├── Makefile │ │ └── test_lfsr_prbs_gen.py │ ├── lfsr_scramble/ │ │ ├── Makefile │ │ └── test_lfsr_scramble.py │ ├── test_lfsr_crc32.py │ ├── test_lfsr_crc32.v │ ├── test_lfsr_crc_crc32.py │ ├── test_lfsr_crc_crc32.v │ ├── test_lfsr_crc_crc32_64.py │ ├── test_lfsr_crc_crc32_64.v │ ├── test_lfsr_descramble.py │ ├── test_lfsr_descramble.v │ ├── test_lfsr_descramble_64.py │ ├── test_lfsr_descramble_64.v │ ├── test_lfsr_prbs31.py │ ├── test_lfsr_prbs31.v │ ├── test_lfsr_prbs9.py │ ├── test_lfsr_prbs9.v │ ├── test_lfsr_prbs_check_prbs31.py │ ├── test_lfsr_prbs_check_prbs31.v │ ├── test_lfsr_prbs_check_prbs31_64.py │ ├── test_lfsr_prbs_check_prbs31_64.v │ ├── test_lfsr_prbs_check_prbs9.py │ ├── test_lfsr_prbs_check_prbs9.v │ ├── test_lfsr_prbs_gen_prbs31.py │ ├── test_lfsr_prbs_gen_prbs31.v │ ├── test_lfsr_prbs_gen_prbs31_64.py │ ├── test_lfsr_prbs_gen_prbs31_64.v │ ├── test_lfsr_prbs_gen_prbs9.py │ ├── test_lfsr_prbs_gen_prbs9.v │ ├── test_lfsr_scramble.py │ ├── test_lfsr_scramble.v │ ├── test_lfsr_scramble_64.py │ └── test_lfsr_scramble_64.v └── tox.ini ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/regression-tests.yml ================================================ name: Regression Tests on: [push, pull_request] jobs: build: name: Python ${{ matrix.python-version }} (${{ matrix.group }}/10) runs-on: ubuntu-20.04 strategy: matrix: python-version: [3.9] group: [1, 2, 3, 4, 5] steps: - uses: actions/checkout@v1 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install Icarus Verilog run: | sudo apt install -y --no-install-recommends iverilog - name: Install Python dependencies run: | python -m pip install --upgrade pip pip install tox tox-gh-actions - name: Test with tox run: tox -- --splits 5 --group ${{ matrix.group }} --splitting-algorithm least_duration ================================================ FILE: .gitignore ================================================ *~ *.lxt *.pyc *.vvp *.kate-swp ================================================ FILE: AUTHORS ================================================ Alex Forencich ================================================ FILE: COPYING ================================================ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Verilog LFSR Readme [![Build Status](https://github.com/alexforencich/verilog-lfsr/workflows/Regression%20Tests/badge.svg?branch=master)](https://github.com/alexforencich/verilog-lfsr/actions/) For more information and updates: http://alexforencich.com/wiki/en/verilog/lfsr/start GitHub repository: https://github.com/alexforencich/verilog-lfsr ## Deprecation Notice This repository is superseded by https://github.com/fpganinja/taxi. All new features and bug fixes will be applied there, and commercial support is also available. As a result, this repo is deprecated and will not receive any future maintenance or support. ## Introduction Fully parametrizable combinatorial parallel LFSR/CRC module. Implements an unrolled LFSR next state computation. Includes full cocotb testbenches. ## Documentation ### lfsr module Fully parametrizable combinatorial parallel LFSR/CRC module. Implements an unrolled LFSR next state computation. ### lfsr_crc module Wrapper for lfsr module for standard CRC computation. ### lfsr_descramble module Wrapper for lfsr module for self-synchronizing descrambler. ### lfsr_prbs_check module Wrapper for lfsr module for standard PRBS check. ### lfsr_prbs_gen module Wrapper for lfsr module for standard PRBS computation. ### lfsr_scramble module Wrapper for lfsr module for self-synchronizing scrambler. ### Source Files lfsr.v : Parametrizable combinatorial LFSR/CRC module lfsr_crc.v : Parametrizable CRC computation wrapper lfsr_descramble.v : Parametrizable LFSR self-synchronizing descrambler lfsr_prbs_check.v : Parametrizable PRBS checker wrapper lfsr_prbs_gen.v : Parametrizable PRBS generator wrapper lfsr_scramble.v : Parametrizable LFSR self-synchronizing scrambler ## Testing Running the included testbenches requires [cocotb](https://github.com/cocotb/cocotb) and [Icarus Verilog](http://iverilog.icarus.com/). The testbenches can be run with pytest directly (requires [cocotb-test](https://github.com/themperek/cocotb-test)), pytest via tox, or via cocotb makefiles. ================================================ FILE: rtl/lfsr.v ================================================ /* Copyright (c) 2016-2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `timescale 1ns / 1ps `default_nettype none /* * Parametrizable combinatorial parallel LFSR/CRC */ module lfsr # ( // width of LFSR parameter LFSR_WIDTH = 31, // LFSR polynomial parameter LFSR_POLY = 31'h10000001, // LFSR configuration: "GALOIS", "FIBONACCI" parameter LFSR_CONFIG = "FIBONACCI", // LFSR feed forward enable parameter LFSR_FEED_FORWARD = 0, // bit-reverse input and output parameter REVERSE = 0, // width of data input parameter DATA_WIDTH = 8, // implementation style: "AUTO", "LOOP", "REDUCTION" parameter STYLE = "AUTO" ) ( input wire [DATA_WIDTH-1:0] data_in, input wire [LFSR_WIDTH-1:0] state_in, output wire [DATA_WIDTH-1:0] data_out, output wire [LFSR_WIDTH-1:0] state_out ); /* Fully parametrizable combinatorial parallel LFSR/CRC module. Implements an unrolled LFSR next state computation, shifting DATA_WIDTH bits per pass through the module. Input data is XORed with LFSR feedback path, tie data_in to zero if this is not required. Works in two parts: statically computes a set of bit masks, then uses these bit masks to select bits for XORing to compute the next state. Ports: data_in Data bits to be shifted through the LFSR (DATA_WIDTH bits) state_in LFSR/CRC current state input (LFSR_WIDTH bits) data_out Data bits shifted out of LFSR (DATA_WIDTH bits) state_out LFSR/CRC next state output (LFSR_WIDTH bits) Parameters: LFSR_WIDTH Specify width of LFSR/CRC register LFSR_POLY Specify the LFSR/CRC polynomial in hex format. For example, the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 would be represented as 32'h04c11db7 Note that the largest term (x^32) is suppressed. This term is generated automatically based on LFSR_WIDTH. LFSR_CONFIG Specify the LFSR configuration, either Fibonacci or Galois. Fibonacci is generally used for linear-feedback shift registers (LFSR) for pseudorandom binary sequence (PRBS) generators, scramblers, and descrambers, while Galois is generally used for cyclic redundancy check generators and checkers. Fibonacci style (example for 64b66b scrambler, 0x8000000001) DIN (LSB first) | V (+)<---------------------------(+)<-----------------------------. | ^ | | .----. .----. .----. | .----. .----. .----. | +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--' | '----' '----' '----' '----' '----' '----' V DOUT Galois style (example for CRC16, 0x8005) ,-------------------+-------------------------+----------(+)<-- DIN (MSB first) | | | ^ | .----. .----. V .----. .----. V .----. | `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |--+---> DOUT '----' '----' '----' '----' '----' LFSR_FEED_FORWARD Generate feed forward instead of feed back LFSR. Enable this for PRBS checking and self- synchronous descrambling. Fibonacci feed-forward style (example for 64b66b descrambler, 0x8000000001) DIN (LSB first) | | .----. .----. .----. .----. .----. .----. +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--. | '----' '----' '----' | '----' '----' '----' | | V | (+)<---------------------------(+)------------------------------' | V DOUT Galois feed-forward style ,-------------------+-------------------------+------------+--- DIN (MSB first) | | | | | .----. .----. V .----. .----. V .----. V `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |->(+)-> DOUT '----' '----' '----' '----' '----' REVERSE Bit-reverse LFSR input and output. Shifts MSB first by default, set REVERSE for LSB first. DATA_WIDTH Specify width of input and output data bus. The module will perform one shift per input data bit, so if the input data bus is not required tie data_in to zero and set DATA_WIDTH to the required number of shifts per clock cycle. STYLE Specify implementation style. Can be "AUTO", "LOOP", or "REDUCTION". When "AUTO" is selected, implemenation will be "LOOP" or "REDUCTION" based on synthesis translate directives. "REDUCTION" and "LOOP" are functionally identical, however they simulate and synthesize differently. "REDUCTION" is implemented with a loop over a Verilog reduction operator. "LOOP" is implemented as a doubly-nested loop with no reduction operator. "REDUCTION" is very fast for simulation in iverilog and synthesizes well in Quartus but synthesizes poorly in ISE, likely due to large inferred XOR gates causing problems with the optimizer. "LOOP" synthesizes will in both ISE and Quartus. "AUTO" will default to "REDUCTION" when simulating and "LOOP" for synthesizers that obey synthesis translate directives. Settings for common LFSR/CRC implementations: Name Configuration Length Polynomial Initial value Notes CRC16-IBM Galois, bit-reverse 16 16'h8005 16'hffff CRC16-CCITT Galois 16 16'h1021 16'h1d0f CRC32 Galois, bit-reverse 32 32'h04c11db7 32'hffffffff Ethernet FCS; invert final output CRC32C Galois, bit-reverse 32 32'h1edc6f41 32'hffffffff iSCSI, Intel CRC32 instruction; invert final output PRBS6 Fibonacci 6 6'h21 any PRBS7 Fibonacci 7 7'h41 any PRBS9 Fibonacci 9 9'h021 any ITU V.52 PRBS10 Fibonacci 10 10'h081 any ITU PRBS11 Fibonacci 11 11'h201 any ITU O.152 PRBS15 Fibonacci, inverted 15 15'h4001 any ITU O.152 PRBS17 Fibonacci 17 17'h04001 any PRBS20 Fibonacci 20 20'h00009 any ITU V.57 PRBS23 Fibonacci, inverted 23 23'h040001 any ITU O.151 PRBS29 Fibonacci, inverted 29 29'h08000001 any PRBS31 Fibonacci, inverted 31 31'h10000001 any 64b66b Fibonacci, bit-reverse 58 58'h8000000001 any 10G Ethernet 128b130b Galois, bit-reverse 23 23'h210125 any PCIe gen 3 */ function [LFSR_WIDTH+DATA_WIDTH-1:0] lfsr_mask(input [31:0] index); reg [LFSR_WIDTH-1:0] lfsr_mask_state[LFSR_WIDTH-1:0]; reg [DATA_WIDTH-1:0] lfsr_mask_data[LFSR_WIDTH-1:0]; reg [LFSR_WIDTH-1:0] output_mask_state[DATA_WIDTH-1:0]; reg [DATA_WIDTH-1:0] output_mask_data[DATA_WIDTH-1:0]; reg [LFSR_WIDTH-1:0] state_val; reg [DATA_WIDTH-1:0] data_val; reg [DATA_WIDTH-1:0] data_mask; integer i, j; begin // init bit masks for (i = 0; i < LFSR_WIDTH; i = i + 1) begin lfsr_mask_state[i] = 0; lfsr_mask_state[i][i] = 1'b1; lfsr_mask_data[i] = 0; end for (i = 0; i < DATA_WIDTH; i = i + 1) begin output_mask_state[i] = 0; if (i < LFSR_WIDTH) begin output_mask_state[i][i] = 1'b1; end output_mask_data[i] = 0; end // simulate shift register if (LFSR_CONFIG == "FIBONACCI") begin // Fibonacci configuration for (data_mask = {1'b1, {DATA_WIDTH-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin // determine shift in value // current value in last FF, XOR with input data bit (MSB first) state_val = lfsr_mask_state[LFSR_WIDTH-1]; data_val = lfsr_mask_data[LFSR_WIDTH-1]; data_val = data_val ^ data_mask; // add XOR inputs from correct indicies for (j = 1; j < LFSR_WIDTH; j = j + 1) begin if ((LFSR_POLY >> j) & 1) begin state_val = lfsr_mask_state[j-1] ^ state_val; data_val = lfsr_mask_data[j-1] ^ data_val; end end // shift for (j = LFSR_WIDTH-1; j > 0; j = j - 1) begin lfsr_mask_state[j] = lfsr_mask_state[j-1]; lfsr_mask_data[j] = lfsr_mask_data[j-1]; end for (j = DATA_WIDTH-1; j > 0; j = j - 1) begin output_mask_state[j] = output_mask_state[j-1]; output_mask_data[j] = output_mask_data[j-1]; end output_mask_state[0] = state_val; output_mask_data[0] = data_val; if (LFSR_FEED_FORWARD) begin // only shift in new input data state_val = {LFSR_WIDTH{1'b0}}; data_val = data_mask; end lfsr_mask_state[0] = state_val; lfsr_mask_data[0] = data_val; end end else if (LFSR_CONFIG == "GALOIS") begin // Galois configuration for (data_mask = {1'b1, {DATA_WIDTH-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin // determine shift in value // current value in last FF, XOR with input data bit (MSB first) state_val = lfsr_mask_state[LFSR_WIDTH-1]; data_val = lfsr_mask_data[LFSR_WIDTH-1]; data_val = data_val ^ data_mask; // shift for (j = LFSR_WIDTH-1; j > 0; j = j - 1) begin lfsr_mask_state[j] = lfsr_mask_state[j-1]; lfsr_mask_data[j] = lfsr_mask_data[j-1]; end for (j = DATA_WIDTH-1; j > 0; j = j - 1) begin output_mask_state[j] = output_mask_state[j-1]; output_mask_data[j] = output_mask_data[j-1]; end output_mask_state[0] = state_val; output_mask_data[0] = data_val; if (LFSR_FEED_FORWARD) begin // only shift in new input data state_val = {LFSR_WIDTH{1'b0}}; data_val = data_mask; end lfsr_mask_state[0] = state_val; lfsr_mask_data[0] = data_val; // add XOR inputs at correct indicies for (j = 1; j < LFSR_WIDTH; j = j + 1) begin if ((LFSR_POLY >> j) & 1) begin lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val; lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val; end end end end else begin $error("Error: unknown configuration setting!"); $finish; end // reverse bits if selected if (REVERSE) begin if (index < LFSR_WIDTH) begin state_val = 0; for (i = 0; i < LFSR_WIDTH; i = i + 1) begin state_val[i] = lfsr_mask_state[LFSR_WIDTH-index-1][LFSR_WIDTH-i-1]; end data_val = 0; for (i = 0; i < DATA_WIDTH; i = i + 1) begin data_val[i] = lfsr_mask_data[LFSR_WIDTH-index-1][DATA_WIDTH-i-1]; end end else begin state_val = 0; for (i = 0; i < LFSR_WIDTH; i = i + 1) begin state_val[i] = output_mask_state[DATA_WIDTH-(index-LFSR_WIDTH)-1][LFSR_WIDTH-i-1]; end data_val = 0; for (i = 0; i < DATA_WIDTH; i = i + 1) begin data_val[i] = output_mask_data[DATA_WIDTH-(index-LFSR_WIDTH)-1][DATA_WIDTH-i-1]; end end end else begin if (index < LFSR_WIDTH) begin state_val = lfsr_mask_state[index]; data_val = lfsr_mask_data[index]; end else begin state_val = output_mask_state[index-LFSR_WIDTH]; data_val = output_mask_data[index-LFSR_WIDTH]; end end lfsr_mask = {data_val, state_val}; end endfunction // synthesis translate_off `define SIMULATION // synthesis translate_on `ifdef SIMULATION // "AUTO" style is "REDUCTION" for faster simulation parameter STYLE_INT = (STYLE == "AUTO") ? "REDUCTION" : STYLE; `else // "AUTO" style is "LOOP" for better synthesis result parameter STYLE_INT = (STYLE == "AUTO") ? "LOOP" : STYLE; `endif genvar n; generate if (STYLE_INT == "REDUCTION") begin // use Verilog reduction operator // fast in iverilog // significantly larger than generated code with ISE (inferred wide XORs may be tripping up optimizer) // slightly smaller than generated code with Quartus // --> better for simulation for (n = 0; n < LFSR_WIDTH; n = n + 1) begin : lfsr_state wire [LFSR_WIDTH+DATA_WIDTH-1:0] mask = lfsr_mask(n); assign state_out[n] = ^({data_in, state_in} & mask); end for (n = 0; n < DATA_WIDTH; n = n + 1) begin : lfsr_data wire [LFSR_WIDTH+DATA_WIDTH-1:0] mask = lfsr_mask(n+LFSR_WIDTH); assign data_out[n] = ^({data_in, state_in} & mask); end end else if (STYLE_INT == "LOOP") begin // use nested loops // very slow in iverilog // slightly smaller than generated code with ISE // same size as generated code with Quartus // --> better for synthesis for (n = 0; n < LFSR_WIDTH; n = n + 1) begin : lfsr_state wire [LFSR_WIDTH+DATA_WIDTH-1:0] mask = lfsr_mask(n); reg state_reg; assign state_out[n] = state_reg; integer i; always @* begin state_reg = 1'b0; for (i = 0; i < LFSR_WIDTH; i = i + 1) begin if (mask[i]) begin state_reg = state_reg ^ state_in[i]; end end for (i = 0; i < DATA_WIDTH; i = i + 1) begin if (mask[i+LFSR_WIDTH]) begin state_reg = state_reg ^ data_in[i]; end end end end for (n = 0; n < DATA_WIDTH; n = n + 1) begin : lfsr_data wire [LFSR_WIDTH+DATA_WIDTH-1:0] mask = lfsr_mask(n+LFSR_WIDTH); reg data_reg; assign data_out[n] = data_reg; integer i; always @* begin data_reg = 1'b0; for (i = 0; i < LFSR_WIDTH; i = i + 1) begin if (mask[i]) begin data_reg = data_reg ^ state_in[i]; end end for (i = 0; i < DATA_WIDTH; i = i + 1) begin if (mask[i+LFSR_WIDTH]) begin data_reg = data_reg ^ data_in[i]; end end end end end else begin initial begin $error("Error: unknown style setting!"); $finish; end end endgenerate endmodule `resetall ================================================ FILE: rtl/lfsr_crc.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `timescale 1ns / 1ps `default_nettype none /* * LFSR CRC generator */ module lfsr_crc # ( // width of LFSR parameter LFSR_WIDTH = 32, // LFSR polynomial parameter LFSR_POLY = 32'h04c11db7, // Initial state parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}, // LFSR configuration: "GALOIS", "FIBONACCI" parameter LFSR_CONFIG = "GALOIS", // bit-reverse input and output parameter REVERSE = 1, // invert output parameter INVERT = 1, // width of data input and output parameter DATA_WIDTH = 8, // implementation style: "AUTO", "LOOP", "REDUCTION" parameter STYLE = "AUTO" ) ( input wire clk, input wire rst, input wire [DATA_WIDTH-1:0] data_in, input wire data_in_valid, output wire [LFSR_WIDTH-1:0] crc_out ); /* Fully parametrizable combinatorial parallel LFSR CRC module. Implements an unrolled LFSR next state computation. Ports: clk Clock input rst Reset module, set state to LFSR_INIT data_in CRC data input data_in_valid Shift input data through CRC when asserted data_out LFSR output (OUTPUT_WIDTH bits) Parameters: LFSR_WIDTH Specify width of LFSR/CRC register LFSR_POLY Specify the LFSR/CRC polynomial in hex format. For example, the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 would be represented as 32'h04c11db7 Note that the largest term (x^32) is suppressed. This term is generated automatically based on LFSR_WIDTH. LFSR_INIT Initial state of LFSR. Defaults to all 1s. LFSR_CONFIG Specify the LFSR configuration, either Fibonacci or Galois. Fibonacci is generally used for linear-feedback shift registers (LFSR) for pseudorandom binary sequence (PRBS) generators, scramblers, and descrambers, while Galois is generally used for cyclic redundancy check generators and checkers. Fibonacci style (example for 64b66b scrambler, 0x8000000001) DIN (LSB first) | V (+)<---------------------------(+)<-----------------------------. | ^ | | .----. .----. .----. | .----. .----. .----. | +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--' | '----' '----' '----' '----' '----' '----' V DOUT Galois style (example for CRC16, 0x8005) ,-------------------+-------------------------+----------(+)<-- DIN (MSB first) | | | ^ | .----. .----. V .----. .----. V .----. | `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |--+---> DOUT '----' '----' '----' '----' '----' REVERSE Bit-reverse LFSR input and output. Shifts MSB first by default, set REVERSE for LSB first. INVERT Bitwise invert CRC output. DATA_WIDTH Specify width of input data bus. The module will perform one shift per input data bit, so if the input data bus is not required tie data_in to zero and set DATA_WIDTH to the required number of shifts per clock cycle. STYLE Specify implementation style. Can be "AUTO", "LOOP", or "REDUCTION". When "AUTO" is selected, implemenation will be "LOOP" or "REDUCTION" based on synthesis translate directives. "REDUCTION" and "LOOP" are functionally identical, however they simulate and synthesize differently. "REDUCTION" is implemented with a loop over a Verilog reduction operator. "LOOP" is implemented as a doubly-nested loop with no reduction operator. "REDUCTION" is very fast for simulation in iverilog and synthesizes well in Quartus but synthesizes poorly in ISE, likely due to large inferred XOR gates causing problems with the optimizer. "LOOP" synthesizes will in both ISE and Quartus. "AUTO" will default to "REDUCTION" when simulating and "LOOP" for synthesizers that obey synthesis translate directives. Settings for common LFSR/CRC implementations: Name Configuration Length Polynomial Initial value Notes CRC16-IBM Galois, bit-reverse 16 16'h8005 16'hffff CRC16-CCITT Galois 16 16'h1021 16'h1d0f CRC32 Galois, bit-reverse 32 32'h04c11db7 32'hffffffff Ethernet FCS; invert final output CRC32C Galois, bit-reverse 32 32'h1edc6f41 32'hffffffff iSCSI, Intel CRC32 instruction; invert final output */ reg [LFSR_WIDTH-1:0] state_reg = LFSR_INIT; reg [LFSR_WIDTH-1:0] output_reg = 0; wire [LFSR_WIDTH-1:0] lfsr_state; assign crc_out = output_reg; lfsr #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_CONFIG(LFSR_CONFIG), .LFSR_FEED_FORWARD(0), .REVERSE(REVERSE), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) lfsr_inst ( .data_in(data_in), .state_in(state_reg), .data_out(), .state_out(lfsr_state) ); always @(posedge clk) begin if (rst) begin state_reg <= LFSR_INIT; output_reg <= 0; end else begin if (data_in_valid) begin state_reg <= lfsr_state; if (INVERT) begin output_reg <= ~lfsr_state; end else begin output_reg <= lfsr_state; end end end end endmodule `resetall ================================================ FILE: rtl/lfsr_descramble.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `timescale 1ns / 1ps `default_nettype none /* * LFSR descrambler */ module lfsr_descramble # ( // width of LFSR parameter LFSR_WIDTH = 58, // LFSR polynomial parameter LFSR_POLY = 58'h8000000001, // Initial state parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}, // LFSR configuration: "GALOIS", "FIBONACCI" parameter LFSR_CONFIG = "FIBONACCI", // bit-reverse input and output parameter REVERSE = 1, // width of data bus parameter DATA_WIDTH = 64, // implementation style: "AUTO", "LOOP", "REDUCTION" parameter STYLE = "AUTO" ) ( input wire clk, input wire rst, input wire [DATA_WIDTH-1:0] data_in, input wire data_in_valid, output wire [DATA_WIDTH-1:0] data_out ); /* Fully parametrizable combinatorial parallel LFSR CRC module. Implements an unrolled LFSR next state computation. Ports: clk Clock input rst Reset module, set state to LFSR_INIT data_in Scrambled data input (DATA_WIDTH bits) data_in_valid Shift input data through CRC when asserted data_out Descrambled data output (DATA_WIDTH bits) Parameters: LFSR_WIDTH Specify width of LFSR/CRC register LFSR_POLY Specify the LFSR/CRC polynomial in hex format. For example, the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 would be represented as 32'h04c11db7 Note that the largest term (x^32) is suppressed. This term is generated automatically based on LFSR_WIDTH. LFSR_INIT Initial state of LFSR. Defaults to all 1s. LFSR_CONFIG Specify the LFSR configuration, either Fibonacci or Galois. Fibonacci is generally used for linear-feedback shift registers (LFSR) for pseudorandom binary sequence (PRBS) generators, scramblers, and descrambers, while Galois is generally used for cyclic redundancy check generators and checkers. Fibonacci style (example for 64b66b scrambler, 0x8000000001) DIN (LSB first) | V (+)<---------------------------(+)<-----------------------------. | ^ | | .----. .----. .----. | .----. .----. .----. | +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--' | '----' '----' '----' '----' '----' '----' V DOUT Galois style (example for CRC16, 0x8005) ,-------------------+-------------------------+----------(+)<-- DIN (MSB first) | | | ^ | .----. .----. V .----. .----. V .----. | `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |--+---> DOUT '----' '----' '----' '----' '----' REVERSE Bit-reverse LFSR input and output. DATA_WIDTH Specify width of the data bus. The module will perform one shift per input data bit. STYLE Specify implementation style. Can be "AUTO", "LOOP", or "REDUCTION". When "AUTO" is selected, implemenation will be "LOOP" or "REDUCTION" based on synthesis translate directives. "REDUCTION" and "LOOP" are functionally identical, however they simulate and synthesize differently. "REDUCTION" is implemented with a loop over a Verilog reduction operator. "LOOP" is implemented as a doubly-nested loop with no reduction operator. "REDUCTION" is very fast for simulation in iverilog and synthesizes well in Quartus but synthesizes poorly in ISE, likely due to large inferred XOR gates causing problems with the optimizer. "LOOP" synthesizes will in both ISE and Quartus. "AUTO" will default to "REDUCTION" when simulating and "LOOP" for synthesizers that obey synthesis translate directives. Settings for common LFSR/CRC implementations: Name Configuration Length Polynomial Initial value Notes CRC32 Galois, bit-reverse 32 32'h04c11db7 32'hffffffff Ethernet FCS; invert final output PRBS6 Fibonacci 6 6'h21 any PRBS7 Fibonacci 7 7'h41 any PRBS9 Fibonacci 9 9'h021 any ITU V.52 PRBS10 Fibonacci 10 10'h081 any ITU PRBS11 Fibonacci 11 11'h201 any ITU O.152 PRBS15 Fibonacci, inverted 15 15'h4001 any ITU O.152 PRBS17 Fibonacci 17 17'h04001 any PRBS20 Fibonacci 20 20'h00009 any ITU V.57 PRBS23 Fibonacci, inverted 23 23'h040001 any ITU O.151 PRBS29 Fibonacci, inverted 29 29'h08000001 any PRBS31 Fibonacci, inverted 31 31'h10000001 any 64b66b Fibonacci, bit-reverse 58 58'h8000000001 any 10G Ethernet 128b130b Galois, bit-reverse 23 23'h210125 any PCIe gen 3 */ reg [LFSR_WIDTH-1:0] state_reg = LFSR_INIT; reg [DATA_WIDTH-1:0] output_reg = 0; wire [DATA_WIDTH-1:0] lfsr_data; wire [LFSR_WIDTH-1:0] lfsr_state; assign data_out = output_reg; lfsr #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_CONFIG(LFSR_CONFIG), .LFSR_FEED_FORWARD(1), .REVERSE(REVERSE), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) lfsr_inst ( .data_in(data_in), .state_in(state_reg), .data_out(lfsr_data), .state_out(lfsr_state) ); always @(posedge clk) begin if (rst) begin state_reg <= LFSR_INIT; output_reg <= 0; end else begin if (data_in_valid) begin state_reg <= lfsr_state; output_reg <= lfsr_data; end end end endmodule `resetall ================================================ FILE: rtl/lfsr_prbs_check.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `timescale 1ns / 1ps `default_nettype none /* * LFSR PRBS checker */ module lfsr_prbs_check # ( // width of LFSR parameter LFSR_WIDTH = 31, // LFSR polynomial parameter LFSR_POLY = 31'h10000001, // Initial state parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}, // LFSR configuration: "GALOIS", "FIBONACCI" parameter LFSR_CONFIG = "FIBONACCI", // bit-reverse input and output parameter REVERSE = 0, // invert input parameter INVERT = 1, // width of data input and output parameter DATA_WIDTH = 8, // implementation style: "AUTO", "LOOP", "REDUCTION" parameter STYLE = "AUTO" ) ( input wire clk, input wire rst, input wire [DATA_WIDTH-1:0] data_in, input wire data_in_valid, output wire [DATA_WIDTH-1:0] data_out ); /* Fully parametrizable combinatorial parallel LFSR PRBS checker. Implements an unrolled LFSR PRBS checker. Ports: clk Clock input rst Reset input, set state to LFSR_INIT data_in PRBS data input (DATA_WIDTH bits) data_in_valid Shift input data through LFSR when asserted data_out Error output (DATA_WIDTH bits) Parameters: LFSR_WIDTH Specify width of LFSR/CRC register LFSR_POLY Specify the LFSR/CRC polynomial in hex format. For example, the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 would be represented as 32'h04c11db7 Note that the largest term (x^32) is suppressed. This term is generated automatically based on LFSR_WIDTH. LFSR_INIT Initial state of LFSR. Defaults to all 1s. LFSR_CONFIG Specify the LFSR configuration, either Fibonacci or Galois. Fibonacci is generally used for linear-feedback shift registers (LFSR) for pseudorandom binary sequence (PRBS) generators, scramblers, and descrambers, while Galois is generally used for cyclic redundancy check generators and checkers. Fibonacci style (example for 64b66b scrambler, 0x8000000001) DIN (LSB first) | V (+)<---------------------------(+)<-----------------------------. | ^ | | .----. .----. .----. | .----. .----. .----. | +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--' | '----' '----' '----' '----' '----' '----' V DOUT Galois style (example for CRC16, 0x8005) ,-------------------+-------------------------+----------(+)<-- DIN (MSB first) | | | ^ | .----. .----. V .----. .----. V .----. | `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |--+---> DOUT '----' '----' '----' '----' '----' REVERSE Bit-reverse LFSR output. Shifts MSB first by default, set REVERSE for LSB first. INVERT Bitwise invert PRBS input. DATA_WIDTH Specify width of output data bus. STYLE Specify implementation style. Can be "AUTO", "LOOP", or "REDUCTION". When "AUTO" is selected, implemenation will be "LOOP" or "REDUCTION" based on synthesis translate directives. "REDUCTION" and "LOOP" are functionally identical, however they simulate and synthesize differently. "REDUCTION" is implemented with a loop over a Verilog reduction operator. "LOOP" is implemented as a doubly-nested loop with no reduction operator. "REDUCTION" is very fast for simulation in iverilog and synthesizes well in Quartus but synthesizes poorly in ISE, likely due to large inferred XOR gates causing problems with the optimizer. "LOOP" synthesizes will in both ISE and Quartus. "AUTO" will default to "REDUCTION" when simulating and "LOOP" for synthesizers that obey synthesis translate directives. Settings for common LFSR/CRC implementations: Name Configuration Length Polynomial Initial value Notes CRC32 Galois, bit-reverse 32 32'h04c11db7 32'hffffffff Ethernet FCS; invert final output PRBS6 Fibonacci 6 6'h21 any PRBS7 Fibonacci 7 7'h41 any PRBS9 Fibonacci 9 9'h021 any ITU V.52 PRBS10 Fibonacci 10 10'h081 any ITU PRBS11 Fibonacci 11 11'h201 any ITU O.152 PRBS15 Fibonacci, inverted 15 15'h4001 any ITU O.152 PRBS17 Fibonacci 17 17'h04001 any PRBS20 Fibonacci 20 20'h00009 any ITU V.57 PRBS23 Fibonacci, inverted 23 23'h040001 any ITU O.151 PRBS29 Fibonacci, inverted 29 29'h08000001 any PRBS31 Fibonacci, inverted 31 31'h10000001 any 64b66b Fibonacci, bit-reverse 58 58'h8000000001 any 10G Ethernet 128b130b Galois, bit-reverse 23 23'h210125 any PCIe gen 3 */ reg [LFSR_WIDTH-1:0] state_reg = LFSR_INIT; reg [DATA_WIDTH-1:0] output_reg = 0; wire [DATA_WIDTH-1:0] lfsr_data; wire [LFSR_WIDTH-1:0] lfsr_state; assign data_out = output_reg; lfsr #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_CONFIG(LFSR_CONFIG), .LFSR_FEED_FORWARD(1), .REVERSE(REVERSE), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) lfsr_inst ( .data_in(INVERT ? ~data_in : data_in), .state_in(state_reg), .data_out(lfsr_data), .state_out(lfsr_state) ); always @(posedge clk) begin if (rst) begin state_reg <= LFSR_INIT; output_reg <= 0; end else begin if (data_in_valid) begin state_reg <= lfsr_state; output_reg <= lfsr_data; end end end endmodule `resetall ================================================ FILE: rtl/lfsr_prbs_gen.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `timescale 1ns / 1ps `default_nettype none /* * LFSR PRBS generator */ module lfsr_prbs_gen # ( // width of LFSR parameter LFSR_WIDTH = 31, // LFSR polynomial parameter LFSR_POLY = 31'h10000001, // Initial state parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}, // LFSR configuration: "GALOIS", "FIBONACCI" parameter LFSR_CONFIG = "FIBONACCI", // bit-reverse input and output parameter REVERSE = 0, // invert output parameter INVERT = 1, // width of data output parameter DATA_WIDTH = 8, // implementation style: "AUTO", "LOOP", "REDUCTION" parameter STYLE = "AUTO" ) ( input wire clk, input wire rst, input wire enable, output wire [DATA_WIDTH-1:0] data_out ); /* Fully parametrizable combinatorial parallel LFSR PRBS module. Implements an unrolled LFSR next state computation. Ports: clk Clock input rst Reset input, set state to LFSR_INIT enable Generate new output data data_out LFSR output (DATA_WIDTH bits) Parameters: LFSR_WIDTH Specify width of LFSR/CRC register LFSR_POLY Specify the LFSR/CRC polynomial in hex format. For example, the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 would be represented as 32'h04c11db7 Note that the largest term (x^32) is suppressed. This term is generated automatically based on LFSR_WIDTH. LFSR_INIT Initial state of LFSR. Defaults to all 1s. LFSR_CONFIG Specify the LFSR configuration, either Fibonacci or Galois. Fibonacci is generally used for linear-feedback shift registers (LFSR) for pseudorandom binary sequence (PRBS) generators, scramblers, and descrambers, while Galois is generally used for cyclic redundancy check generators and checkers. Fibonacci style (example for 64b66b scrambler, 0x8000000001) DIN (LSB first) | V (+)<---------------------------(+)<-----------------------------. | ^ | | .----. .----. .----. | .----. .----. .----. | +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--' | '----' '----' '----' '----' '----' '----' V DOUT Galois style (example for CRC16, 0x8005) ,-------------------+-------------------------+----------(+)<-- DIN (MSB first) | | | ^ | .----. .----. V .----. .----. V .----. | `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |--+---> DOUT '----' '----' '----' '----' '----' REVERSE Bit-reverse LFSR output. Shifts MSB first by default, set REVERSE for LSB first. INVERT Bitwise invert PRBS output. DATA_WIDTH Specify width of output data bus. STYLE Specify implementation style. Can be "AUTO", "LOOP", or "REDUCTION". When "AUTO" is selected, implemenation will be "LOOP" or "REDUCTION" based on synthesis translate directives. "REDUCTION" and "LOOP" are functionally identical, however they simulate and synthesize differently. "REDUCTION" is implemented with a loop over a Verilog reduction operator. "LOOP" is implemented as a doubly-nested loop with no reduction operator. "REDUCTION" is very fast for simulation in iverilog and synthesizes well in Quartus but synthesizes poorly in ISE, likely due to large inferred XOR gates causing problems with the optimizer. "LOOP" synthesizes will in both ISE and Quartus. "AUTO" will default to "REDUCTION" when simulating and "LOOP" for synthesizers that obey synthesis translate directives. Settings for common LFSR/CRC implementations: Name Configuration Length Polynomial Initial value Notes CRC32 Galois, bit-reverse 32 32'h04c11db7 32'hffffffff Ethernet FCS; invert final output PRBS6 Fibonacci 6 6'h21 any PRBS7 Fibonacci 7 7'h41 any PRBS9 Fibonacci 9 9'h021 any ITU V.52 PRBS10 Fibonacci 10 10'h081 any ITU PRBS11 Fibonacci 11 11'h201 any ITU O.152 PRBS15 Fibonacci, inverted 15 15'h4001 any ITU O.152 PRBS17 Fibonacci 17 17'h04001 any PRBS20 Fibonacci 20 20'h00009 any ITU V.57 PRBS23 Fibonacci, inverted 23 23'h040001 any ITU O.151 PRBS29 Fibonacci, inverted 29 29'h08000001 any PRBS31 Fibonacci, inverted 31 31'h10000001 any 64b66b Fibonacci, bit-reverse 58 58'h8000000001 any 10G Ethernet 128b130b Galois, bit-reverse 23 23'h210125 any PCIe gen 3 */ reg [LFSR_WIDTH-1:0] state_reg = LFSR_INIT; reg [DATA_WIDTH-1:0] output_reg = 0; wire [DATA_WIDTH-1:0] lfsr_data; wire [LFSR_WIDTH-1:0] lfsr_state; assign data_out = output_reg; lfsr #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_CONFIG(LFSR_CONFIG), .LFSR_FEED_FORWARD(0), .REVERSE(REVERSE), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) lfsr_inst ( .data_in({DATA_WIDTH{1'b0}}), .state_in(state_reg), .data_out(lfsr_data), .state_out(lfsr_state) ); always @* begin if (INVERT) begin output_reg <= ~lfsr_data; end else begin output_reg <= lfsr_data; end end always @(posedge clk) begin if (rst) begin state_reg <= LFSR_INIT; end else begin if (enable) begin state_reg <= lfsr_state; end end end endmodule `resetall ================================================ FILE: rtl/lfsr_scramble.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `timescale 1ns / 1ps `default_nettype none /* * LFSR scrambler */ module lfsr_scramble # ( // width of LFSR parameter LFSR_WIDTH = 58, // LFSR polynomial parameter LFSR_POLY = 58'h8000000001, // Initial state parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}, // LFSR configuration: "GALOIS", "FIBONACCI" parameter LFSR_CONFIG = "FIBONACCI", // bit-reverse input and output parameter REVERSE = 1, // width of data bus parameter DATA_WIDTH = 64, // implementation style: "AUTO", "LOOP", "REDUCTION" parameter STYLE = "AUTO" ) ( input wire clk, input wire rst, input wire [DATA_WIDTH-1:0] data_in, input wire data_in_valid, output wire [DATA_WIDTH-1:0] data_out ); /* Fully parametrizable combinatorial parallel LFSR CRC module. Implements an unrolled LFSR next state computation. Ports: clk Clock input rst Reset module, set state to LFSR_INIT data_in Unscrambled data input (DATA_WIDTH bits) data_in_valid Shift input data through CRC when asserted data_out Scrambled data output (DATA_WIDTH bits) Parameters: LFSR_WIDTH Specify width of LFSR/CRC register LFSR_POLY Specify the LFSR/CRC polynomial in hex format. For example, the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 would be represented as 32'h04c11db7 Note that the largest term (x^32) is suppressed. This term is generated automatically based on LFSR_WIDTH. LFSR_INIT Initial state of LFSR. Defaults to all 1s. LFSR_CONFIG Specify the LFSR configuration, either Fibonacci or Galois. Fibonacci is generally used for linear-feedback shift registers (LFSR) for pseudorandom binary sequence (PRBS) generators, scramblers, and descrambers, while Galois is generally used for cyclic redundancy check generators and checkers. Fibonacci style (example for 64b66b scrambler, 0x8000000001) DIN (LSB first) | V (+)<---------------------------(+)<-----------------------------. | ^ | | .----. .----. .----. | .----. .----. .----. | +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--' | '----' '----' '----' '----' '----' '----' V DOUT Galois style (example for CRC16, 0x8005) ,-------------------+-------------------------+----------(+)<-- DIN (MSB first) | | | ^ | .----. .----. V .----. .----. V .----. | `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |--+---> DOUT '----' '----' '----' '----' '----' REVERSE Bit-reverse LFSR input and output. DATA_WIDTH Specify width of the data bus. The module will perform one shift per input data bit. STYLE Specify implementation style. Can be "AUTO", "LOOP", or "REDUCTION". When "AUTO" is selected, implemenation will be "LOOP" or "REDUCTION" based on synthesis translate directives. "REDUCTION" and "LOOP" are functionally identical, however they simulate and synthesize differently. "REDUCTION" is implemented with a loop over a Verilog reduction operator. "LOOP" is implemented as a doubly-nested loop with no reduction operator. "REDUCTION" is very fast for simulation in iverilog and synthesizes well in Quartus but synthesizes poorly in ISE, likely due to large inferred XOR gates causing problems with the optimizer. "LOOP" synthesizes will in both ISE and Quartus. "AUTO" will default to "REDUCTION" when simulating and "LOOP" for synthesizers that obey synthesis translate directives. Settings for common LFSR/CRC implementations: Name Configuration Length Polynomial Initial value Notes CRC32 Galois, bit-reverse 32 32'h04c11db7 32'hffffffff Ethernet FCS; invert final output PRBS6 Fibonacci 6 6'h21 any PRBS7 Fibonacci 7 7'h41 any PRBS9 Fibonacci 9 9'h021 any ITU V.52 PRBS10 Fibonacci 10 10'h081 any ITU PRBS11 Fibonacci 11 11'h201 any ITU O.152 PRBS15 Fibonacci, inverted 15 15'h4001 any ITU O.152 PRBS17 Fibonacci 17 17'h04001 any PRBS20 Fibonacci 20 20'h00009 any ITU V.57 PRBS23 Fibonacci, inverted 23 23'h040001 any ITU O.151 PRBS29 Fibonacci, inverted 29 29'h08000001 any PRBS31 Fibonacci, inverted 31 31'h10000001 any 64b66b Fibonacci, bit-reverse 58 58'h8000000001 any 10G Ethernet 128b130b Galois, bit-reverse 23 23'h210125 any PCIe gen 3 */ reg [LFSR_WIDTH-1:0] state_reg = LFSR_INIT; reg [DATA_WIDTH-1:0] output_reg = 0; wire [DATA_WIDTH-1:0] lfsr_data; wire [LFSR_WIDTH-1:0] lfsr_state; assign data_out = output_reg; lfsr #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_CONFIG(LFSR_CONFIG), .LFSR_FEED_FORWARD(0), .REVERSE(REVERSE), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) lfsr_inst ( .data_in(data_in), .state_in(state_reg), .data_out(lfsr_data), .state_out(lfsr_state) ); always @(posedge clk) begin if (rst) begin state_reg <= LFSR_INIT; output_reg <= 0; end else begin if (data_in_valid) begin state_reg <= lfsr_state; output_reg <= lfsr_data; end end end endmodule `resetall ================================================ FILE: tb/lfsr/Makefile ================================================ # Copyright (c) 2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. TOPLEVEL_LANG = verilog SIM ?= icarus WAVES ?= 0 COCOTB_HDL_TIMEUNIT = 1ns COCOTB_HDL_TIMEPRECISION = 1ps DUT = lfsr TOPLEVEL = $(DUT) MODULE = test_$(DUT) VERILOG_SOURCES += ../../rtl/$(DUT).v # module parameters export PARAM_LFSR_WIDTH ?= 32 export PARAM_LFSR_POLY ?= "32'h4c11db7" export PARAM_LFSR_CONFIG ?= "\"GALOIS\"" export PARAM_LFSR_FEED_FORWARD ?= 0 export PARAM_REVERSE ?= 1 export PARAM_DATA_WIDTH ?= 8 export PARAM_STYLE ?= "\"AUTO\"" ifeq ($(SIM), icarus) PLUSARGS += -fst COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(TOPLEVEL).$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) VERILOG_SOURCES += iverilog_dump.v COMPILE_ARGS += -s iverilog_dump endif else ifeq ($(SIM), verilator) COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) COMPILE_ARGS += --trace-fst endif endif include $(shell cocotb-config --makefiles)/Makefile.sim iverilog_dump.v: echo 'module iverilog_dump();' > $@ echo 'initial begin' >> $@ echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ echo 'end' >> $@ echo 'endmodule' >> $@ clean:: @rm -rf iverilog_dump.v @rm -rf dump.fst $(TOPLEVEL).fst ================================================ FILE: tb/lfsr/test_lfsr.py ================================================ #!/usr/bin/env python """ Copyright (c) 2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import itertools import logging import os import zlib import pytest import cocotb_test.simulator import cocotb from cocotb.triggers import Timer from cocotb.regression import TestFactory class TB: def __init__(self, dut): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) dut.data_in.setimmediatevalue(0) dut.state_in.setimmediatevalue(0) def chunks(lst, n, padvalue=None): return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue) def crc32(data): return zlib.crc32(data) & 0xffffffff def crc32c(data, crc=0xffffffff, poly=0x82f63b78): for d in data: crc = crc ^ d for bit in range(0, 8): if crc & 1: crc = (crc >> 1) ^ poly else: crc = crc >> 1 return ~crc & 0xffffffff async def run_test_crc(dut, ref_crc): data_width = len(dut.data_in) byte_lanes = data_width // 8 state_width = len(dut.state_in) state_mask = 2**state_width-1 tb = TB(dut) await Timer(10, 'ns') block = bytes([(x+1)*0x11 for x in range(byte_lanes)]) dut.state_in.value = state_mask dut.data_in.value = int.from_bytes(block, 'little') await Timer(10, 'ns') val = ~dut.state_out.value.integer & state_mask ref = ref_crc(block) tb.log.info("CRC: 0x%x (ref: 0x%x)", val, ref) assert val == ref await Timer(10, 'ns') block = bytearray(itertools.islice(itertools.cycle(range(256)), 1024)) dut.state_in.value = state_mask for b in chunks(block, byte_lanes): dut.data_in.value = int.from_bytes(b, 'little') await Timer(10, 'ns') dut.state_in.value = dut.state_out.value val = ~dut.state_out.value.integer & state_mask ref = ref_crc(block) tb.log.info("CRC: 0x%x (ref: 0x%x)", val, ref) assert val == ref await Timer(10, 'ns') def prbs9(state=0x1ff): while True: for i in range(8): if bool(state & 0x10) ^ bool(state & 0x100): state = ((state & 0xff) << 1) | 1 else: state = (state & 0xff) << 1 yield ~state & 0xff def prbs31(state=0x7fffffff): while True: for i in range(8): if bool(state & 0x08000000) ^ bool(state & 0x40000000): state = ((state & 0x3fffffff) << 1) | 1 else: state = (state & 0x3fffffff) << 1 yield ~state & 0xff async def run_test_prbs(dut, ref_prbs): data_width = len(dut.data_in) byte_lanes = data_width // 8 data_mask = 2**data_width-1 state_width = len(dut.state_in) state_mask = 2**state_width-1 tb = TB(dut) await Timer(10, 'ns') dut.state_in.value = state_mask dut.data_in.value = 0 gen = chunks(ref_prbs(), byte_lanes) await Timer(10, 'ns') for i in range(512): ref = int.from_bytes(bytes(next(gen)), 'big') val = ~dut.data_out.value.integer & data_mask tb.log.info("PRBS: 0x%x (ref: 0x%x)", val, ref) assert ref == val dut.state_in.value = dut.state_out.value await Timer(10, 'ns') if cocotb.SIM_NAME: if cocotb.top.LFSR_POLY.value == 0x4c11db7: factory = TestFactory(run_test_crc) factory.add_option("ref_crc", [crc32]) factory.generate_tests() if cocotb.top.LFSR_POLY.value == 0x1edc6f41: factory = TestFactory(run_test_crc) factory.add_option("ref_crc", [crc32c]) factory.generate_tests() if cocotb.top.LFSR_POLY.value == 0x021: factory = TestFactory(run_test_prbs) factory.add_option("ref_prbs", [prbs9]) factory.generate_tests() if cocotb.top.LFSR_POLY.value == 0x10000001: factory = TestFactory(run_test_prbs) factory.add_option("ref_prbs", [prbs31]) factory.generate_tests() # cocotb-test tests_dir = os.path.abspath(os.path.dirname(__file__)) rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) @pytest.mark.parametrize("style", ["AUTO", "LOOP"]) @pytest.mark.parametrize(("lfsr_width", "lfsr_poly", "lfsr_config", "reverse", "data_width"), [ (32, "32'h4c11db7", "GALOIS", 1, 8), (32, "32'h4c11db7", "GALOIS", 1, 64), (32, "32'h1edc6f41", "GALOIS", 1, 8), (32, "32'h1edc6f41", "GALOIS", 1, 64), (9, "9'h021", "FIBONACCI", 0, 8), (9, "9'h021", "FIBONACCI", 0, 64), (31, "31'h10000001", "FIBONACCI", 0, 8), (31, "31'h10000001", "FIBONACCI", 0, 64), ]) def test_lfsr(request, lfsr_width, lfsr_poly, lfsr_config, reverse, data_width, style): dut = "lfsr" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut verilog_sources = [ os.path.join(rtl_dir, f"{dut}.v"), ] parameters = {} parameters['LFSR_WIDTH'] = lfsr_width parameters['LFSR_POLY'] = lfsr_poly parameters['LFSR_CONFIG'] = f'"{lfsr_config}"' parameters['LFSR_FEED_FORWARD'] = 0 parameters['REVERSE'] = reverse parameters['DATA_WIDTH'] = data_width parameters['STYLE'] = f'"{style}"' extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} sim_build = os.path.join(tests_dir, "sim_build", request.node.name.replace('[', '-').replace(']', '')) cocotb_test.simulator.run( python_search=[tests_dir], verilog_sources=verilog_sources, toplevel=toplevel, module=module, parameters=parameters, sim_build=sim_build, extra_env=extra_env, ) ================================================ FILE: tb/lfsr_crc/Makefile ================================================ # Copyright (c) 2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. TOPLEVEL_LANG = verilog SIM ?= icarus WAVES ?= 0 COCOTB_HDL_TIMEUNIT = 1ns COCOTB_HDL_TIMEPRECISION = 1ps DUT = lfsr_crc TOPLEVEL = $(DUT) MODULE = test_$(DUT) VERILOG_SOURCES += ../../rtl/$(DUT).v VERILOG_SOURCES += ../../rtl/lfsr.v # module parameters export PARAM_LFSR_WIDTH ?= 32 export PARAM_LFSR_POLY ?= "32'h4c11db7" export PARAM_LFSR_INIT ?= "32'hffffffff" export PARAM_LFSR_CONFIG ?= "\"GALOIS\"" export PARAM_REVERSE ?= 1 export PARAM_INVERT ?= 1 export PARAM_DATA_WIDTH ?= 8 export PARAM_STYLE ?= "\"AUTO\"" ifeq ($(SIM), icarus) PLUSARGS += -fst COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(TOPLEVEL).$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) VERILOG_SOURCES += iverilog_dump.v COMPILE_ARGS += -s iverilog_dump endif else ifeq ($(SIM), verilator) COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) COMPILE_ARGS += --trace-fst endif endif include $(shell cocotb-config --makefiles)/Makefile.sim iverilog_dump.v: echo 'module iverilog_dump();' > $@ echo 'initial begin' >> $@ echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ echo 'end' >> $@ echo 'endmodule' >> $@ clean:: @rm -rf iverilog_dump.v @rm -rf dump.fst $(TOPLEVEL).fst ================================================ FILE: tb/lfsr_crc/test_lfsr_crc.py ================================================ #!/usr/bin/env python """ Copyright (c) 2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import itertools import logging import os import zlib import pytest import cocotb_test.simulator import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge from cocotb.regression import TestFactory class TB: def __init__(self, dut): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) cocotb.start_soon(Clock(dut.clk, 10, units="ns").start()) dut.data_in.setimmediatevalue(0) dut.data_in_valid.setimmediatevalue(0) async def reset(self): self.dut.rst.setimmediatevalue(0) await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 1 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 0 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) def chunks(lst, n, padvalue=None): return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue) def crc32(data): return zlib.crc32(data) & 0xffffffff def crc32c(data, crc=0xffffffff, poly=0x82f63b78): for d in data: crc = crc ^ d for bit in range(0, 8): if crc & 1: crc = (crc >> 1) ^ poly else: crc = crc >> 1 return ~crc & 0xffffffff async def run_test_crc(dut, ref_crc): data_width = len(dut.data_in) byte_lanes = data_width // 8 tb = TB(dut) await tb.reset() block = bytes([(x+1)*0x11 for x in range(byte_lanes)]) dut.data_in.value = int.from_bytes(block, 'little') dut.data_in_valid.value = 1 await RisingEdge(dut.clk) dut.data_in_valid.value = 0 await RisingEdge(dut.clk) val = dut.crc_out.value.integer ref = ref_crc(block) tb.log.info("CRC: 0x%x (ref: 0x%x)", val, ref) assert val == ref await tb.reset() block = bytearray(itertools.islice(itertools.cycle(range(256)), 1024)) for b in chunks(block, byte_lanes): dut.data_in.value = int.from_bytes(b, 'little') dut.data_in_valid.value = 1 await RisingEdge(dut.clk) dut.data_in_valid.value = 0 await RisingEdge(dut.clk) val = dut.crc_out.value.integer ref = ref_crc(block) tb.log.info("CRC: 0x%x (ref: 0x%x)", val, ref) assert val == ref await RisingEdge(dut.clk) await RisingEdge(dut.clk) if cocotb.SIM_NAME: if cocotb.top.LFSR_POLY.value == 0x4c11db7: factory = TestFactory(run_test_crc) factory.add_option("ref_crc", [crc32]) factory.generate_tests() if cocotb.top.LFSR_POLY.value == 0x1edc6f41: factory = TestFactory(run_test_crc) factory.add_option("ref_crc", [crc32c]) factory.generate_tests() # cocotb-test tests_dir = os.path.abspath(os.path.dirname(__file__)) rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) @pytest.mark.parametrize("style", ["AUTO", "LOOP"]) @pytest.mark.parametrize(("lfsr_width", "lfsr_poly", "lfsr_init", "lfsr_config", "reverse", "invert", "data_width"), [ (32, "32'h4c11db7", "32'hffffffff", "GALOIS", 1, 1, 8), (32, "32'h4c11db7", "32'hffffffff", "GALOIS", 1, 1, 64), (32, "32'h1edc6f41", "32'hffffffff", "GALOIS", 1, 1, 8), (32, "32'h1edc6f41", "32'hffffffff", "GALOIS", 1, 1, 64), ]) def test_lfsr_crc(request, lfsr_width, lfsr_poly, lfsr_init, lfsr_config, reverse, invert, data_width, style): dut = "lfsr_crc" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut verilog_sources = [ os.path.join(rtl_dir, f"{dut}.v"), os.path.join(rtl_dir, "lfsr.v"), ] parameters = {} parameters['LFSR_WIDTH'] = lfsr_width parameters['LFSR_POLY'] = lfsr_poly parameters['LFSR_INIT'] = lfsr_init parameters['LFSR_CONFIG'] = f'"{lfsr_config}"' parameters['REVERSE'] = reverse parameters['INVERT'] = invert parameters['DATA_WIDTH'] = data_width parameters['STYLE'] = f'"{style}"' extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} sim_build = os.path.join(tests_dir, "sim_build", request.node.name.replace('[', '-').replace(']', '')) cocotb_test.simulator.run( python_search=[tests_dir], verilog_sources=verilog_sources, toplevel=toplevel, module=module, parameters=parameters, sim_build=sim_build, extra_env=extra_env, ) ================================================ FILE: tb/lfsr_descramble/Makefile ================================================ # Copyright (c) 2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. TOPLEVEL_LANG = verilog SIM ?= icarus WAVES ?= 0 COCOTB_HDL_TIMEUNIT = 1ns COCOTB_HDL_TIMEPRECISION = 1ps DUT = lfsr_descramble TOPLEVEL = $(DUT) MODULE = test_$(DUT) VERILOG_SOURCES += ../../rtl/$(DUT).v VERILOG_SOURCES += ../../rtl/lfsr.v # module parameters export PARAM_LFSR_WIDTH ?= 58 export PARAM_LFSR_POLY ?= "58'h8000000001" export PARAM_LFSR_INIT ?= "58'h3ffffffffffffff" export PARAM_LFSR_CONFIG ?= "\"FIBONACCI\"" export PARAM_REVERSE ?= 1 export PARAM_DATA_WIDTH ?= 8 export PARAM_STYLE ?= "\"AUTO\"" ifeq ($(SIM), icarus) PLUSARGS += -fst COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(TOPLEVEL).$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) VERILOG_SOURCES += iverilog_dump.v COMPILE_ARGS += -s iverilog_dump endif else ifeq ($(SIM), verilator) COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) COMPILE_ARGS += --trace-fst endif endif include $(shell cocotb-config --makefiles)/Makefile.sim iverilog_dump.v: echo 'module iverilog_dump();' > $@ echo 'initial begin' >> $@ echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ echo 'end' >> $@ echo 'endmodule' >> $@ clean:: @rm -rf iverilog_dump.v @rm -rf dump.fst $(TOPLEVEL).fst ================================================ FILE: tb/lfsr_descramble/test_lfsr_descramble.py ================================================ #!/usr/bin/env python """ Copyright (c) 2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import itertools import logging import os import pytest import cocotb_test.simulator import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge from cocotb.regression import TestFactory class TB: def __init__(self, dut): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) cocotb.start_soon(Clock(dut.clk, 10, units="ns").start()) dut.data_in.setimmediatevalue(0) dut.data_in_valid.setimmediatevalue(0) async def reset(self): self.dut.rst.setimmediatevalue(0) await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 1 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 0 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) def chunks(lst, n, padvalue=None): return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue) def scramble_64b66b(data, state=0x3ffffffffffffff): data_out = bytearray() for d in data: b = 0 for i in range(8): if bool(state & (1 << 38)) ^ bool(state & (1 << 57)) ^ bool(d & (1 << i)): state = ((state & 0x1ffffffffffffff) << 1) | 1 b = b | (1 << i) else: state = (state & 0x1ffffffffffffff) << 1 data_out.append(b) return data_out def descramble_64b66b(data, state=0x3ffffffffffffff): data_out = bytearray() for d in data: b = 0 for i in range(8): if bool(state & (1 << 38)) ^ bool(state & (1 << 57)) ^ bool(d & (1 << i)): b = b | (1 << i) state = (state & 0x1ffffffffffffff) << 1 | bool(d & (1 << i)) data_out += bytearray([b]) return data_out async def run_test_descramble(dut, ref_scramble): data_width = len(dut.data_in) byte_lanes = data_width // 8 tb = TB(dut) await tb.reset() block = bytearray(itertools.islice(itertools.cycle(range(256)), 1024)) scr = scramble_64b66b(block) dscr = descramble_64b66b(scr) assert dscr == block ref_iter = iter(chunks(block, byte_lanes)) first = True for b in chunks(scr, byte_lanes): dut.data_in.value = int.from_bytes(b, 'little') dut.data_in_valid.value = 1 await RisingEdge(dut.clk) val = dut.data_out.value.integer if not first: ref = int.from_bytes(bytes(next(ref_iter)), 'little') tb.log.info("Descrambled: 0x%x (ref: 0x%x)", val, ref) assert ref == val first = False dut.data_in_valid.value = 0 await RisingEdge(dut.clk) if cocotb.SIM_NAME: # if cocotb.top.LFSR_POLY.value == 0x8000000001: if cocotb.top.LFSR_WIDTH == 58: factory = TestFactory(run_test_descramble) factory.add_option("ref_scramble", [scramble_64b66b]) factory.generate_tests() # cocotb-test tests_dir = os.path.abspath(os.path.dirname(__file__)) rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) @pytest.mark.parametrize("style", ["AUTO", "LOOP"]) @pytest.mark.parametrize(("lfsr_width", "lfsr_poly", "lfsr_init", "lfsr_config", "reverse", "data_width"), [ (58, "58'h8000000001", "58'h3ffffffffffffff", "FIBONACCI", 1, 8), (58, "58'h8000000001", "58'h3ffffffffffffff", "FIBONACCI", 1, 64), ]) def test_lfsr_descramble(request, lfsr_width, lfsr_poly, lfsr_init, lfsr_config, reverse, data_width, style): dut = "lfsr_descramble" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut verilog_sources = [ os.path.join(rtl_dir, f"{dut}.v"), os.path.join(rtl_dir, "lfsr.v"), ] parameters = {} parameters['LFSR_WIDTH'] = lfsr_width parameters['LFSR_POLY'] = lfsr_poly parameters['LFSR_INIT'] = lfsr_init parameters['LFSR_CONFIG'] = f'"{lfsr_config}"' parameters['REVERSE'] = reverse parameters['DATA_WIDTH'] = data_width parameters['STYLE'] = f'"{style}"' extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} sim_build = os.path.join(tests_dir, "sim_build", request.node.name.replace('[', '-').replace(']', '')) cocotb_test.simulator.run( python_search=[tests_dir], verilog_sources=verilog_sources, toplevel=toplevel, module=module, parameters=parameters, sim_build=sim_build, extra_env=extra_env, ) ================================================ FILE: tb/lfsr_prbs_check/Makefile ================================================ # Copyright (c) 2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. TOPLEVEL_LANG = verilog SIM ?= icarus WAVES ?= 0 COCOTB_HDL_TIMEUNIT = 1ns COCOTB_HDL_TIMEPRECISION = 1ps DUT = lfsr_prbs_check TOPLEVEL = $(DUT) MODULE = test_$(DUT) VERILOG_SOURCES += ../../rtl/$(DUT).v VERILOG_SOURCES += ../../rtl/lfsr.v # module parameters export PARAM_LFSR_WIDTH ?= 31 export PARAM_LFSR_POLY ?= "31'h10000001" export PARAM_LFSR_INIT ?= "31'h7fffffff" export PARAM_LFSR_CONFIG ?= "\"FIBONACCI\"" export PARAM_REVERSE ?= 0 export PARAM_INVERT ?= 1 export PARAM_DATA_WIDTH ?= 8 export PARAM_STYLE ?= "\"AUTO\"" ifeq ($(SIM), icarus) PLUSARGS += -fst COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(TOPLEVEL).$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) VERILOG_SOURCES += iverilog_dump.v COMPILE_ARGS += -s iverilog_dump endif else ifeq ($(SIM), verilator) COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) COMPILE_ARGS += --trace-fst endif endif include $(shell cocotb-config --makefiles)/Makefile.sim iverilog_dump.v: echo 'module iverilog_dump();' > $@ echo 'initial begin' >> $@ echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ echo 'end' >> $@ echo 'endmodule' >> $@ clean:: @rm -rf iverilog_dump.v @rm -rf dump.fst $(TOPLEVEL).fst ================================================ FILE: tb/lfsr_prbs_check/test_lfsr_prbs_check.py ================================================ #!/usr/bin/env python """ Copyright (c) 2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import itertools import logging import os import pytest import cocotb_test.simulator import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge from cocotb.regression import TestFactory class TB: def __init__(self, dut): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) cocotb.start_soon(Clock(dut.clk, 10, units="ns").start()) dut.data_in.setimmediatevalue(0) dut.data_in_valid.setimmediatevalue(0) async def reset(self): self.dut.rst.setimmediatevalue(0) await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 1 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 0 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) def chunks(lst, n, padvalue=None): return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue) def prbs9(state=0x1ff): while True: for i in range(8): if bool(state & 0x10) ^ bool(state & 0x100): state = ((state & 0xff) << 1) | 1 else: state = (state & 0xff) << 1 yield ~state & 0xff def prbs31(state=0x7fffffff): while True: for i in range(8): if bool(state & 0x08000000) ^ bool(state & 0x40000000): state = ((state & 0x3fffffff) << 1) | 1 else: state = (state & 0x3fffffff) << 1 yield ~state & 0xff def count_set_bits(n): cnt = 0 while n: n &= n - 1 cnt += 1 return cnt async def run_test_prbs(dut, ref_prbs): data_width = len(dut.data_out) byte_lanes = data_width // 8 tb = TB(dut) await tb.reset() gen = chunks(ref_prbs(), byte_lanes) err_cnt = 0 for i in range(512): dut.data_in.value = int.from_bytes(bytes(next(gen)), 'big') dut.data_in_valid.value = 1 val = dut.data_out.value.integer tb.log.info("Error value: 0x%x", val) err_cnt += count_set_bits(val) assert val == 0 await RisingEdge(dut.clk) dut.data_in_valid.value = 0 tb.log.info("Error count: %d", err_cnt) assert err_cnt == 0 await tb.reset() tb.log.info("Single error test") gen = chunks(ref_prbs(), byte_lanes) err_cnt = 0 for i in range(64): val = int.from_bytes(bytes(next(gen)), 'big') if i == 32: val = val ^ (1 << (data_width // 2)) dut.data_in.value = val dut.data_in_valid.value = 1 val = dut.data_out.value.integer tb.log.info("Error value: 0x%x", val) err_cnt += count_set_bits(val) await RisingEdge(dut.clk) dut.data_in_valid.value = 0 tb.log.info("Error count: %d", err_cnt) # one bit set per tap assert err_cnt == 3 if cocotb.SIM_NAME: if cocotb.top.LFSR_POLY.value == 0x021: factory = TestFactory(run_test_prbs) factory.add_option("ref_prbs", [prbs9]) factory.generate_tests() if cocotb.top.LFSR_POLY.value == 0x10000001: factory = TestFactory(run_test_prbs) factory.add_option("ref_prbs", [prbs31]) factory.generate_tests() # cocotb-test tests_dir = os.path.abspath(os.path.dirname(__file__)) rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) @pytest.mark.parametrize("style", ["AUTO", "LOOP"]) @pytest.mark.parametrize(("lfsr_width", "lfsr_poly", "lfsr_init", "lfsr_config", "reverse", "invert", "data_width"), [ (9, "9'h021", "9'h1ff", "FIBONACCI", 0, 1, 8), (9, "9'h021", "9'h1ff", "FIBONACCI", 0, 1, 64), (31, "31'h10000001", "31'h7fffffff", "FIBONACCI", 0, 1, 8), (31, "31'h10000001", "31'h7fffffff", "FIBONACCI", 0, 1, 64), ]) def test_lfsr_prbs_check(request, lfsr_width, lfsr_poly, lfsr_init, lfsr_config, reverse, invert, data_width, style): dut = "lfsr_prbs_check" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut verilog_sources = [ os.path.join(rtl_dir, f"{dut}.v"), os.path.join(rtl_dir, "lfsr.v"), ] parameters = {} parameters['LFSR_WIDTH'] = lfsr_width parameters['LFSR_POLY'] = lfsr_poly parameters['LFSR_INIT'] = lfsr_init parameters['LFSR_CONFIG'] = f'"{lfsr_config}"' parameters['REVERSE'] = reverse parameters['INVERT'] = invert parameters['DATA_WIDTH'] = data_width parameters['STYLE'] = f'"{style}"' extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} sim_build = os.path.join(tests_dir, "sim_build", request.node.name.replace('[', '-').replace(']', '')) cocotb_test.simulator.run( python_search=[tests_dir], verilog_sources=verilog_sources, toplevel=toplevel, module=module, parameters=parameters, sim_build=sim_build, extra_env=extra_env, ) ================================================ FILE: tb/lfsr_prbs_gen/Makefile ================================================ # Copyright (c) 2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. TOPLEVEL_LANG = verilog SIM ?= icarus WAVES ?= 0 COCOTB_HDL_TIMEUNIT = 1ns COCOTB_HDL_TIMEPRECISION = 1ps DUT = lfsr_prbs_gen TOPLEVEL = $(DUT) MODULE = test_$(DUT) VERILOG_SOURCES += ../../rtl/$(DUT).v VERILOG_SOURCES += ../../rtl/lfsr.v # module parameters export PARAM_LFSR_WIDTH ?= 31 export PARAM_LFSR_POLY ?= "31'h10000001" export PARAM_LFSR_INIT ?= "31'h7fffffff" export PARAM_LFSR_CONFIG ?= "\"FIBONACCI\"" export PARAM_REVERSE ?= 0 export PARAM_INVERT ?= 1 export PARAM_DATA_WIDTH ?= 8 export PARAM_STYLE ?= "\"AUTO\"" ifeq ($(SIM), icarus) PLUSARGS += -fst COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(TOPLEVEL).$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) VERILOG_SOURCES += iverilog_dump.v COMPILE_ARGS += -s iverilog_dump endif else ifeq ($(SIM), verilator) COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) COMPILE_ARGS += --trace-fst endif endif include $(shell cocotb-config --makefiles)/Makefile.sim iverilog_dump.v: echo 'module iverilog_dump();' > $@ echo 'initial begin' >> $@ echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ echo 'end' >> $@ echo 'endmodule' >> $@ clean:: @rm -rf iverilog_dump.v @rm -rf dump.fst $(TOPLEVEL).fst ================================================ FILE: tb/lfsr_prbs_gen/test_lfsr_prbs_gen.py ================================================ #!/usr/bin/env python """ Copyright (c) 2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import itertools import logging import os import pytest import cocotb_test.simulator import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge from cocotb.regression import TestFactory class TB: def __init__(self, dut): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) cocotb.start_soon(Clock(dut.clk, 10, units="ns").start()) dut.enable.setimmediatevalue(0) async def reset(self): self.dut.rst.setimmediatevalue(0) await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 1 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 0 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) def chunks(lst, n, padvalue=None): return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue) def prbs9(state=0x1ff): while True: for i in range(8): if bool(state & 0x10) ^ bool(state & 0x100): state = ((state & 0xff) << 1) | 1 else: state = (state & 0xff) << 1 yield ~state & 0xff def prbs31(state=0x7fffffff): while True: for i in range(8): if bool(state & 0x08000000) ^ bool(state & 0x40000000): state = ((state & 0x3fffffff) << 1) | 1 else: state = (state & 0x3fffffff) << 1 yield ~state & 0xff async def run_test_prbs(dut, ref_prbs): data_width = len(dut.data_out) byte_lanes = data_width // 8 tb = TB(dut) await tb.reset() gen = chunks(ref_prbs(), byte_lanes) dut.enable.value = 1 await RisingEdge(dut.clk) for i in range(512): ref = int.from_bytes(bytes(next(gen)), 'big') val = dut.data_out.value.integer tb.log.info("PRBS: 0x%x (ref: 0x%x)", val, ref) assert ref == val await RisingEdge(dut.clk) if cocotb.SIM_NAME: if cocotb.top.LFSR_POLY.value == 0x021: factory = TestFactory(run_test_prbs) factory.add_option("ref_prbs", [prbs9]) factory.generate_tests() if cocotb.top.LFSR_POLY.value == 0x10000001: factory = TestFactory(run_test_prbs) factory.add_option("ref_prbs", [prbs31]) factory.generate_tests() # cocotb-test tests_dir = os.path.abspath(os.path.dirname(__file__)) rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) @pytest.mark.parametrize("style", ["AUTO", "LOOP"]) @pytest.mark.parametrize(("lfsr_width", "lfsr_poly", "lfsr_init", "lfsr_config", "reverse", "invert", "data_width"), [ (9, "9'h021", "9'h1ff", "FIBONACCI", 0, 1, 8), (9, "9'h021", "9'h1ff", "FIBONACCI", 0, 1, 64), (31, "31'h10000001", "31'h7fffffff", "FIBONACCI", 0, 1, 8), (31, "31'h10000001", "31'h7fffffff", "FIBONACCI", 0, 1, 64), ]) def test_lfsr_prbs_gen(request, lfsr_width, lfsr_poly, lfsr_init, lfsr_config, reverse, invert, data_width, style): dut = "lfsr_prbs_gen" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut verilog_sources = [ os.path.join(rtl_dir, f"{dut}.v"), os.path.join(rtl_dir, "lfsr.v"), ] parameters = {} parameters['LFSR_WIDTH'] = lfsr_width parameters['LFSR_POLY'] = lfsr_poly parameters['LFSR_INIT'] = lfsr_init parameters['LFSR_CONFIG'] = f'"{lfsr_config}"' parameters['REVERSE'] = reverse parameters['INVERT'] = invert parameters['DATA_WIDTH'] = data_width parameters['STYLE'] = f'"{style}"' extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} sim_build = os.path.join(tests_dir, "sim_build", request.node.name.replace('[', '-').replace(']', '')) cocotb_test.simulator.run( python_search=[tests_dir], verilog_sources=verilog_sources, toplevel=toplevel, module=module, parameters=parameters, sim_build=sim_build, extra_env=extra_env, ) ================================================ FILE: tb/lfsr_scramble/Makefile ================================================ # Copyright (c) 2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. TOPLEVEL_LANG = verilog SIM ?= icarus WAVES ?= 0 COCOTB_HDL_TIMEUNIT = 1ns COCOTB_HDL_TIMEPRECISION = 1ps DUT = lfsr_scramble TOPLEVEL = $(DUT) MODULE = test_$(DUT) VERILOG_SOURCES += ../../rtl/$(DUT).v VERILOG_SOURCES += ../../rtl/lfsr.v # module parameters export PARAM_LFSR_WIDTH ?= 58 export PARAM_LFSR_POLY ?= "58'h8000000001" export PARAM_LFSR_INIT ?= "58'h3ffffffffffffff" export PARAM_LFSR_CONFIG ?= "\"FIBONACCI\"" export PARAM_REVERSE ?= 1 export PARAM_DATA_WIDTH ?= 8 export PARAM_STYLE ?= "\"AUTO\"" ifeq ($(SIM), icarus) PLUSARGS += -fst COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(TOPLEVEL).$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) VERILOG_SOURCES += iverilog_dump.v COMPILE_ARGS += -s iverilog_dump endif else ifeq ($(SIM), verilator) COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v))) ifeq ($(WAVES), 1) COMPILE_ARGS += --trace-fst endif endif include $(shell cocotb-config --makefiles)/Makefile.sim iverilog_dump.v: echo 'module iverilog_dump();' > $@ echo 'initial begin' >> $@ echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ echo 'end' >> $@ echo 'endmodule' >> $@ clean:: @rm -rf iverilog_dump.v @rm -rf dump.fst $(TOPLEVEL).fst ================================================ FILE: tb/lfsr_scramble/test_lfsr_scramble.py ================================================ #!/usr/bin/env python """ Copyright (c) 2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import itertools import logging import os import pytest import cocotb_test.simulator import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge from cocotb.regression import TestFactory class TB: def __init__(self, dut): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) cocotb.start_soon(Clock(dut.clk, 10, units="ns").start()) dut.data_in.setimmediatevalue(0) dut.data_in_valid.setimmediatevalue(0) async def reset(self): self.dut.rst.setimmediatevalue(0) await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 1 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) self.dut.rst.value = 0 await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) def chunks(lst, n, padvalue=None): return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue) def scramble_64b66b(data, state=0x3ffffffffffffff): data_out = bytearray() for d in data: b = 0 for i in range(8): if bool(state & (1 << 38)) ^ bool(state & (1 << 57)) ^ bool(d & (1 << i)): state = ((state & 0x1ffffffffffffff) << 1) | 1 b = b | (1 << i) else: state = (state & 0x1ffffffffffffff) << 1 data_out.append(b) return data_out async def run_test_scramble(dut, ref_scramble): data_width = len(dut.data_in) byte_lanes = data_width // 8 tb = TB(dut) await tb.reset() block = bytearray(itertools.islice(itertools.cycle(range(256)), 1024)) scr = scramble_64b66b(block) scr_iter = iter(chunks(scr, byte_lanes)) first = True for b in chunks(block, byte_lanes): dut.data_in.value = int.from_bytes(b, 'little') dut.data_in_valid.value = 1 await RisingEdge(dut.clk) val = dut.data_out.value.integer if not first: ref = int.from_bytes(bytes(next(scr_iter)), 'little') tb.log.info("Scrambled: 0x%x (ref: 0x%x)", val, ref) assert ref == val first = False dut.data_in_valid.value = 0 await RisingEdge(dut.clk) if cocotb.SIM_NAME: # if cocotb.top.LFSR_POLY.value == 0x8000000001: if cocotb.top.LFSR_WIDTH == 58: factory = TestFactory(run_test_scramble) factory.add_option("ref_scramble", [scramble_64b66b]) factory.generate_tests() # cocotb-test tests_dir = os.path.abspath(os.path.dirname(__file__)) rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) @pytest.mark.parametrize("style", ["AUTO", "LOOP"]) @pytest.mark.parametrize(("lfsr_width", "lfsr_poly", "lfsr_init", "lfsr_config", "reverse", "data_width"), [ (58, "58'h8000000001", "58'h3ffffffffffffff", "FIBONACCI", 1, 8), (58, "58'h8000000001", "58'h3ffffffffffffff", "FIBONACCI", 1, 64), ]) def test_lfsr_scramble(request, lfsr_width, lfsr_poly, lfsr_init, lfsr_config, reverse, data_width, style): dut = "lfsr_scramble" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut verilog_sources = [ os.path.join(rtl_dir, f"{dut}.v"), os.path.join(rtl_dir, "lfsr.v"), ] parameters = {} parameters['LFSR_WIDTH'] = lfsr_width parameters['LFSR_POLY'] = lfsr_poly parameters['LFSR_INIT'] = lfsr_init parameters['LFSR_CONFIG'] = f'"{lfsr_config}"' parameters['REVERSE'] = reverse parameters['DATA_WIDTH'] = data_width parameters['STYLE'] = f'"{style}"' extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} sim_build = os.path.join(tests_dir, "sim_build", request.node.name.replace('[', '-').replace(']', '')) cocotb_test.simulator.run( python_search=[tests_dir], verilog_sources=verilog_sources, toplevel=toplevel, module=module, parameters=parameters, sim_build=sim_build, extra_env=extra_env, ) ================================================ FILE: tb/test_lfsr_crc32.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os import zlib module = 'lfsr' testbench = 'test_%s_crc32' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def bench(): # Parameters LFSR_WIDTH = 32 LFSR_POLY = 0x4c11db7 LFSR_CONFIG = "GALOIS" LFSR_FEED_FORWARD = 0 REVERSE = 1 DATA_WIDTH = 8 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) data_in = Signal(intbv(0)[DATA_WIDTH:]) state_in = Signal(intbv(0)[LFSR_WIDTH:]) # Outputs data_out = Signal(intbv(0)[DATA_WIDTH:]) state_out = Signal(intbv(0)[LFSR_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, data_in=data_in, state_in=state_in, data_out=data_out, state_out=state_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: single word") current_test.next = 1 state_in.next = 0xffffffff data_in.next = 0x12 yield clk.posedge print(hex(~state_out.val)) print(hex(zlib.crc32(b'\x12') & 0xffffffff)) assert ~state_out.val == zlib.crc32(b'\x12') & 0xffffffff yield delay(100) yield clk.posedge print("test 2: block") current_test.next = 2 block = b'\x11\x22\x33\x44' state_in.next = 0xffffffff for b in block: data_in.next = b yield clk.posedge state_in.next = state_out.val print(hex(~state_out.val)) print(hex(zlib.crc32(block) & 0xffffffff)) assert ~state_out.val == zlib.crc32(block) & 0xffffffff yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_crc32.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_crc32 */ module test_lfsr_crc32; // Parameters parameter LFSR_WIDTH = 32; parameter LFSR_POLY = 32'h4c11db7; parameter LFSR_CONFIG = "GALOIS"; parameter LFSR_FEED_FORWARD = 0; parameter REVERSE = 1; parameter DATA_WIDTH = 8; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg [DATA_WIDTH-1:0] data_in = 0; reg [LFSR_WIDTH-1:0] state_in = 0; // Outputs wire [DATA_WIDTH-1:0] data_out = 0; wire [LFSR_WIDTH-1:0] state_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, data_in, state_in ); $to_myhdl( data_out, state_out ); // dump file $dumpfile("test_lfsr_crc32.lxt"); $dumpvars(0, test_lfsr_crc32); end lfsr #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_CONFIG(LFSR_CONFIG), .LFSR_FEED_FORWARD(LFSR_FEED_FORWARD), .REVERSE(REVERSE), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .data_in(data_in), .state_in(state_in), .data_out(data_out), .state_out(state_out) ); endmodule ================================================ FILE: tb/test_lfsr_crc_crc32.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os import zlib module = 'lfsr_crc' testbench = 'test_%s_crc32' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def bench(): # Parameters LFSR_WIDTH = 32 LFSR_POLY = 0x04c11db7 LFSR_INIT = 0xffffffff LFSR_CONFIG = "GALOIS" REVERSE = 1 INVERT = 1 DATA_WIDTH = 8 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) data_in = Signal(intbv(0)[DATA_WIDTH:]) data_in_valid = Signal(bool(0)) # Outputs crc_out = Signal(intbv(0)[LFSR_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, data_in=data_in, data_in_valid=data_in_valid, crc_out=crc_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): print("mark") yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: single word") current_test.next = 1 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge data_in.next = 0x12 data_in_valid.next = 1 yield clk.posedge data_in_valid.next = 0 yield clk.posedge print(hex(crc_out.val)) print(hex(zlib.crc32(b'\x12') & 0xffffffff)) assert crc_out.val == zlib.crc32(b'\x12') & 0xffffffff yield delay(100) yield clk.posedge print("test 2: block") current_test.next = 2 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge block = b'\x11\x22\x33\x44' for b in block: data_in.next = b data_in_valid.next = 1 yield clk.posedge data_in_valid.next = 0 yield clk.posedge print(hex(crc_out.val)) print(hex(zlib.crc32(block) & 0xffffffff)) assert crc_out.val == zlib.crc32(block) & 0xffffffff yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_crc_crc32.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_crc */ module test_lfsr_crc_crc32; // Parameters parameter LFSR_WIDTH = 32; parameter LFSR_POLY = 32'h04c11db7; parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}; parameter LFSR_CONFIG = "GALOIS"; parameter REVERSE = 1; parameter INVERT = 1; parameter DATA_WIDTH = 8; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg [DATA_WIDTH-1:0] data_in = 0; reg data_in_valid = 0; // Outputs wire [LFSR_WIDTH-1:0] crc_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, data_in, data_in_valid ); $to_myhdl( crc_out ); // dump file $dumpfile("test_lfsr_crc_crc32.lxt"); $dumpvars(0, test_lfsr_crc_crc32); end lfsr_crc #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_INIT(LFSR_INIT), .LFSR_CONFIG(LFSR_CONFIG), .REVERSE(REVERSE), .INVERT(INVERT), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .clk(clk), .rst(rst), .data_in(data_in), .data_in_valid(data_in_valid), .crc_out(crc_out) ); endmodule ================================================ FILE: tb/test_lfsr_crc_crc32_64.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os import zlib import struct module = 'lfsr_crc' testbench = 'test_%s_crc32_64' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def chunks(l, n): """Yield successive n-sized chunks from l.""" for i in range(0, len(l), n): yield l[i:i+n] def bench(): # Parameters LFSR_WIDTH = 32 LFSR_POLY = 0x04c11db7 LFSR_INIT = 0xffffffff LFSR_CONFIG = "GALOIS" REVERSE = 1 INVERT = 1 DATA_WIDTH = 64 OUTPUT_WIDTH = LFSR_WIDTH STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) data_in = Signal(intbv(0)[DATA_WIDTH:]) data_in_valid = Signal(bool(0)) # Outputs crc_out = Signal(intbv(0)[OUTPUT_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, data_in=data_in, data_in_valid=data_in_valid, crc_out=crc_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: single word") current_test.next = 1 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge block = bytes(range(8)) data_in.next = struct.unpack(' 0: ref = block[i-1] print(hex(data_out)) print(hex(ref)) assert data_out == ref i += 1 data_in_valid.next = 0 yield clk.posedge yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_descramble.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_descramble */ module test_lfsr_descramble; // Parameters parameter LFSR_WIDTH = 58; parameter LFSR_POLY = 58'h8000000001; parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}; parameter LFSR_CONFIG = "FIBONACCI"; parameter REVERSE = 1; parameter DATA_WIDTH = 8; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg [DATA_WIDTH-1:0] data_in = 0; reg data_in_valid = 0; // Outputs wire [DATA_WIDTH-1:0] data_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, data_in, data_in_valid ); $to_myhdl( data_out ); // dump file $dumpfile("test_lfsr_descramble.lxt"); $dumpvars(0, test_lfsr_descramble); end lfsr_descramble #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_INIT(LFSR_INIT), .LFSR_CONFIG(LFSR_CONFIG), .REVERSE(REVERSE), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .clk(clk), .rst(rst), .data_in(data_in), .data_in_valid(data_in_valid), .data_out(data_out) ); endmodule ================================================ FILE: tb/test_lfsr_descramble_64.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os import struct module = 'lfsr_descramble' testbench = 'test_%s_64' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def scramble_64b66b(data, state=0x3ffffffffffffff): data_out = bytearray() for d in data: b = 0 for i in range(8): if bool(state & (1<<38)) ^ bool(state & (1<<57)) ^ bool(d & (1 << i)): state = ((state & 0x1ffffffffffffff) << 1) | 1 b = b | (1 << i) else: state = (state & 0x1ffffffffffffff) << 1 data_out += bytearray([b]) return data_out def descramble_64b66b(data, state=0x3ffffffffffffff): data_out = bytearray() for d in data: b = 0 for i in range(8): if bool(state & (1<<38)) ^ bool(state & (1<<57)) ^ bool(d & (1 << i)): b = b | (1 << i) state = (state & 0x1ffffffffffffff) << 1 | bool(d & (1 << i)) data_out += bytearray([b]) print(hex(d)+" "+hex(b)) print(hex(state)) return data_out def chunks(l, n): """Yield successive n-sized chunks from l.""" for i in range(0, len(l), n): yield l[i:i+n] def bench(): # Parameters LFSR_WIDTH = 58 LFSR_POLY = 0x8000000001 LFSR_INIT = 0x3ffffffffffffff LFSR_CONFIG = "FIBONACCI" REVERSE = 1 DATA_WIDTH = 64 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) data_in = Signal(intbv(0)[DATA_WIDTH:]) data_in_valid = Signal(bool(0)) # Outputs data_out = Signal(intbv(0)[DATA_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, data_in=data_in, data_in_valid=data_in_valid, data_out=data_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: block") current_test.next = 1 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge block = bytes(range(256)) scr = scramble_64b66b(block) dscr = descramble_64b66b(scr) for i in range(0, len(scr), 8): data_in.next = struct.unpack(' 0: ref = struct.unpack('Q', bytes([x for _, x in zip(range(8), gen)]))[0] data_in_valid.next = 1 yield clk.posedge for i in range(512): data_in.next = struct.unpack('>Q', bytes([x for _, x in zip(range(8), gen)]))[0] data_in_valid.next = 1 val = data_out.val print(val) assert val == 0 yield clk.posedge data_in_valid.next = 0 yield delay(100) yield clk.posedge print("test 2: single error") current_test.next = 2 gen = prbs31() for i in range(16): data_in.next = struct.unpack('>Q', bytes([x for _, x in zip(range(8), gen)]))[0] data_in_valid.next = 1 yield clk.posedge data_in.next = struct.unpack('>Q', bytes([x for _, x in zip(range(8), gen)]))[0] ^ 0x0001000000000000 data_in_valid.next = 1 yield clk.posedge val = data_out.val print(val) assert val == 0x0000000000000000 data_in.next = struct.unpack('>Q', bytes([x for _, x in zip(range(8), gen)]))[0] data_in_valid.next = 1 yield clk.posedge val = data_out.val print(val) assert val == 0x0001000000120000 data_in.next = struct.unpack('>Q', bytes([x for _, x in zip(range(8), gen)]))[0] data_in_valid.next = 1 yield clk.posedge val = data_out.val print(val) assert val == 0x0000000000000000 data_in_valid.next = 0 yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_prbs_check_prbs31_64.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_prbs_check */ module test_lfsr_prbs_check_prbs31_64; // Parameters parameter LFSR_WIDTH = 31; parameter LFSR_POLY = 31'h10000001; parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}; parameter LFSR_CONFIG = "FIBONACCI"; parameter REVERSE = 0; parameter INVERT = 1; parameter DATA_WIDTH = 64; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg [DATA_WIDTH-1:0] data_in = 0; reg data_in_valid = 0; // Outputs wire [DATA_WIDTH-1:0] data_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, data_in, data_in_valid ); $to_myhdl( data_out ); // dump file $dumpfile("test_lfsr_prbs_check_prbs31_64.lxt"); $dumpvars(0, test_lfsr_prbs_check_prbs31_64); end lfsr_prbs_check #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_INIT(LFSR_INIT), .LFSR_CONFIG(LFSR_CONFIG), .REVERSE(REVERSE), .INVERT(INVERT), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .clk(clk), .rst(rst), .data_in(data_in), .data_in_valid(data_in_valid), .data_out(data_out) ); endmodule ================================================ FILE: tb/test_lfsr_prbs_check_prbs9.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os module = 'lfsr_prbs_check' testbench = 'test_%s_prbs9' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def prbs9(state = 0x1ff): while True: for i in range(8): if bool(state & 0x10) ^ bool(state & 0x100): state = ((state & 0xff) << 1) | 1 else: state = (state & 0xff) << 1 yield state & 0xff def bench(): # Parameters LFSR_WIDTH = 9 LFSR_POLY = 0x021 LFSR_INIT = 0x1ff LFSR_CONFIG = "FIBONACCI" REVERSE = 0 INVERT = 0 DATA_WIDTH = 8 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) data_in = Signal(intbv(0)[DATA_WIDTH:]) data_in_valid = Signal(bool(0)) # Outputs data_out = Signal(intbv(0)[DATA_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, data_in=data_in, data_in_valid=data_in_valid, data_out=data_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: test PRBS9") current_test.next = 1 gen = prbs9() data_in.next = next(gen) data_in_valid.next = 1 yield clk.posedge for i in range(512): data_in.next = next(gen) data_in_valid.next = 1 val = data_out.val print(val) assert val == 0 yield clk.posedge data_in_valid.next = 0 yield delay(100) yield clk.posedge print("test 2: single error") current_test.next = 2 gen = prbs9() for i in range(16): data_in.next = next(gen) data_in_valid.next = 1 yield clk.posedge data_in.next = next(gen) ^ 0x08 data_in_valid.next = 1 yield clk.posedge val = data_out.val print(val) assert val == 0x00 data_in.next = next(gen) data_in_valid.next = 1 yield clk.posedge val = data_out.val print(val) assert val == 0x08 data_in.next = next(gen) data_in_valid.next = 1 yield clk.posedge val = data_out.val print(val) assert val == 0x44 data_in.next = next(gen) data_in_valid.next = 1 yield clk.posedge val = data_out.val print(val) assert val == 0x00 yield clk.posedge data_in_valid.next = 0 yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_prbs_check_prbs9.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_prbs_check */ module test_lfsr_prbs_check_prbs9; // Parameters parameter LFSR_WIDTH = 9; parameter LFSR_POLY = 9'h021; parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}; parameter LFSR_CONFIG = "FIBONACCI"; parameter REVERSE = 0; parameter INVERT = 0; parameter DATA_WIDTH = 8; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg [DATA_WIDTH-1:0] data_in = 0; reg data_in_valid = 0; // Outputs wire [DATA_WIDTH-1:0] data_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, data_in, data_in_valid ); $to_myhdl( data_out ); // dump file $dumpfile("test_lfsr_prbs_check_prbs9.lxt"); $dumpvars(0, test_lfsr_prbs_check_prbs9); end lfsr_prbs_check #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_INIT(LFSR_INIT), .LFSR_CONFIG(LFSR_CONFIG), .REVERSE(REVERSE), .INVERT(INVERT), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .clk(clk), .rst(rst), .data_in(data_in), .data_in_valid(data_in_valid), .data_out(data_out) ); endmodule ================================================ FILE: tb/test_lfsr_prbs_gen_prbs31.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os module = 'lfsr_prbs_gen' testbench = 'test_%s_prbs31' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def prbs31(state = 0x7fffffff): while True: for i in range(8): if bool(state & 0x08000000) ^ bool(state & 0x40000000): state = ((state & 0x3fffffff) << 1) | 1 else: state = (state & 0x3fffffff) << 1 yield ~state & 0xff def bench(): # Parameters LFSR_WIDTH = 31 LFSR_POLY = 0x10000001 LFSR_INIT = 0x7fffffff LFSR_CONFIG = "FIBONACCI" REVERSE = 0 INVERT = 1 DATA_WIDTH = 8 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) enable = Signal(bool(0)) # Outputs data_out = Signal(intbv(0)[DATA_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, enable=enable, data_out=data_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: test PRBS31") current_test.next = 1 gen = prbs31() enable.next = 1 yield clk.posedge yield clk.posedge enable.next = 0 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge enable.next = 1 yield clk.posedge for i in range(512): ref = next(gen) val = data_out.val print((ref, val)) assert ref == val yield clk.posedge enable.next = 0 yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_prbs_gen_prbs31.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_prbs_gen */ module test_lfsr_prbs_gen_prbs31; // Parameters parameter LFSR_WIDTH = 31; parameter LFSR_POLY = 31'h10000001; parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}; parameter LFSR_CONFIG = "FIBONACCI"; parameter REVERSE = 0; parameter INVERT = 1; parameter DATA_WIDTH = 8; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg enable = 0; // Outputs wire [DATA_WIDTH-1:0] data_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, enable ); $to_myhdl( data_out ); // dump file $dumpfile("test_lfsr_prbs_gen_prbs31.lxt"); $dumpvars(0, test_lfsr_prbs_gen_prbs31); end lfsr_prbs_gen #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_INIT(LFSR_INIT), .LFSR_CONFIG(LFSR_CONFIG), .REVERSE(REVERSE), .INVERT(INVERT), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .clk(clk), .rst(rst), .enable(enable), .data_out(data_out) ); endmodule ================================================ FILE: tb/test_lfsr_prbs_gen_prbs31_64.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os import struct module = 'lfsr_prbs_gen' testbench = 'test_%s_prbs31_64' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def prbs31(state = 0x7fffffff): while True: for i in range(8): if bool(state & 0x08000000) ^ bool(state & 0x40000000): state = ((state & 0x3fffffff) << 1) | 1 else: state = (state & 0x3fffffff) << 1 yield ~state & 0xff def bench(): # Parameters LFSR_WIDTH = 31 LFSR_POLY = 0x10000001 LFSR_INIT = 0x7fffffff LFSR_CONFIG = "FIBONACCI" REVERSE = 0 INVERT = 1 DATA_WIDTH = 64 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) enable = Signal(bool(0)) # Outputs data_out = Signal(intbv(0)[DATA_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, enable=enable, data_out=data_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: test PRBS31") current_test.next = 1 gen = prbs31() enable.next = 1 yield clk.posedge yield clk.posedge enable.next = 0 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge enable.next = 1 yield clk.posedge for i in range(512): #ref = next(gen) ref = struct.unpack('>Q', bytes([x for _, x in zip(range(8), gen)]))[0] val = data_out.val print((ref, val)) assert ref == val yield clk.posedge enable.next = 0 yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_prbs_gen_prbs31_64.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_prbs_gen */ module test_lfsr_prbs_gen_prbs31_64; // Parameters parameter LFSR_WIDTH = 31; parameter LFSR_POLY = 31'h10000001; parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}; parameter LFSR_CONFIG = "FIBONACCI"; parameter REVERSE = 0; parameter INVERT = 1; parameter DATA_WIDTH = 64; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg enable = 0; // Outputs wire [DATA_WIDTH-1:0] data_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, enable ); $to_myhdl( data_out ); // dump file $dumpfile("test_lfsr_prbs_gen_prbs31_64.lxt"); $dumpvars(0, test_lfsr_prbs_gen_prbs31_64); end lfsr_prbs_gen #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_INIT(LFSR_INIT), .LFSR_CONFIG(LFSR_CONFIG), .REVERSE(REVERSE), .INVERT(INVERT), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .clk(clk), .rst(rst), .enable(enable), .data_out(data_out) ); endmodule ================================================ FILE: tb/test_lfsr_prbs_gen_prbs9.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os module = 'lfsr_prbs_gen' testbench = 'test_%s_prbs9' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def prbs9(state = 0x1ff): while True: for i in range(8): if bool(state & 0x10) ^ bool(state & 0x100): state = ((state & 0xff) << 1) | 1 else: state = (state & 0xff) << 1 yield state & 0xff def bench(): # Parameters LFSR_WIDTH = 9 LFSR_POLY = 0x021 LFSR_INIT = 0x1ff LFSR_CONFIG = "FIBONACCI" REVERSE = 0 INVERT = 0 DATA_WIDTH = 8 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) enable = Signal(bool(0)) # Outputs data_out = Signal(intbv(0)[DATA_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, enable=enable, data_out=data_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: test PRBS9") current_test.next = 1 gen = prbs9() enable.next = 1 yield clk.posedge yield clk.posedge enable.next = 0 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge enable.next = 1 yield clk.posedge for i in range(512): ref = next(gen) val = data_out.val print((ref, val)) assert ref == val yield clk.posedge enable.next = 0 yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_prbs_gen_prbs9.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_prbs_gen */ module test_lfsr_prbs_gen_prbs9; // Parameters parameter LFSR_WIDTH = 9; parameter LFSR_POLY = 9'h021; parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}; parameter LFSR_CONFIG = "FIBONACCI"; parameter REVERSE = 0; parameter INVERT = 0; parameter DATA_WIDTH = 8; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg enable = 0; // Outputs wire [DATA_WIDTH-1:0] data_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, enable ); $to_myhdl( data_out ); // dump file $dumpfile("test_lfsr_prbs_gen_prbs9.lxt"); $dumpvars(0, test_lfsr_prbs_gen_prbs9); end lfsr_prbs_gen #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_INIT(LFSR_INIT), .LFSR_CONFIG(LFSR_CONFIG), .REVERSE(REVERSE), .INVERT(INVERT), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .clk(clk), .rst(rst), .enable(enable), .data_out(data_out) ); endmodule ================================================ FILE: tb/test_lfsr_scramble.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os import struct module = 'lfsr_scramble' testbench = 'test_%s' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def scramble_64b66b(data, state=0x3ffffffffffffff): data_out = bytearray() for d in data: b = 0 for i in range(8): if bool(state & (1<<38)) ^ bool(state & (1<<57)) ^ bool(d & (1 << i)): state = ((state & 0x1ffffffffffffff) << 1) | 1 b = b | (1 << i) else: state = (state & 0x1ffffffffffffff) << 1 data_out += bytearray([b]) return data_out def chunks(l, n): """Yield successive n-sized chunks from l.""" for i in range(0, len(l), n): yield l[i:i+n] def bench(): # Parameters LFSR_WIDTH = 58 LFSR_POLY = 0x8000000001 LFSR_INIT = 0x3ffffffffffffff LFSR_CONFIG = "FIBONACCI" REVERSE = 1 DATA_WIDTH = 8 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) data_in = Signal(intbv(0)[DATA_WIDTH:]) data_in_valid = Signal(bool(0)) # Outputs data_out = Signal(intbv(0)[DATA_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, data_in=data_in, data_in_valid=data_in_valid, data_out=data_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: block") current_test.next = 1 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge block = bytes(range(256)) scr = scramble_64b66b(block) for i in range(len(block)): data_in.next = block[i] data_in_valid.next = 1 yield clk.posedge if i > 0: ref = scr[i-1] print(hex(data_out)) print(hex(ref)) assert data_out == ref i += 1 data_in_valid.next = 0 yield clk.posedge yield delay(100) raise StopSimulation return instances() def test_bench(): sim = Simulation(bench()) sim.run() if __name__ == '__main__': print("Running test...") test_bench() ================================================ FILE: tb/test_lfsr_scramble.v ================================================ /* Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `timescale 1ns / 1ps /* * Testbench for lfsr_scramble */ module test_lfsr_scramble; // Parameters parameter LFSR_WIDTH = 58; parameter LFSR_POLY = 58'h8000000001; parameter LFSR_INIT = {LFSR_WIDTH{1'b1}}; parameter LFSR_CONFIG = "FIBONACCI"; parameter REVERSE = 1; parameter DATA_WIDTH = 8; parameter STYLE = "AUTO"; // Inputs reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; reg [DATA_WIDTH-1:0] data_in = 0; reg data_in_valid = 0; // Outputs wire [DATA_WIDTH-1:0] data_out; initial begin // myhdl integration $from_myhdl( clk, rst, current_test, data_in, data_in_valid ); $to_myhdl( data_out ); // dump file $dumpfile("test_lfsr_scramble.lxt"); $dumpvars(0, test_lfsr_scramble); end lfsr_scramble #( .LFSR_WIDTH(LFSR_WIDTH), .LFSR_POLY(LFSR_POLY), .LFSR_INIT(LFSR_INIT), .LFSR_CONFIG(LFSR_CONFIG), .REVERSE(REVERSE), .DATA_WIDTH(DATA_WIDTH), .STYLE(STYLE) ) UUT ( .clk(clk), .rst(rst), .data_in(data_in), .data_in_valid(data_in_valid), .data_out(data_out) ); endmodule ================================================ FILE: tb/test_lfsr_scramble_64.py ================================================ #!/usr/bin/env python """ Copyright (c) 2016 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from myhdl import * import os import struct module = 'lfsr_scramble' testbench = 'test_%s_64' % module srcs = [] srcs.append("../rtl/%s.v" % module) srcs.append("../rtl/lfsr.v") srcs.append("%s.v" % testbench) src = ' '.join(srcs) build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def scramble_64b66b(data, state=0x3ffffffffffffff): data_out = bytearray() for d in data: b = 0 for i in range(8): if bool(state & (1<<38)) ^ bool(state & (1<<57)) ^ bool(d & (1 << i)): state = ((state & 0x1ffffffffffffff) << 1) | 1 b = b | (1 << i) else: state = (state & 0x1ffffffffffffff) << 1 data_out += bytearray([b]) return data_out def chunks(l, n): """Yield successive n-sized chunks from l.""" for i in range(0, len(l), n): yield l[i:i+n] def bench(): # Parameters LFSR_WIDTH = 58 LFSR_POLY = 0x8000000001 LFSR_INIT = 0x3ffffffffffffff LFSR_CONFIG = "FIBONACCI" REVERSE = 1 DATA_WIDTH = 64 STYLE = "AUTO" # Inputs clk = Signal(bool(0)) rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) data_in = Signal(intbv(0)[DATA_WIDTH:]) data_in_valid = Signal(bool(0)) # Outputs data_out = Signal(intbv(0)[DATA_WIDTH:]) # DUT if os.system(build_cmd): raise Exception("Error running build command") dut = Cosimulation( "vvp -m myhdl %s.vvp -lxt2" % testbench, clk=clk, rst=rst, current_test=current_test, data_in=data_in, data_in_valid=data_in_valid, data_out=data_out ) @always(delay(4)) def clkgen(): clk.next = not clk @instance def check(): yield delay(100) yield clk.posedge rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge yield delay(100) yield clk.posedge # testbench stimulus yield clk.posedge print("test 1: block") current_test.next = 1 rst.next = 1 yield clk.posedge rst.next = 0 yield clk.posedge block = bytes(range(256)) scr = scramble_64b66b(block) for i in range(0, len(block), 8): data_in.next = struct.unpack(' 0: ref = struct.unpack('= 16.1 [gh-actions] python = 3.9: py3 [testenv] deps = pytest == 7.1.3 pytest-xdist == 2.5.0 pytest-split == 0.8.0 cocotb == 1.7.0 cocotb-test == 0.2.2 commands = pytest -n auto {posargs} # pytest configuration [pytest] testpaths = tb addopts = --ignore-glob=tb/test_*.py --import-mode importlib