OpenCores
URL https://opencores.org/ocsvn/spi/spi/trunk

Subversion Repositories spi

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 5 to Rev 6
    Reverse comparison

Rev 5 → Rev 6

/tags/rel_1/doc/spi.pdf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
tags/rel_1/doc/spi.pdf Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: tags/rel_1/doc/src/spi.doc =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: tags/rel_1/doc/src/spi.doc =================================================================== --- tags/rel_1/doc/src/spi.doc (nonexistent) +++ tags/rel_1/doc/src/spi.doc (revision 6)
tags/rel_1/doc/src/spi.doc Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: tags/rel_1/bench/verilog/tb_spi_top.v =================================================================== --- tags/rel_1/bench/verilog/tb_spi_top.v (nonexistent) +++ tags/rel_1/bench/verilog/tb_spi_top.v (revision 6) @@ -0,0 +1,322 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// 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; + + parameter SPI_RX = 4'h0; + parameter SPI_TX = 4'h0; + parameter SPI_CTRL = 4'h4; + parameter SPI_DEVIDE = 4'h8; + parameter SPI_SS = 4'hc; + + // 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; + + // 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_DEVIDE, 32'h05); // set devider register + i_wb_master.wb_write(0, SPI_TX, 32'h5a); // set tx register to 0x5a + i_wb_master.wb_write(0, SPI_CTRL, 32'h40); // 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_DEVIDE, 32'h05); // verify devider register + i_wb_master.wb_cmp(0, SPI_TX, 32'h5a); // verify tx register + i_wb_master.wb_cmp(0, SPI_CTRL, 32'h40); // 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_wb_master.wb_write(0, SPI_CTRL, 32'h41); // set 8 bit transfer, start transfer + + $display("status: %t generate transfer: 8 bit (0x0000005a), msb first, tx posedge, rx negedge", $time); + + // Check bsy bit + i_wb_master.wb_read(0, SPI_CTRL, q); + while (q[0]) + i_wb_master.wb_read(1, SPI_CTRL, q); + + if (i_spi_slave.data == 32'h5a) + $display("status: %t transfer completed: 0x0000005a == 0x%x ok", $time, i_spi_slave.data); + else + $display("status: %t transfer completed: 0x0000005a != 0x%x nok", $time, i_spi_slave.data); + + i_spi_slave.rx_negedge = 1'b0; + i_wb_master.wb_write(0, SPI_TX, 32'ha5); + i_wb_master.wb_write(0, SPI_CTRL, 32'h44); // set 8 bit transfer, tx negedge + i_wb_master.wb_write(0, SPI_CTRL, 32'h45); // set 8 bit transfer, tx negedge, start transfer + + $display("status: %t generate transfer: 8 bit (0x0000005a), msb first, tx negedge, rx posedge", $time); + + // Check bsy bit + i_wb_master.wb_read(0, SPI_CTRL, q); + while (q[0]) + i_wb_master.wb_read(1, SPI_CTRL, q); + + if (i_spi_slave.data == 32'h5aa5) + $display("status: %t transfer completed: 0x00005aa5 == 0x%x ok", $time, i_spi_slave.data); + else + $display("status: %t transfer completed: 0x00005aa5 != 0x%x nok", $time, i_spi_slave.data); + + i_spi_slave.rx_negedge = 1'b0; + i_wb_master.wb_write(0, SPI_TX, 32'h5aa5); + i_wb_master.wb_write(0, SPI_CTRL, 32'h184); // set 16 bit transfer, tx negedge, lsb + i_wb_master.wb_write(0, SPI_CTRL, 32'h185); // set 16 bit transfer, tx negedge, start transfer + + $display("status: %t generate transfer: 16 bit (0x00005aa5), lsb first, tx negedge, rx posedge", $time); + + // Check bsy bit + i_wb_master.wb_read(0, SPI_CTRL, q); + while (q[0]) + i_wb_master.wb_read(1, SPI_CTRL, q); + + + if (i_spi_slave.data == 32'h5aa5a55a) + $display("status: %t transfer completed: 0x5aa5a55a == 0x%x ok", $time, i_spi_slave.data); + else + $display("status: %t transfer completed: 0x5aa5a55a != 0x%x nok", $time, i_spi_slave.data); + + i_spi_slave.rx_negedge = 1'b0; + i_spi_slave.tx_negedge = 1'b1; + i_wb_master.wb_write(0, SPI_TX, 32'h55); + i_wb_master.wb_write(0, SPI_CTRL, 32'h144); // set 8 bit transfer, tx negedge, lsb + i_wb_master.wb_write(0, SPI_CTRL, 32'h145); // set 8 bit transfer, tx negedge, start transfer + + $display("status: %t generate transfer: 8 bit (0x000000a5), lsb first, tx negedge, rx posedge", $time); + + // Check bsy bit + i_wb_master.wb_read(0, SPI_CTRL, q); + while (q[0]) + i_wb_master.wb_read(1, SPI_CTRL, q); + + i_wb_master.wb_read(1, SPI_RX, q); + + if (i_spi_slave.data == 32'ha5a55aaa && q == 32'h00000055) + $display("status: %t transfer completed: 0xa5a55aaa == 0x%x 0x0000005a == 0x%x ok", $time, i_spi_slave.data, q); + else if (i_spi_slave.data == 32'ha5a55aaa) + $display("status: %t transfer completed: 0xa5a55aaa == 0x%x 0x0000005a != 0x%x nok", $time, i_spi_slave.data, q); + else if (q == 32'h0000005a) + $display("status: %t transfer completed: 0xa5a55aaa != 0x%x 0x0000005a == 0x%x nok", $time, i_spi_slave.data, q); + else + $display("status: %t transfer completed: 0xa5a55aaa != 0x%x 0x0000005a != 0x%x nok", $time, i_spi_slave.data, q); + + i_spi_slave.rx_negedge = 1'b1; + i_spi_slave.tx_negedge = 1'b0; + i_wb_master.wb_write(0, SPI_TX, 32'haa); + i_wb_master.wb_write(0, SPI_CTRL, 32'h142); // set 8 bit transfer, rx negedge, lsb + i_wb_master.wb_write(0, SPI_CTRL, 32'h143); // set 8 bit transfer, rx negedge, start transfer + + $display("status: %t generate transfer: 8 bit (0x000000aa), lsb first, tx posedge, rx negedge", $time); + + // Check bsy bit + i_wb_master.wb_read(0, SPI_CTRL, q); + while (q[0]) + i_wb_master.wb_read(1, SPI_CTRL, q); + + i_wb_master.wb_read(1, SPI_RX, q); + + if (i_spi_slave.data == 32'ha55aaa55 && q == 32'h000000a5) + $display("status: %t transfer completed: 0xa55aaa55 == 0x%x 0x000000a5 == 0x%x ok", $time, i_spi_slave.data, q); + else if (i_spi_slave.data == 32'ha55aaa55) + $display("status: %t transfer completed: 0xa55aaa55 == 0x%x 0x000000a5 != 0x%x nok", $time, i_spi_slave.data, q); + else if (q == 32'h000000a5) + $display("status: %t transfer completed: 0xa55aaa55 != 0x%x 0x000000a5 == 0x%x nok", $time, i_spi_slave.data, q); + else + $display("status: %t transfer completed: 0xa55aaa55 != 0x%x 0x000000a5 != 0x%x nok", $time, i_spi_slave.data, q); + + i_spi_slave.rx_negedge = 1'b1; + i_spi_slave.tx_negedge = 1'b0; + i_wb_master.wb_write(0, SPI_TX, 32'haa55); + i_wb_master.wb_write(0, SPI_CTRL, 32'h82); // set 16 bit transfer, rx negedge + i_wb_master.wb_write(0, SPI_CTRL, 32'h83); // set 16 bit transfer, rx negedge, start transfer + + $display("status: %t generate transfer: 8 bit (0x0000aa55), msb first, tx posedge, rx negedge", $time); + + // Check bsy bit + i_wb_master.wb_read(0, SPI_CTRL, q); + while (q[0]) + i_wb_master.wb_read(1, SPI_CTRL, q); + + i_wb_master.wb_read(1, SPI_RX, q); + + if (i_spi_slave.data == 32'haa55aa55 && q == 32'h0000a55a) + $display("status: %t transfer completed: 0xaa55aa55 == 0x%x 0x0000a55a == 0x%x ok", $time, i_spi_slave.data, q); + else if (i_spi_slave.data == 32'haa55aa55) + $display("status: %t transfer completed: 0xaa55aa55 == 0x%x 0x0000a55a != 0x%x nok", $time, i_spi_slave.data, q); + else if (q == 32'h0000a55a) + $display("status: %t transfer completed: 0xaa55aa55 != 0x%x 0x0000a55a == 0x%x nok", $time, i_spi_slave.data, q); + else + $display("status: %t transfer completed: 0xaa55aa55 != 0x%x 0x0000a55a != 0x%x nok", $time, i_spi_slave.data, q); + + i_spi_slave.rx_negedge = 1'b1; + i_spi_slave.tx_negedge = 1'b1; + i_wb_master.wb_write(0, SPI_TX, 32'haa55a5a5); + i_wb_master.wb_write(0, SPI_CTRL, 32'h200); // set 32 bit transfer, ie + i_wb_master.wb_write(0, SPI_CTRL, 32'h201); // set 32 bit transfer, start transfer + + $display("status: %t generate transfer: 32 bit (0xaa55a5a5), msb first, tx negedge, rx negedge", $time); + + // Check interrupt signal + while (!int) + @(posedge clk); + + i_wb_master.wb_read(1, SPI_RX, q); + + @(posedge clk); + if (int) + $display("status: %t transfer completed: interrupt still active nok", $time, i_spi_slave.data, q); + + if (i_spi_slave.data == 32'haa55a5a5 && q == 32'h552ad52a) + $display("status: %t transfer completed: 0xaa55a5a5 == 0x%x 0x552ad52a == 0x%x ok", $time, i_spi_slave.data, q); + else if (i_spi_slave.data == 32'haa55a5a5) + $display("status: %t transfer completed: 0xaa55a5a5 == 0x%x 0x552ad52a != 0x%x nok", $time, i_spi_slave.data, q); + else if (q == 32'h552ad52a) + $display("status: %t transfer completed: 0xaa55a5a5 != 0x%x 0x552ad52a == 0x%x nok", $time, i_spi_slave.data, q); + else + $display("status: %t transfer completed: 0xaa55a5a5 != 0x%x 0x552ad52a != 0x%x nok", $time, i_spi_slave.data, q); + + i_spi_slave.rx_negedge = 1'b0; + i_spi_slave.tx_negedge = 1'b0; + i_wb_master.wb_write(0, SPI_CTRL, 32'h306); // set 32 bit transfer, ie, lsb, rx negedge, tx negedge + i_wb_master.wb_write(0, SPI_CTRL, 32'h307); // set 32 bit transfer, start transfer + + $display("status: %t generate transfer: 32 bit (0xaa55a5a5), msb first, tx negedge, rx negedge", $time); + + // Check interrupt signal + while (!int) + @(posedge clk); + + i_wb_master.wb_read(1, SPI_RX, q); + + @(posedge clk); + if (int) + $display("status: %t transfer completed: interrupt still active nok", $time, i_spi_slave.data, q); + + if (i_spi_slave.data == 32'h54ab54aa && q == 32'ha5a5aa55) + $display("status: %t transfer completed: 0x54ab54aa == 0x%x 0xa5a5aa55 == 0x%x ok", $time, i_spi_slave.data, q); + else if (i_spi_slave.data == 32'h54ab54aa) + $display("status: %t transfer completed: 0x54ab54aa == 0x%x 0xa5a5aa55 != 0x%x nok", $time, i_spi_slave.data, q); + else if (q == 32'ha5a5aa55) + $display("status: %t transfer completed: 0x54ab54aa != 0x%x 0xa5a5aa55 == 0x%x nok", $time, i_spi_slave.data, q); + else + $display("status: %t transfer completed: 0x54ab54aa != 0x%x 0xa5a5aa55 != 0x%x nok", $time, i_spi_slave.data, q); + + $display("\n\nstatus: %t Testbench done", $time); + + #25000; // wait 25us + + $stop; + end + +endmodule + + Index: tags/rel_1/bench/verilog/wb_master_model.v =================================================================== --- tags/rel_1/bench/verilog/wb_master_model.v (nonexistent) +++ tags/rel_1/bench/verilog/wb_master_model.v (revision 6) @@ -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 + Index: tags/rel_1/bench/verilog/spi_slave_model.v =================================================================== --- tags/rel_1/bench/verilog/spi_slave_model.v (nonexistent) +++ tags/rel_1/bench/verilog/spi_slave_model.v (revision 6) @@ -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 + data <= #Tp {data[30:0], mosi}; + end + + always @(posedge(sclk && !tx_negedge) or negedge(sclk && tx_negedge)) + begin + miso <= #Tp data[31]; + end + +endmodule + Index: tags/rel_1/rtl/verilog/spi_top.v =================================================================== --- tags/rel_1/rtl/verilog/spi_top.v (nonexistent) +++ tags/rel_1/rtl/verilog/spi_top.v (revision 6) @@ -0,0 +1,233 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// 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 //// +//// //// +//// 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" +`include "timescale.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 +); + + parameter dw = 32; + parameter Tp = 1; + + // 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 [dw-1:0] wb_dat_i; // databus input + output [dw-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 [dw-1:0] wb_dat_o; + reg wb_ack_o; + reg wb_err_o; + reg wb_int_o; + + // Internal signals + reg [`SPI_DIVIDER_BIT_NB-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 [dw-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 spi_divider_sel; // divider register select + wire spi_ctrl_sel; // ctrl register select + wire spi_tx_sel; // tx 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_DEVIDE); + assign spi_ctrl_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_CTRL); + assign spi_tx_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX); + 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]) + `SPI_RX: wb_dat = {{dw-`SPI_MAX_CHAR{1'b0}}, rx}; + `SPI_CTRL: wb_dat = {{dw-`SPI_CTRL_BIT_NB{1'b0}}, ctrl}; + `SPI_DEVIDE: wb_dat = {{dw-`SPI_DIVIDER_BIT_NB{1'b0}}, divider}; + `SPI_SS: wb_dat = {{dw-`SPI_SS_NB{1'b0}}, ss}; + endcase + end + + // Wb data out + always @(posedge wb_clk_i or posedge wb_rst_i) + begin + if (wb_rst_i) + wb_dat_o <= #Tp {dw{1'b0}}; + else + wb_dat_o <= #Tp wb_dat; + end + + // Wb acknowledge + always @(posedge wb_clk_i or posedge wb_rst_i) + begin + if (wb_rst_i) + wb_ack_o <= #Tp 1'b0; + else + wb_ack_o <= #Tp wb_cyc_i & wb_stb_i & ~wb_ack_o; + end + + // Wb error + always @(posedge wb_clk_i or posedge wb_rst_i) + begin + if (wb_rst_i) + wb_err_o <= #Tp 1'b0; + else + wb_err_o <= #Tp wb_cyc_i & wb_stb_i & (wb_sel_i != 4'b1111) & ~wb_err_o; + end + + // Interrupt + always @(posedge wb_clk_i or posedge wb_rst_i) + begin + if (wb_rst_i) + wb_int_o <= #Tp 1'b0; + else if (ie && tip && last_bit && pos_edge) + wb_int_o <= #Tp 1'b1; + else if (wb_ack_o) + wb_int_o <= #Tp 1'b0; + end + + // Divider register + always @(posedge wb_clk_i or posedge wb_rst_i) + begin + if (wb_rst_i) + divider <= #Tp {`SPI_DIVIDER_BIT_NB{1'b0}}; + else if (spi_divider_sel && wb_we_i && !tip) + divider <= #Tp wb_dat_i[`SPI_DIVIDER_BIT_NB-1:0]; + end + + // Ctrl register + always @(posedge wb_clk_i or posedge wb_rst_i) + begin + if (wb_rst_i) + ctrl <= #Tp {`SPI_CTRL_BIT_NB{1'b0}}; + else if(spi_ctrl_sel && wb_we_i && !tip) + begin + ctrl[`SPI_CTRL_GO] <= #Tp wb_dat_i[`SPI_CTRL_GO] | ctrl[`SPI_CTRL_GO]; + ctrl[`SPI_CTRL_RX_NEGEDGE] <= #Tp wb_dat_i[`SPI_CTRL_RX_NEGEDGE]; + ctrl[`SPI_CTRL_TX_NEGEDGE] <= #Tp wb_dat_i[`SPI_CTRL_TX_NEGEDGE]; + ctrl[`SPI_CTRL_CHAR_LEN] <= #Tp wb_dat_i[`SPI_CTRL_CHAR_LEN]; + ctrl[`SPI_CTRL_LSB] <= #Tp wb_dat_i[`SPI_CTRL_LSB]; + ctrl[`SPI_CTRL_IE] <= #Tp wb_dat_i[`SPI_CTRL_IE]; + end + else if(tip && last_bit && pos_edge) + ctrl[`SPI_CTRL_GO] <= #Tp 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]; + + // Slave select register + always @(posedge wb_clk_i or posedge wb_rst_i) + begin + if (wb_rst_i) + ss <= #Tp {`SPI_SS_NB{1'b0}}; + else if(spi_ss_sel && wb_we_i && !tip) + ss <= #Tp wb_dat_i[`SPI_SS_NB-1:0]; + end + + assign ss_pad_o = ~ss; + + spi_clgen clgen (.clk_in(wb_clk_i), .rst(wb_rst_i), .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 && wb_we_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 + + + + + + + + + + + + + + + + + + Index: tags/rel_1/rtl/verilog/spi_clgen.v =================================================================== --- tags/rel_1/rtl/verilog/spi_clgen.v (nonexistent) +++ tags/rel_1/rtl/verilog/spi_clgen.v (revision 6) @@ -0,0 +1,107 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// 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" +`include "timescale.v" + +module spi_clgen (clk_in, rst, enable, last_clk, divider, clk_out, pos_edge, neg_edge); + + parameter Tp = 1; + + input clk_in; // input clock (system clock) + input rst; // reset + input enable; // clock enable + input last_clk; // last clock + input [`SPI_DIVIDER_BIT_NB-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_BIT_NB-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_BIT_NB{1'b0}}; + assign cnt_one = cnt == {{`SPI_DIVIDER_BIT_NB-1{1'b0}}, 1'b1}; + + // Counter counts half period + always @(posedge clk_in or posedge rst) + begin + if(rst) + cnt <= #Tp {`SPI_DIVIDER_BIT_NB{1'b1}}; + else + begin + if(!enable || cnt_zero) + cnt <= #Tp divider; + else + cnt <= #Tp cnt - {{`SPI_DIVIDER_BIT_NB-1{1'b0}}, 1'b1}; + end + end + + // clk_out is asserted every other half period + always @(posedge clk_in or posedge rst) + begin + if(rst) + clk_out <= #Tp 1'b0; + else + clk_out <= #Tp (cnt_zero && (!last_clk || clk_out)) ? ~clk_out : clk_out; + end + + // Pos and neg edge signals + always @(posedge clk_in or posedge rst) + begin + if(rst) + begin + pos_edge <= #Tp 1'b0; + neg_edge <= #Tp 1'b0; + end + else + begin + pos_edge <= #Tp (clk_out == 1'b0) && cnt_one; + neg_edge <= #Tp (clk_out == 1'b1) && cnt_one; + end + end +endmodule + Index: tags/rel_1/rtl/verilog/timescale.v =================================================================== --- tags/rel_1/rtl/verilog/timescale.v (nonexistent) +++ tags/rel_1/rtl/verilog/timescale.v (revision 6) @@ -0,0 +1,2 @@ +`timescale 1ns / 10ps + Index: tags/rel_1/rtl/verilog/spi_defines.v =================================================================== --- tags/rel_1/rtl/verilog/spi_defines.v (nonexistent) +++ tags/rel_1/rtl/verilog/spi_defines.v (revision 6) @@ -0,0 +1,89 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// 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. +// Default is 16. +// +`define SPI_DIVIDER_BIT_NB 16 + +// +// Maximum nuber of bits that can be send/received at once. Alloved values are +// 32, 16 and 8. SPI_CHAR_LEN_BITS must be also set to 5, 4 or 3 respectively. +// Default is 32. +// +`define SPI_MAX_CHAR 32 +`define SPI_CHAR_LEN_BITS 5 + +// +// Number of device select signals. +// +`define SPI_SS_NB 8 +// +// Bits of WISHBONE address used for partial decoding of SPI registers. +// +`define SPI_OFS_BITS 3:2 + +// +// Register offset +// +`define SPI_RX 0 +`define SPI_TX 0 +`define SPI_CTRL 1 +`define SPI_DEVIDE 2 +`define SPI_SS 3 + +// +// Number of bits in ctrl register +// +`define SPI_CTRL_BIT_NB 10 + +// +// Control register bit position +// +`define SPI_CTRL_IE 9 +`define SPI_CTRL_LSB 8 +`define SPI_CTRL_CHAR_LEN 7:3 +`define SPI_CTRL_TX_NEGEDGE 2 +`define SPI_CTRL_RX_NEGEDGE 1 +`define SPI_CTRL_GO 0 + + Index: tags/rel_1/rtl/verilog/spi_shift.v =================================================================== --- tags/rel_1/rtl/verilog/spi_shift.v (nonexistent) +++ tags/rel_1/rtl/verilog/spi_shift.v (revision 6) @@ -0,0 +1,136 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// 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" +`include "timescale.v" + +module spi_shift (clk, rst, latch, len, lsb, go, + pos_edge, neg_edge, rx_negedge, tx_negedge, + tip, last, + p_in, p_out, s_clk, s_in, s_out); + + parameter Tp = 1; + + input clk; // system clock + input rst; // reset + input latch; // latch signal 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 [`SPI_MAX_CHAR-1: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 or posedge rst) + begin + if(rst) + cnt <= #Tp {`SPI_CHAR_LEN_BITS+1{1'b0}}; + else + begin + if(tip) + cnt <= #Tp pos_edge ? (cnt - {{`SPI_CHAR_LEN_BITS{1'b0}}, 1'b1}) : cnt; + else + cnt <= #Tp !(|len) ? {1'b1, {`SPI_CHAR_LEN_BITS{1'b0}}} : {1'b0, len}; + end + end + + // Transfer in progress + always @(posedge clk or posedge rst) + begin + if(rst) + tip <= #Tp 1'b0; + else if(go && ~tip) + tip <= #Tp 1'b1; + else if(tip && last && pos_edge) + tip <= #Tp 1'b0; + end + + // Sending bits to the line + always @(posedge clk or posedge rst) + begin + if (rst) + s_out <= #Tp 1'b0; + else + s_out <= #Tp (tx_clk || !tip) ? data[tx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] : s_out; + end + + // Receiving bits from the line + always @(posedge clk or posedge rst) + begin + if (rst) + data <= #Tp {`SPI_MAX_CHAR{1'b0}}; + else if (latch && !tip) + data <= #Tp p_in; + else + data[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] <= #Tp rx_clk ? s_in : data[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]]; + end + +endmodule + Index: tags/rel_1/sim/run/sim =================================================================== --- tags/rel_1/sim/run/sim (nonexistent) +++ tags/rel_1/sim/run/sim (revision 6) @@ -0,0 +1,14 @@ +ncprep \ + ../../bench/verilog/tb_spi_top.v \ + ../../bench/verilog/wb_master_model.v \ + ../../bench/verilog/spi_slave_model.v \ + ../../rtl/verilog/spi_top.v \ + ../../rtl/verilog/spi_clgen.v \ + ../../rtl/verilog/spi_shift.v \ + +incdir+../../rtl/verilog/ \ + +mess \ + +access+r \ + +notimingchecks \ + +overwrite \ + +ncsimargs+"-errormax 10" \ + +tcl+"./tcl.scr"
tags/rel_1/sim/run/sim Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tags/rel_1/sim/run/tcl.scr =================================================================== --- tags/rel_1/sim/run/tcl.scr (nonexistent) +++ tags/rel_1/sim/run/tcl.scr (revision 6) @@ -0,0 +1,5 @@ +database -open waves -into ../out/wave/spi -default +probe -create -shm tb_spi_top -all -variables -depth 8 +stop -create -time 25000000 -relative +run +quit

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.