Merge FPGA repository back into UHD repository

The FPGA codebase was removed from the UHD repository in 2014 to reduce
the size of the repository. However, over the last half-decade, the
split between the repositories has proven more burdensome than it has
been helpful. By merging the FPGA code back, it will be possible to
create atomic commits that touch both FPGA and UHD codebases. Continuous
integration testing is also simplified by merging the repositories,
because it was previously difficult to automatically derive the correct
UHD branch when testing a feature branch on the FPGA repository.

This commit also updates the license files and paths therein.

We are therefore merging the repositories again. Future development for
FPGA code will happen in the same repository as the UHD host code and
MPM code.

== Original Codebase and Rebasing ==

The original FPGA repository will be hosted for the foreseeable future
at its original local location: https://github.com/EttusResearch/fpga/

It can be used for bisecting, reference, and a more detailed history.

The final commit from said repository to be merged here is
05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as
v4.0.0.0-pre-uhd-merge.

If you have changes in the FPGA repository that you want to rebase onto
the UHD repository, simply run the following commands:

- Create a directory to store patches (this should be an empty
  directory):

    mkdir ~/patches

- Now make sure that your FPGA codebase is based on the same state as
  the code that was merged:

    cd src/fpga # Or wherever your FPGA code is stored
    git rebase v4.0.0.0-pre-uhd-merge

  Note: The rebase command may look slightly different depending on what
  exactly you're trying to rebase.

- Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge:

    git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches

  Note: Make sure that only patches are stored in your output directory.
  It should otherwise be empty. Make sure that you picked the correct
  range of commits, and only commits you wanted to rebase were exported
  as patch files.

- Go to the UHD repository and apply the patches:

    cd src/uhd # Or wherever your UHD repository is stored
    git am --directory fpga ~/patches/*
    rm -rf ~/patches # This is for cleanup

== Contributors ==

The following people have contributed mainly to these files (this list
is not complete):

Co-authored-by: Alex Williams <alex.williams@ni.com>
Co-authored-by: Andrej Rode <andrej.rode@ettus.com>
Co-authored-by: Ashish Chaudhari <ashish@ettus.com>
Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Derek Kozel <derek.kozel@ettus.com>
Co-authored-by: EJ Kreinar <ej@he360.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Ian Buckley <ian.buckley@gmail.com>
Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Jon Kiser <jon.kiser@ni.com>
Co-authored-by: Josh Blum <josh@joshknows.com>
Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Matt Ettus <matt@ettus.com>
Co-authored-by: Michael West <michael.west@ettus.com>
Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com>
Co-authored-by: Nick Foster <nick@ettus.com>
Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Paul David <paul.david@ettus.com>
Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com>
Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com>
Co-authored-by: Sylvain Munaut <tnt@246tNt.com>
Co-authored-by: Trung Tran <trung.tran@ettus.com>
Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>


Original-commit: bafa9d95453387814ef25e6b6256ba8db2df612f
This commit is contained in:
Martin Braun
2020-01-28 09:35:36 -08:00
co-authored by Alex Williams Andrej Rode Ashish Chaudhari Ben Hilburn Ciro Nishiguchi Daniel Jepson Derek Kozel EJ Kreinar Humberto Jimenez Ian Buckley Jörg Hofrichter Jon Kiser Josh Blum Jonathon Pendlum Matt Ettus Michael West Moritz Fischer Nick Foster Nicolas Cuervo Paul Butler Paul David Ryan Marlow Sugandha Gupta Sylvain Munaut Trung Tran Vidush Vishwanath Wade Fife
parent 74893643ca
commit 6b67702ad7
2157 changed files with 1282567 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
#
# Copyright 2013 Ettus Research LLC
#
##################################################
# Control Lib Sources
##################################################
WB_SPI_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/wb_spi/, \
rtl/verilog/spi_clgen.v \
rtl/verilog/spi_defines.v \
rtl/verilog/spi_shift.v \
rtl/verilog/spi_top16.v \
rtl/verilog/spi_top.v \
))
@@ -0,0 +1,73 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_slave_model.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "timescale.v"
module spi_slave_model (rst, ss, sclk, mosi, miso);
input rst; // reset
input ss; // slave select
input sclk; // serial clock
input mosi; // master out slave in
output miso; // master in slave out
reg miso;
reg rx_negedge; // slave receiving on negedge
reg tx_negedge; // slave transmiting on negedge
reg [31:0] data; // data register
parameter Tp = 1;
always @(posedge(sclk && !rx_negedge) or negedge(sclk && rx_negedge) or rst)
begin
if (rst)
data <= #Tp 32'b0;
else if (!ss)
data <= #Tp {data[30:0], mosi};
end
always @(posedge(sclk && !tx_negedge) or negedge(sclk && tx_negedge))
begin
miso <= #Tp data[31];
end
endmodule
+339
View File
@@ -0,0 +1,339 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// tb_spi_top.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// Based on: ////
//// - i2c/bench/verilog/tst_bench_top.v ////
//// Copyright (C) 2001 Richard Herveille ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "timescale.v"
module tb_spi_top();
reg clk;
reg rst;
wire [31:0] adr;
wire [31:0] dat_i, dat_o;
wire we;
wire [3:0] sel;
wire stb;
wire cyc;
wire ack;
wire err;
wire int;
wire [7:0] ss;
wire sclk;
wire mosi;
wire miso;
reg [31:0] q;
reg [31:0] q1;
reg [31:0] q2;
reg [31:0] q3;
reg [31:0] result;
parameter SPI_RX_0 = 5'h0;
parameter SPI_RX_1 = 5'h4;
parameter SPI_RX_2 = 5'h8;
parameter SPI_RX_3 = 5'hc;
parameter SPI_TX_0 = 5'h0;
parameter SPI_TX_1 = 5'h4;
parameter SPI_TX_2 = 5'h8;
parameter SPI_TX_3 = 5'hc;
parameter SPI_CTRL = 5'h10;
parameter SPI_DIVIDE = 5'h14;
parameter SPI_SS = 5'h18;
// Generate clock
always #5 clk = ~clk;
// Wishbone master model
wb_master_model #(32, 32) i_wb_master (
.clk(clk), .rst(rst),
.adr(adr), .din(dat_i), .dout(dat_o),
.cyc(cyc), .stb(stb), .we(we), .sel(sel), .ack(ack), .err(err), .rty(1'b0)
);
// SPI master core
spi_top i_spi_top (
.wb_clk_i(clk), .wb_rst_i(rst),
.wb_adr_i(adr[4:0]), .wb_dat_i(dat_o), .wb_dat_o(dat_i),
.wb_sel_i(sel), .wb_we_i(we), .wb_stb_i(stb),
.wb_cyc_i(cyc), .wb_ack_o(ack), .wb_err_o(err), .wb_int_o(int),
.ss_pad_o(ss), .sclk_pad_o(sclk), .mosi_pad_o(mosi), .miso_pad_i(miso)
);
// SPI slave model
spi_slave_model i_spi_slave (
.rst(rst), .ss(ss[0]), .sclk(sclk), .mosi(mosi), .miso(miso)
);
initial
begin
$display("\nstatus: %t Testbench started\n\n", $time);
$dumpfile("bench.vcd");
$dumpvars(1, tb_spi_top);
$dumpvars(1, tb_spi_top.i_spi_slave);
// Initial values
clk = 0;
i_spi_slave.rx_negedge = 1'b0;
i_spi_slave.tx_negedge = 1'b0;
result = 32'h0;
// Reset system
rst = 1'b0; // negate reset
#2;
rst = 1'b1; // assert reset
repeat(20) @(posedge clk);
rst = 1'b0; // negate reset
$display("status: %t done reset", $time);
@(posedge clk);
// Program core
i_wb_master.wb_write(0, SPI_DIVIDE, 32'h00); // set devider register
i_wb_master.wb_write(0, SPI_TX_0, 32'h5a); // set tx register to 0x5a
i_wb_master.wb_write(0, SPI_CTRL, 32'h208); // set 8 bit transfer
i_wb_master.wb_write(0, SPI_SS, 32'h01); // set ss 0
$display("status: %t programmed registers", $time);
i_wb_master.wb_cmp(0, SPI_DIVIDE, 32'h00); // verify devider register
i_wb_master.wb_cmp(0, SPI_TX_0, 32'h5a); // verify tx register
i_wb_master.wb_cmp(0, SPI_CTRL, 32'h208); // verify tx register
i_wb_master.wb_cmp(0, SPI_SS, 32'h01); // verify ss register
$display("status: %t verified registers", $time);
i_spi_slave.rx_negedge = 1'b1;
i_spi_slave.tx_negedge = 1'b0;
i_spi_slave.data[31:0] = 32'ha5967e5a;
i_wb_master.wb_write(0, SPI_CTRL, 32'h308); // set 8 bit transfer, start transfer
$display("status: %t generate transfer: 8 bit, msb first, tx posedge, rx negedge", $time);
// Check bsy bit
i_wb_master.wb_read(0, SPI_CTRL, q);
while (q[8])
i_wb_master.wb_read(1, SPI_CTRL, q);
i_wb_master.wb_read(1, SPI_RX_0, q);
result = result + q;
if (i_spi_slave.data[7:0] == 8'h5a && q == 32'h000000a5)
$display("status: %t transfer completed: ok", $time);
else
$display("status: %t transfer completed: nok", $time);
i_spi_slave.rx_negedge = 1'b0;
i_spi_slave.tx_negedge = 1'b1;
i_wb_master.wb_write(0, SPI_TX_0, 32'ha5);
i_wb_master.wb_write(0, SPI_CTRL, 32'h408); // set 8 bit transfer, tx negedge
i_wb_master.wb_write(0, SPI_CTRL, 32'h508); // set 8 bit transfer, tx negedge, start transfer
$display("status: %t generate transfer: 8 bit, msb first, tx negedge, rx posedge", $time);
// Check bsy bit
i_wb_master.wb_read(0, SPI_CTRL, q);
while (q[8])
i_wb_master.wb_read(1, SPI_CTRL, q);
i_wb_master.wb_read(1, SPI_RX_0, q);
result = result + q;
if (i_spi_slave.data[7:0] == 8'ha5 && q == 32'h00000096)
$display("status: %t transfer completed: ok", $time);
else
$display("status: %t transfer completed: nok", $time);
i_spi_slave.rx_negedge = 1'b0;
i_spi_slave.tx_negedge = 1'b1;
i_wb_master.wb_write(0, SPI_TX_0, 32'h5aa5);
i_wb_master.wb_write(0, SPI_CTRL, 32'hc10); // set 16 bit transfer, tx negedge, lsb
i_wb_master.wb_write(0, SPI_CTRL, 32'hd10); // set 16 bit transfer, tx negedge, start transfer
$display("status: %t generate transfer: 16 bit, lsb first, tx negedge, rx posedge", $time);
// Check bsy bit
i_wb_master.wb_read(0, SPI_CTRL, q);
while (q[8])
i_wb_master.wb_read(1, SPI_CTRL, q);
i_wb_master.wb_read(1, SPI_RX_0, q);
result = result + q;
if (i_spi_slave.data[15:0] == 16'ha55a && q == 32'h00005a7e)
$display("status: %t transfer completed: ok", $time);
else
$display("status: %t transfer completed: nok", $time);
i_spi_slave.rx_negedge = 1'b1;
i_spi_slave.tx_negedge = 1'b0;
i_wb_master.wb_write(0, SPI_TX_0, 32'h76543210);
i_wb_master.wb_write(0, SPI_TX_1, 32'hfedcba98);
i_wb_master.wb_write(0, SPI_CTRL, 32'h1a40); // set 64 bit transfer, rx negedge, lsb
i_wb_master.wb_write(0, SPI_CTRL, 32'h1b40); // set 64 bit transfer, rx negedge, start transfer
$display("status: %t generate transfer: 64 bit, lsb first, tx posedge, rx negedge", $time);
// Check bsy bit
i_wb_master.wb_read(0, SPI_CTRL, q);
while (q[8])
i_wb_master.wb_read(1, SPI_CTRL, q);
i_wb_master.wb_read(1, SPI_RX_0, q);
result = result + q;
i_wb_master.wb_read(1, SPI_RX_1, q1);
result = result + q1;
if (i_spi_slave.data == 32'h195d3b7f && q == 32'h5aa5a55a && q1 == 32'h76543210)
$display("status: %t transfer completed: ok", $time);
else
$display("status: %t transfer completed: nok", $time);
i_spi_slave.rx_negedge = 1'b0;
i_spi_slave.tx_negedge = 1'b1;
i_wb_master.wb_write(0, SPI_TX_0, 32'hccddeeff);
i_wb_master.wb_write(0, SPI_TX_1, 32'h8899aabb);
i_wb_master.wb_write(0, SPI_TX_2, 32'h44556677);
i_wb_master.wb_write(0, SPI_TX_3, 32'h00112233);
i_wb_master.wb_write(0, SPI_CTRL, 32'h400);
i_wb_master.wb_write(0, SPI_CTRL, 32'h500);
$display("status: %t generate transfer: 128 bit, msb first, tx posedge, rx negedge", $time);
// Check bsy bit
i_wb_master.wb_read(0, SPI_CTRL, q);
while (q[8])
i_wb_master.wb_read(1, SPI_CTRL, q);
i_wb_master.wb_read(1, SPI_RX_0, q);
result = result + q;
i_wb_master.wb_read(1, SPI_RX_1, q1);
result = result + q1;
i_wb_master.wb_read(1, SPI_RX_2, q2);
result = result + q2;
i_wb_master.wb_read(1, SPI_RX_3, q3);
result = result + q3;
if (i_spi_slave.data == 32'hccddeeff && q == 32'h8899aabb && q1 == 32'h44556677 && q2 == 32'h00112233 && q3 == 32'h195d3b7f)
$display("status: %t transfer completed: ok", $time);
else
$display("status: %t transfer completed: nok", $time);
i_spi_slave.rx_negedge = 1'b0;
i_spi_slave.tx_negedge = 1'b1;
i_wb_master.wb_write(0, SPI_TX_0, 32'haa55a5a5);
i_wb_master.wb_write(0, SPI_CTRL, 32'h1420);
i_wb_master.wb_write(0, SPI_CTRL, 32'h1520);
$display("status: %t generate transfer: 32 bit, msb first, tx negedge, rx posedge, ie", $time);
// Check interrupt signal
while (!int)
@(posedge clk);
i_wb_master.wb_read(1, SPI_RX_0, q);
result = result + q;
@(posedge clk);
if (!int && i_spi_slave.data == 32'haa55a5a5 && q == 32'hccddeeff)
$display("status: %t transfer completed: ok", $time);
else
$display("status: %t transfer completed: nok", $time);
i_spi_slave.rx_negedge = 1'b1;
i_spi_slave.tx_negedge = 1'b0;
i_wb_master.wb_write(0, SPI_TX_0, 32'h01248421);
i_wb_master.wb_write(0, SPI_CTRL, 32'h3220);
i_wb_master.wb_write(0, SPI_CTRL, 32'h3320);
$display("status: %t generate transfer: 32 bit, msb first, tx posedge, rx negedge, ie, ass", $time);
while (!int)
@(posedge clk);
i_wb_master.wb_read(1, SPI_RX_0, q);
result = result + q;
@(posedge clk);
if (!int && i_spi_slave.data == 32'h01248421 && q == 32'haa55a5a5)
$display("status: %t transfer completed: ok", $time);
else
$display("status: %t transfer completed: nok", $time);
i_spi_slave.rx_negedge = 1'b1;
i_spi_slave.tx_negedge = 1'b0;
i_wb_master.wb_write(0, SPI_TX_0, 32'h1);
i_wb_master.wb_write(0, SPI_CTRL, 32'h3201);
i_wb_master.wb_write(0, SPI_CTRL, 32'h3301);
$display("status: %t generate transfer: 1 bit, msb first, tx posedge, rx negedge, ie, ass", $time);
while (!int)
@(posedge clk);
i_wb_master.wb_read(1, SPI_RX_0, q);
result = result + q;
@(posedge clk);
if (!int && i_spi_slave.data == 32'h02490843 && q == 32'h0)
$display("status: %t transfer completed: ok", $time);
else
$display("status: %t transfer completed: nok", $time);
$display("\n\nstatus: %t Testbench done", $time);
#25000; // wait 25us
$display("report (%h)", (result ^ 32'h2e8b36ab) + 32'hdeaddead);
$display("exit (%h)", result ^ 32'h2e8b36ab);
$stop;
end
endmodule
+176
View File
@@ -0,0 +1,176 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// wb_master_model.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// Based on: ////
//// - i2c/bench/verilog/wb_master_model.v ////
//// Copyright (C) 2001 Richard Herveille ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "timescale.v"
module wb_master_model(clk, rst, adr, din, dout, cyc, stb, we, sel, ack, err, rty);
parameter dwidth = 32;
parameter awidth = 32;
input clk, rst;
output [awidth -1:0] adr;
input [dwidth -1:0] din;
output [dwidth -1:0] dout;
output cyc, stb;
output we;
output [dwidth/8 -1:0] sel;
input ack, err, rty;
// Internal signals
reg [awidth -1:0] adr;
reg [dwidth -1:0] dout;
reg cyc, stb;
reg we;
reg [dwidth/8 -1:0] sel;
reg [dwidth -1:0] q;
// Memory Logic
initial
begin
adr = {awidth{1'bx}};
dout = {dwidth{1'bx}};
cyc = 1'b0;
stb = 1'bx;
we = 1'hx;
sel = {dwidth/8{1'bx}};
#1;
end
// Wishbone write cycle
task wb_write;
input delay;
integer delay;
input [awidth -1:0] a;
input [dwidth -1:0] d;
begin
// wait initial delay
repeat(delay) @(posedge clk);
// assert wishbone signal
#1;
adr = a;
dout = d;
cyc = 1'b1;
stb = 1'b1;
we = 1'b1;
sel = {dwidth/8{1'b1}};
@(posedge clk);
// wait for acknowledge from slave
while(~ack) @(posedge clk);
// negate wishbone signals
#1;
cyc = 1'b0;
stb = 1'bx;
adr = {awidth{1'bx}};
dout = {dwidth{1'bx}};
we = 1'hx;
sel = {dwidth/8{1'bx}};
end
endtask
// Wishbone read cycle
task wb_read;
input delay;
integer delay;
input [awidth -1:0] a;
output [dwidth -1:0] d;
begin
// wait initial delay
repeat(delay) @(posedge clk);
// assert wishbone signals
#1;
adr = a;
dout = {dwidth{1'bx}};
cyc = 1'b1;
stb = 1'b1;
we = 1'b0;
sel = {dwidth/8{1'b1}};
@(posedge clk);
// wait for acknowledge from slave
while(~ack) @(posedge clk);
// negate wishbone signals
#1;
cyc = 1'b0;
stb = 1'bx;
adr = {awidth{1'bx}};
dout = {dwidth{1'bx}};
we = 1'hx;
sel = {dwidth/8{1'bx}};
d = din;
end
endtask
// Wishbone compare cycle (read data from location and compare with expected data)
task wb_cmp;
input delay;
integer delay;
input [awidth -1:0] a;
input [dwidth -1:0] d_exp;
begin
wb_read (delay, a, q);
if (d_exp !== q)
$display("Data compare error. Received %h, expected %h at time %t", q, d_exp, $time);
end
endtask
endmodule
Binary file not shown.
BIN
View File
Binary file not shown.
+105
View File
@@ -0,0 +1,105 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_clgen.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "spi_defines.v"
module spi_clgen (clk_in, rst, go, enable, last_clk, divider, clk_out, pos_edge, neg_edge);
input clk_in; // input clock (system clock)
input rst; // reset
input enable; // clock enable
input go; // start transfer
input last_clk; // last clock
input [`SPI_DIVIDER_LEN-1:0] divider; // clock divider (output clock is divided by this value)
output clk_out; // output clock
output pos_edge; // pulse marking positive edge of clk_out
output neg_edge; // pulse marking negative edge of clk_out
reg clk_out;
reg pos_edge;
reg neg_edge;
reg [`SPI_DIVIDER_LEN-1:0] cnt; // clock counter
wire cnt_zero; // conter is equal to zero
wire cnt_one; // conter is equal to one
assign cnt_zero = cnt == {`SPI_DIVIDER_LEN{1'b0}};
assign cnt_one = cnt == {{`SPI_DIVIDER_LEN-1{1'b0}}, 1'b1};
// Counter counts half period
always @(posedge clk_in)
begin
if(rst)
cnt <= {`SPI_DIVIDER_LEN{1'b1}};
else
begin
if(!enable || cnt_zero)
cnt <= divider;
else
cnt <= cnt - {{`SPI_DIVIDER_LEN-1{1'b0}}, 1'b1};
end
end
// clk_out is asserted every other half period
always @(posedge clk_in)
begin
if(rst)
clk_out <= 1'b0;
else
clk_out <= (enable && cnt_zero && (!last_clk || clk_out)) ? ~clk_out : clk_out;
end
// Pos and neg edge signals
always @(posedge clk_in)
begin
if(rst)
begin
pos_edge <= 1'b0;
neg_edge <= 1'b0;
end
else
begin
pos_edge <= (enable && !clk_out && cnt_one) || (!(|divider) && clk_out) || (!(|divider) && go && !enable);
neg_edge <= (enable && clk_out && cnt_one) || (!(|divider) && !clk_out && enable);
end
end
endmodule
+161
View File
@@ -0,0 +1,161 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_define.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
//
// Number of bits used for devider register. If used in system with
// low frequency of system clock this can be reduced.
// Use SPI_DIVIDER_LEN for fine tuning theexact number.
//
`define SPI_DIVIDER_LEN_8
//`define SPI_DIVIDER_LEN_16
//`define SPI_DIVIDER_LEN_24
//`define SPI_DIVIDER_LEN_32
`ifdef SPI_DIVIDER_LEN_8
`define SPI_DIVIDER_LEN 8 // Can be set from 1 to 8
`endif
`ifdef SPI_DIVIDER_LEN_16
`define SPI_DIVIDER_LEN 16 // Can be set from 9 to 16
`endif
`ifdef SPI_DIVIDER_LEN_24
`define SPI_DIVIDER_LEN 24 // Can be set from 17 to 24
`endif
`ifdef SPI_DIVIDER_LEN_32
`define SPI_DIVIDER_LEN 32 // Can be set from 25 to 32
`endif
//
// Maximum nuber of bits that can be send/received at once.
// Use SPI_MAX_CHAR for fine tuning the exact number, when using
// SPI_MAX_CHAR_32, SPI_MAX_CHAR_24, SPI_MAX_CHAR_16, SPI_MAX_CHAR_8.
//
`ifndef SPI_MAX_CHAR_64
`define SPI_MAX_CHAR_128
`endif
//`define SPI_MAX_CHAR_64
//`define SPI_MAX_CHAR_32
//`define SPI_MAX_CHAR_24
//`define SPI_MAX_CHAR_16
//`define SPI_MAX_CHAR_8
`ifdef SPI_MAX_CHAR_128
`define SPI_MAX_CHAR 128 // Can only be set to 128
`define SPI_CHAR_LEN_BITS 7
`endif
`ifdef SPI_MAX_CHAR_64
`define SPI_MAX_CHAR 64 // Can only be set to 64
`define SPI_CHAR_LEN_BITS 6
`endif
`ifdef SPI_MAX_CHAR_32
`define SPI_MAX_CHAR 32 // Can be set from 25 to 32
`define SPI_CHAR_LEN_BITS 5
`endif
`ifdef SPI_MAX_CHAR_24
`define SPI_MAX_CHAR 24 // Can be set from 17 to 24
`define SPI_CHAR_LEN_BITS 5
`endif
`ifdef SPI_MAX_CHAR_16
`define SPI_MAX_CHAR 16 // Can be set from 9 to 16
`define SPI_CHAR_LEN_BITS 4
`endif
`ifdef SPI_MAX_CHAR_8
`define SPI_MAX_CHAR 8 // Can be set from 1 to 8
`define SPI_CHAR_LEN_BITS 3
`endif
//
// Number of device select signals. Use SPI_SS_NB for fine tuning the
// exact number.
//
//`define SPI_SS_NB_8
`define SPI_SS_NB_16
//`define SPI_SS_NB_24
//`define SPI_SS_NB_32
`ifdef SPI_SS_NB_8
`define SPI_SS_NB 8 // Can be set from 1 to 8
`endif
`ifdef SPI_SS_NB_16
`define SPI_SS_NB 16 // Can be set from 9 to 16
`endif
`ifdef SPI_SS_NB_24
`define SPI_SS_NB 24 // Can be set from 17 to 24
`endif
`ifdef SPI_SS_NB_32
`define SPI_SS_NB 32 // Can be set from 25 to 32
`endif
//
// Bits of WISHBONE address used for partial decoding of SPI registers.
//
`define SPI_OFS_BITS 4:2
//
// Register offset
//
`define SPI_RX_0 0
`define SPI_RX_1 1
`define SPI_RX_2 2
`define SPI_RX_3 3
`define SPI_TX_0 0
`define SPI_TX_1 1
`define SPI_TX_2 2
`define SPI_TX_3 3
`define SPI_CTRL 4
`define SPI_DIVIDE 5
`define SPI_SS 6
//
// Number of bits in ctrl register
//
`define SPI_CTRL_BIT_NB 14
//
// Control register bit position
//
`define SPI_CTRL_ASS 13
`define SPI_CTRL_IE 12
`define SPI_CTRL_LSB 11
`define SPI_CTRL_TX_NEGEDGE 10
`define SPI_CTRL_RX_NEGEDGE 9
`define SPI_CTRL_GO 8
`define SPI_CTRL_RES_1 7
`define SPI_CTRL_CHAR_LEN 6:0
+235
View File
@@ -0,0 +1,235 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_shift.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "spi_defines.v"
module spi_shift (clk, rst, latch, byte_sel, len, lsb, go,
pos_edge, neg_edge, rx_negedge, tx_negedge,
tip, last,
p_in, p_out, s_clk, s_in, s_out);
input clk; // system clock
input rst; // reset
input [3:0] latch; // latch signal for storing the data in shift register
input [3:0] byte_sel; // byte select signals for storing the data in shift register
input [`SPI_CHAR_LEN_BITS-1:0] len; // data len in bits (minus one)
input lsb; // lbs first on the line
input go; // start stansfer
input pos_edge; // recognize posedge of sclk
input neg_edge; // recognize negedge of sclk
input rx_negedge; // s_in is sampled on negative edge
input tx_negedge; // s_out is driven on negative edge
output tip; // transfer in progress
output last; // last bit
input [31:0] p_in; // parallel in
output [`SPI_MAX_CHAR-1:0] p_out; // parallel out
input s_clk; // serial clock
input s_in; // serial in
output s_out; // serial out
reg s_out;
reg tip;
reg [`SPI_CHAR_LEN_BITS:0] cnt; // data bit count
reg [`SPI_MAX_CHAR-1:0] data; // shift register
wire [`SPI_CHAR_LEN_BITS:0] tx_bit_pos; // next bit position
wire [`SPI_CHAR_LEN_BITS:0] rx_bit_pos; // next bit position
wire rx_clk; // rx clock enable
wire tx_clk; // tx clock enable
assign p_out = data;
assign tx_bit_pos = lsb ? {!(|len), len} - cnt : cnt - {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1};
assign rx_bit_pos = lsb ? {!(|len), len} - (rx_negedge ? cnt + {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1} : cnt) :
(rx_negedge ? cnt : cnt - {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1});
assign last = !(|cnt);
assign rx_clk = (rx_negedge ? neg_edge : pos_edge) && (!last || s_clk);
assign tx_clk = (tx_negedge ? neg_edge : pos_edge) && !last;
// Character bit counter
always @(posedge clk)
begin
if(rst)
cnt <= {`SPI_CHAR_LEN_BITS+1{1'b0}};
else
begin
if(tip)
cnt <= pos_edge ? (cnt - {{`SPI_CHAR_LEN_BITS{1'b0}}, 1'b1}) : cnt;
else
cnt <= !(|len) ? {1'b1, {`SPI_CHAR_LEN_BITS{1'b0}}} : {1'b0, len};
end
end
// Transfer in progress
always @(posedge clk)
begin
if(rst)
tip <= 1'b0;
else if(go && ~tip)
tip <= 1'b1;
else if(tip && last && pos_edge)
tip <= 1'b0;
end
// Sending bits to the line
always @(posedge clk)
begin
if (rst)
s_out <= 1'b0;
else
s_out <= (tx_clk || !tip) ? data[tx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] : s_out;
end
// Receiving bits from the line
always @(posedge clk)
begin
if (rst)
data <= {`SPI_MAX_CHAR{1'b0}};
`ifdef SPI_MAX_CHAR_128
else if (latch[0] && !tip)
begin
if (byte_sel[3])
data[31:24] <= p_in[31:24];
if (byte_sel[2])
data[23:16] <= p_in[23:16];
if (byte_sel[1])
data[15:8] <= p_in[15:8];
if (byte_sel[0])
data[7:0] <= p_in[7:0];
end
else if (latch[1] && !tip)
begin
if (byte_sel[3])
data[63:56] <= p_in[31:24];
if (byte_sel[2])
data[55:48] <= p_in[23:16];
if (byte_sel[1])
data[47:40] <= p_in[15:8];
if (byte_sel[0])
data[39:32] <= p_in[7:0];
end
else if (latch[2] && !tip)
begin
if (byte_sel[3])
data[95:88] <= p_in[31:24];
if (byte_sel[2])
data[87:80] <= p_in[23:16];
if (byte_sel[1])
data[79:72] <= p_in[15:8];
if (byte_sel[0])
data[71:64] <= p_in[7:0];
end
else if (latch[3] && !tip)
begin
if (byte_sel[3])
data[127:120] <= p_in[31:24];
if (byte_sel[2])
data[119:112] <= p_in[23:16];
if (byte_sel[1])
data[111:104] <= p_in[15:8];
if (byte_sel[0])
data[103:96] <= p_in[7:0];
end
`else
`ifdef SPI_MAX_CHAR_64
else if (latch[0] && !tip)
begin
if (byte_sel[3])
data[31:24] <= p_in[31:24];
if (byte_sel[2])
data[23:16] <= p_in[23:16];
if (byte_sel[1])
data[15:8] <= p_in[15:8];
if (byte_sel[0])
data[7:0] <= p_in[7:0];
end
else if (latch[1] && !tip)
begin
if (byte_sel[3])
data[63:56] <= p_in[31:24];
if (byte_sel[2])
data[55:48] <= p_in[23:16];
if (byte_sel[1])
data[47:40] <= p_in[15:8];
if (byte_sel[0])
data[39:32] <= p_in[7:0];
end
`else
else if (latch[0] && !tip)
begin
`ifdef SPI_MAX_CHAR_8
if (byte_sel[0])
data[`SPI_MAX_CHAR-1:0] <= p_in[`SPI_MAX_CHAR-1:0];
`endif
`ifdef SPI_MAX_CHAR_16
if (byte_sel[0])
data[7:0] <= p_in[7:0];
if (byte_sel[1])
data[`SPI_MAX_CHAR-1:8] <= p_in[`SPI_MAX_CHAR-1:8];
`endif
`ifdef SPI_MAX_CHAR_24
if (byte_sel[0])
data[7:0] <= p_in[7:0];
if (byte_sel[1])
data[15:8] <= p_in[15:8];
if (byte_sel[2])
data[`SPI_MAX_CHAR-1:16] <= p_in[`SPI_MAX_CHAR-1:16];
`endif
`ifdef SPI_MAX_CHAR_32
if (byte_sel[0])
data[7:0] <= p_in[7:0];
if (byte_sel[1])
data[15:8] <= p_in[15:8];
if (byte_sel[2])
data[23:16] <= p_in[23:16];
if (byte_sel[3])
data[`SPI_MAX_CHAR-1:24] <= p_in[`SPI_MAX_CHAR-1:24];
`endif
end
`endif
`endif
else
data[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] <= rx_clk ? s_in : data[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]];
end
endmodule
+289
View File
@@ -0,0 +1,289 @@
// Modified 2010 by Matt Ettus to remove old verilog style
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_top.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
////
//// SPDX-License-Identifier: LGPL-3.0-or-later
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "spi_defines.v"
module spi_top
(
// Wishbone signals
wb_clk_i, wb_rst_i, wb_adr_i, wb_dat_i, wb_dat_o, wb_sel_i,
wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_err_o, wb_int_o,
// SPI signals
ss_pad_o, sclk_pad_o, mosi_pad_o, miso_pad_i
);
// Wishbone signals
input wb_clk_i; // master clock input
input wb_rst_i; // synchronous active high reset
input [4:0] wb_adr_i; // lower address bits
input [32-1:0] wb_dat_i; // databus input
output [32-1:0] wb_dat_o; // databus output
input [3:0] wb_sel_i; // byte select inputs
input wb_we_i; // write enable input
input wb_stb_i; // stobe/core select signal
input wb_cyc_i; // valid bus cycle input
output wb_ack_o; // bus cycle acknowledge output
output wb_err_o; // termination w/ error
output wb_int_o; // interrupt request signal output
// SPI signals
output [`SPI_SS_NB-1:0] ss_pad_o; // slave select
output sclk_pad_o; // serial clock
output mosi_pad_o; // master out slave in
input miso_pad_i; // master in slave out
reg [32-1:0] wb_dat_o;
reg wb_ack_o;
reg wb_int_o;
// Internal signals
reg [`SPI_DIVIDER_LEN-1:0] divider; // Divider register
reg [`SPI_CTRL_BIT_NB-1:0] ctrl; // Control and status register
reg [`SPI_SS_NB-1:0] ss; // Slave select register
reg [32-1:0] wb_dat; // wb data out
wire [`SPI_MAX_CHAR-1:0] rx; // Rx register
wire rx_negedge; // miso is sampled on negative edge
wire tx_negedge; // mosi is driven on negative edge
wire [`SPI_CHAR_LEN_BITS-1:0] char_len; // char len
wire go; // go
wire lsb; // lsb first on line
wire ie; // interrupt enable
wire ass; // automatic slave select
wire spi_divider_sel; // divider register select
wire spi_ctrl_sel; // ctrl register select
wire [3:0] spi_tx_sel; // tx_l register select
wire spi_ss_sel; // ss register select
wire tip; // transfer in progress
wire pos_edge; // recognize posedge of sclk
wire neg_edge; // recognize negedge of sclk
wire last_bit; // marks last character bit
// Address decoder
assign spi_divider_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_DIVIDE);
assign spi_ctrl_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_CTRL);
assign spi_tx_sel[0] = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_0);
assign spi_tx_sel[1] = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_1);
assign spi_tx_sel[2] = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_2);
assign spi_tx_sel[3] = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_3);
assign spi_ss_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_SS);
// Read from registers
always @(wb_adr_i or rx or ctrl or divider or ss)
begin
case (wb_adr_i[`SPI_OFS_BITS])
`ifdef SPI_MAX_CHAR_128
`SPI_RX_0: wb_dat = rx[31:0];
`SPI_RX_1: wb_dat = rx[63:32];
`SPI_RX_2: wb_dat = rx[95:64];
`SPI_RX_3: wb_dat = {{128-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:96]};
`else
`ifdef SPI_MAX_CHAR_64
`SPI_RX_0: wb_dat = rx[31:0];
`SPI_RX_1: wb_dat = {{64-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:32]};
`SPI_RX_2: wb_dat = 32'b0;
`SPI_RX_3: wb_dat = 32'b0;
`else
`SPI_RX_0: wb_dat = {{32-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:0]};
`SPI_RX_1: wb_dat = 32'b0;
`SPI_RX_2: wb_dat = 32'b0;
`SPI_RX_3: wb_dat = 32'b0;
`endif
`endif
`SPI_CTRL: wb_dat = {{32-`SPI_CTRL_BIT_NB{1'b0}}, ctrl};
`SPI_DIVIDE: wb_dat = {{32-`SPI_DIVIDER_LEN{1'b0}}, divider};
`SPI_SS: wb_dat = {{32-`SPI_SS_NB{1'b0}}, ss};
default: wb_dat = 32'bx;
endcase
end
// Wb data out
always @(posedge wb_clk_i)
begin
if (wb_rst_i)
wb_dat_o <= 32'b0;
else
wb_dat_o <= wb_dat;
end
// Wb acknowledge
always @(posedge wb_clk_i)
begin
if (wb_rst_i)
wb_ack_o <= 1'b0;
else
wb_ack_o <= wb_cyc_i & wb_stb_i & ~wb_ack_o;
end
// Wb error
assign wb_err_o = 1'b0;
// Interrupt
always @(posedge wb_clk_i)
begin
if (wb_rst_i)
wb_int_o <= 1'b0;
else if (ie && tip && last_bit && pos_edge)
wb_int_o <= 1'b1;
else if (wb_ack_o)
wb_int_o <= 1'b0;
end
// Divider register
always @(posedge wb_clk_i)
begin
if (wb_rst_i)
divider <= {`SPI_DIVIDER_LEN{1'b0}};
else if (spi_divider_sel && wb_we_i && !tip)
begin
`ifdef SPI_DIVIDER_LEN_8
if (wb_sel_i[0])
divider <= wb_dat_i[`SPI_DIVIDER_LEN-1:0];
`endif
`ifdef SPI_DIVIDER_LEN_16
if (wb_sel_i[0])
divider[7:0] <= wb_dat_i[7:0];
if (wb_sel_i[1])
divider[`SPI_DIVIDER_LEN-1:8] <= wb_dat_i[`SPI_DIVIDER_LEN-1:8];
`endif
`ifdef SPI_DIVIDER_LEN_24
if (wb_sel_i[0])
divider[7:0] <= wb_dat_i[7:0];
if (wb_sel_i[1])
divider[15:8] <= wb_dat_i[15:8];
if (wb_sel_i[2])
divider[`SPI_DIVIDER_LEN-1:16] <= wb_dat_i[`SPI_DIVIDER_LEN-1:16];
`endif
`ifdef SPI_DIVIDER_LEN_32
if (wb_sel_i[0])
divider[7:0] <= wb_dat_i[7:0];
if (wb_sel_i[1])
divider[15:8] <= wb_dat_i[15:8];
if (wb_sel_i[2])
divider[23:16] <= wb_dat_i[23:16];
if (wb_sel_i[3])
divider[`SPI_DIVIDER_LEN-1:24] <= wb_dat_i[`SPI_DIVIDER_LEN-1:24];
`endif
end
end
// Ctrl register
always @(posedge wb_clk_i)
begin
if (wb_rst_i)
ctrl <= {`SPI_CTRL_BIT_NB{1'b0}};
else if(spi_ctrl_sel && wb_we_i && !tip)
begin
if (wb_sel_i[0])
ctrl[7:0] <= wb_dat_i[7:0] | {7'b0, ctrl[0]};
if (wb_sel_i[1])
ctrl[`SPI_CTRL_BIT_NB-1:8] <= wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
end
else if(tip && last_bit && pos_edge)
ctrl[`SPI_CTRL_GO] <= 1'b0;
end
assign rx_negedge = ctrl[`SPI_CTRL_RX_NEGEDGE];
assign tx_negedge = ctrl[`SPI_CTRL_TX_NEGEDGE];
assign go = ctrl[`SPI_CTRL_GO];
assign char_len = ctrl[`SPI_CTRL_CHAR_LEN];
assign lsb = ctrl[`SPI_CTRL_LSB];
assign ie = ctrl[`SPI_CTRL_IE];
assign ass = ctrl[`SPI_CTRL_ASS];
// Slave select register
always @(posedge wb_clk_i)
begin
if (wb_rst_i)
ss <= {`SPI_SS_NB{1'b0}};
else if(spi_ss_sel && wb_we_i && !tip)
begin
`ifdef SPI_SS_NB_8
if (wb_sel_i[0])
ss <= wb_dat_i[`SPI_SS_NB-1:0];
`endif
`ifdef SPI_SS_NB_16
if (wb_sel_i[0])
ss[7:0] <= wb_dat_i[7:0];
if (wb_sel_i[1])
ss[`SPI_SS_NB-1:8] <= wb_dat_i[`SPI_SS_NB-1:8];
`endif
`ifdef SPI_SS_NB_24
if (wb_sel_i[0])
ss[7:0] <= wb_dat_i[7:0];
if (wb_sel_i[1])
ss[15:8] <= wb_dat_i[15:8];
if (wb_sel_i[2])
ss[`SPI_SS_NB-1:16] <= wb_dat_i[`SPI_SS_NB-1:16];
`endif
`ifdef SPI_SS_NB_32
if (wb_sel_i[0])
ss[7:0] <= wb_dat_i[7:0];
if (wb_sel_i[1])
ss[15:8] <= wb_dat_i[15:8];
if (wb_sel_i[2])
ss[23:16] <= wb_dat_i[23:16];
if (wb_sel_i[3])
ss[`SPI_SS_NB-1:24] <= wb_dat_i[`SPI_SS_NB-1:24];
`endif
end
end
assign ss_pad_o = ~((ss & {`SPI_SS_NB{tip & ass}}) | (ss & {`SPI_SS_NB{!ass}}));
spi_clgen clgen (.clk_in(wb_clk_i), .rst(wb_rst_i), .go(go), .enable(tip), .last_clk(last_bit),
.divider(divider), .clk_out(sclk_pad_o), .pos_edge(pos_edge),
.neg_edge(neg_edge));
spi_shift shift (.clk(wb_clk_i), .rst(wb_rst_i), .len(char_len[`SPI_CHAR_LEN_BITS-1:0]),
.latch(spi_tx_sel[3:0] & {4{wb_we_i}}), .byte_sel(wb_sel_i), .lsb(lsb),
.go(go), .pos_edge(pos_edge), .neg_edge(neg_edge),
.rx_negedge(rx_negedge), .tx_negedge(tx_negedge),
.tip(tip), .last(last_bit),
.p_in(wb_dat_i), .p_out(rx),
.s_clk(sclk_pad_o), .s_in(miso_pad_i), .s_out(mosi_pad_o));
endmodule
+184
View File
@@ -0,0 +1,184 @@
// Modified 2010 by Matt Ettus to remove old verilog style and
// allow 16-bit operation
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_top.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
////
//// SPDX-License-Identifier: LGPL-3.0-or-later
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "spi_defines.v"
module spi_top16
(input wb_clk_i, input wb_rst_i,
input [4:0] wb_adr_i,
input [15:0] wb_dat_i,
output reg [15:0] wb_dat_o,
input [1:0] wb_sel_i,
input wb_we_i, input wb_stb_i, input wb_cyc_i,
output reg wb_ack_o, output wb_err_o, output reg wb_int_o,
// SPI signals
output [15:0] ss_pad_o, output sclk_pad_o, output mosi_pad_o, input miso_pad_i);
// Internal signals
reg [15:0] divider; // Divider register
reg [`SPI_CTRL_BIT_NB-1:0] ctrl; // Control and status register
reg [15:0] ss; // Slave select register
reg [31:0] wb_dat; // wb data out
wire [31:0] rx; // Rx register
wire rx_negedge; // miso is sampled on negative edge
wire tx_negedge; // mosi is driven on negative edge
wire [`SPI_CHAR_LEN_BITS-1:0] char_len; // char len
wire go; // go
wire lsb; // lsb first on line
wire ie; // interrupt enable
wire ass; // automatic slave select
wire spi_divider_sel; // divider register select
wire spi_ctrl_sel; // ctrl register select
wire [3:0] spi_tx_sel; // tx_l register select
wire spi_ss_sel; // ss register select
wire tip; // transfer in progress
wire pos_edge; // recognize posedge of sclk
wire neg_edge; // recognize negedge of sclk
wire last_bit; // marks last character bit
// Address decoder
assign spi_divider_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_DIVIDE);
assign spi_ctrl_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_CTRL);
assign spi_tx_sel[0] = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_TX_0);
assign spi_tx_sel[1] = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_TX_1);
assign spi_tx_sel[2] = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_TX_2);
assign spi_tx_sel[3] = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_TX_3);
assign spi_ss_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_SS);
always @(wb_adr_i or rx or ctrl or divider or ss)
case (wb_adr_i[4:2])
`SPI_RX_0: wb_dat = rx[31:0];
`SPI_CTRL: wb_dat = {{32-`SPI_CTRL_BIT_NB{1'b0}}, ctrl};
`SPI_DIVIDE: wb_dat = {16'b0, divider};
`SPI_SS: wb_dat = {16'b0, ss};
default : wb_dat = 32'd0;
endcase // case (wb_adr_i[4:2])
always @(posedge wb_clk_i)
if (wb_rst_i)
wb_dat_o <= 32'b0;
else
wb_dat_o <= wb_adr_i[1] ? wb_dat[31:16] : wb_dat[15:0];
always @(posedge wb_clk_i)
if (wb_rst_i)
wb_ack_o <= 1'b0;
else
wb_ack_o <= wb_cyc_i & wb_stb_i & ~wb_ack_o;
assign wb_err_o = 1'b0;
// Interrupt
always @(posedge wb_clk_i)
if (wb_rst_i)
wb_int_o <= 1'b0;
else if (ie && tip && last_bit && pos_edge)
wb_int_o <= 1'b1;
else if (wb_ack_o)
wb_int_o <= 1'b0;
// Divider register
always @(posedge wb_clk_i)
if (wb_rst_i)
divider <= 16'b0;
else if (spi_divider_sel && wb_we_i && !tip && ~wb_adr_i[1])
divider <= wb_dat_i;
// Ctrl register
always @(posedge wb_clk_i)
if (wb_rst_i)
ctrl <= {`SPI_CTRL_BIT_NB{1'b0}};
else if(spi_ctrl_sel && wb_we_i && !tip && ~wb_adr_i[1])
begin
if (wb_sel_i[0])
ctrl[7:0] <= wb_dat_i[7:0] | {7'b0, ctrl[0]};
if (wb_sel_i[1])
ctrl[`SPI_CTRL_BIT_NB-1:8] <= wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
end
else if(tip && last_bit && pos_edge)
ctrl[`SPI_CTRL_GO] <= 1'b0;
assign rx_negedge = ctrl[`SPI_CTRL_RX_NEGEDGE];
assign tx_negedge = ctrl[`SPI_CTRL_TX_NEGEDGE];
assign go = ctrl[`SPI_CTRL_GO];
assign char_len = ctrl[`SPI_CTRL_CHAR_LEN];
assign lsb = ctrl[`SPI_CTRL_LSB];
assign ie = ctrl[`SPI_CTRL_IE];
assign ass = ctrl[`SPI_CTRL_ASS];
// Slave select register
always @(posedge wb_clk_i)
if (wb_rst_i)
ss <= 16'b0;
else if(spi_ss_sel && wb_we_i && !tip & ~wb_adr_i[1])
begin
if (wb_sel_i[0])
ss[7:0] <= wb_dat_i[7:0];
if (wb_sel_i[1])
ss[15:8] <= wb_dat_i[15:8];
end
assign ss_pad_o = ~((ss & {16{tip & ass}}) | (ss & {16{!ass}}));
spi_clgen clgen (.clk_in(wb_clk_i), .rst(wb_rst_i), .go(go), .enable(tip), .last_clk(last_bit),
.divider(divider[`SPI_DIVIDER_LEN-1:0]), .clk_out(sclk_pad_o), .pos_edge(pos_edge),
.neg_edge(neg_edge));
wire [3:0] new_sels = { (wb_adr_i[1] & wb_sel_i[1]), (wb_adr_i[1] & wb_sel_i[0]),
(~wb_adr_i[1] & wb_sel_i[1]), (~wb_adr_i[1] & wb_sel_i[0]) };
spi_shift shift (.clk(wb_clk_i), .rst(wb_rst_i), .len(char_len[`SPI_CHAR_LEN_BITS-1:0]),
.latch(spi_tx_sel[3:0] & {4{wb_we_i}}), .byte_sel(new_sels), .lsb(lsb),
.go(go), .pos_edge(pos_edge), .neg_edge(neg_edge),
.rx_negedge(rx_negedge), .tx_negedge(tx_negedge),
.tip(tip), .last(last_bit),
.p_in({wb_dat_i,wb_dat_i}), .p_out(rx),
.s_clk(sclk_pad_o), .s_in(miso_pad_i), .s_out(mosi_pad_o));
endmodule // spi_top16
+3
View File
@@ -0,0 +1,3 @@
spi_top.v
spi_clgen.v
spi_shift.v
+108
View File
@@ -0,0 +1,108 @@
#!/bin/csh -f
set current_par = 0
set output_waveform = 0
while ( $current_par < $# )
@ current_par = $current_par + 1
case wave:
@ output_waveform = 1
breaksw
default:
echo 'Unknown option "'$argv[$current_par]'"!'
exit
breaksw
endsw
end
echo "TEST: spi"
#echo "-CDSLIB ./cds.lib" > ncvlog.args
#echo "-HDLVAR ./hdl.var" >> ncvlog.args
echo "-MESSAGES" > ncvlog.args
echo "-INCDIR ../../../bench/verilog" >> ncvlog.args
echo "-INCDIR ../../../rtl/verilog" >> ncvlog.args
echo "-NOCOPYRIGHT" >> ncvlog.args
echo "-UPDATE" >> ncvlog.args
echo "-LOGFILE ncvlog.log" >> ncvlog.args
foreach filename ( `cat ./rtl.fl` )
echo "../../../rtl/verilog/"$filename >> ncvlog.args
end
foreach filename ( `cat ./sim.fl` )
echo "../../../bench/verilog/"$filename >> ncvlog.args
end
ncvlog -f ncvlog.args
if ($status != 0) then
echo "STATUS: failed"
exit
endif
echo "-MESSAGES" > ncelab.args
echo "-NOCOPYRIGHT" >> ncelab.args
#echo "-CDSLIB ./cds.lib" >> ncelab.args
#echo "-HDLVAR ./hdl.var" >> ncelab.args
echo "-LOGFILE ncelab.log" >> ncelab.args
echo "-SNAPSHOT worklib.tb_spi_top:v" >> ncelab.args
echo "-NOTIMINGCHECKS" >> ncelab.args
echo "-ACCESS +RWC" >> ncelab.args
echo "tb_spi_top" >> ncelab.args
ncelab -f ncelab.args
if ($status != 0) then
echo "STATUS: failed"
exit
endif
echo "-MESSAGES" > ncsim.args
echo "-NOCOPYRIGHT" >> ncsim.args
#echo "-CDSLIB ./cds.lib" >> ncsim.args
#echo "-HDLVAR ./hdl.var" >> ncsim.args
echo "-INPUT ncsim.tcl" >> ncsim.args
echo "-LOGFILE ncsim.log" >> ncsim.args
echo "worklib.tb_spi_top:v" >> ncsim.args
if ( $output_waveform ) then
echo "database -open waves -shm -into ../out/wav" > ./ncsim.tcl
echo "probe -create -database waves -shm tb_spi_top -all -depth all" >> ./ncsim.tcl
echo "stop -create -time 25000000 -relative" >> ./ncsim.tcl
echo "run" >> ./ncsim.tcl
else
echo "stop -create -time 25000000 -relative" >> ./ncsim.tcl
echo "run" > ./ncsim.tcl
endif
echo "exit" >> ncsim.tcl
ncsim -LICQUEUE -f ./ncsim.args
set exit_line_nb = `sed -n '/exit/=' < ./ncsim.log`
set dead_line_nb = 0
if ( $exit_line_nb ) then
@ dead_line_nb = $exit_line_nb - 1
set exit_line=`sed -n $exit_line_nb's/exit/&/gp' < ./ncsim.log`
set dead_line=`sed -n $dead_line_nb's/report/&/gp' < ./ncsim.log`
if ( "$dead_line" == "report (deaddead)" ) then
if ( "$exit_line" == "exit (00000000)" ) then
echo "STATUS: passed" #|tee -a ./run_sim.log 2>&1
else
echo "STATUS: failed" #|tee -a ./run_sim.log 2>&1
endif
else
echo "STATUS: failed"
endif
endif
exit
+3
View File
@@ -0,0 +1,3 @@
tb_spi_top.v
wb_master_model.v
spi_slave_model.v