diff --git a/finiteStateMachine.v b/finiteStateMachine.v new file mode 100644 index 0000000..f3f593a --- /dev/null +++ b/finiteStateMachine.v @@ -0,0 +1,117 @@ +`define WAIT 3'd0 +`define READADDRESS 3'd1 +`define WRITE 3'd3 +`define READ 3'd4 +`define READORWRITE 3'd2 + + +module fsm +( + output reg MISObuff, + output reg memWE, + output reg addrWE, + output reg srWE, + + //input posclkedge, + input spi_clk, + input spi_falling, + input cs_falling, + input rw_select +); + reg [3:0] count; + reg [2:0] state; + + initial count = 4'd0; + initial state = `WAIT; + initial MISObuff = 0; + initial memWE = 0; + initial addrWE = 0; + initial srWE = 0; + + always @(posedge cs_falling) begin + state <= `READADDRESS; + end + //always @(posedge cs) begin +// state <= `WAIT; + // end + + always @(posedge spi_clk) begin + case (state) + `WAIT: begin + MISObuff <= 0; + memWE <= 0; + addrWE <= 0; + srWE <= 0; + end + + `READADDRESS: begin + if (count == 4'd6) begin + state <= `READORWRITE; + addrWE <= 1; + count <= 0; + @(posedge spi_falling) begin + addrWE <= 0; + end + end + else + count = count + 1; + + end + + `READORWRITE: begin + if (rw_select == 0) begin + state <= `WRITE; + end + else begin + srWE <= 1; + MISObuff <= 1; + state <= `READ; + @(posedge spi_falling) begin + srWE <= 0; + end + end + end + + `WRITE: begin + if (count == 4'd7) begin + count <= 0; + memWE <= 1; + state <= `WAIT; + @(posedge spi_falling) begin + memWE <= 0; + end + end + else + count <= count + 1; + + end + + `READ: begin + srWE <= 0; + if (count == 4'd7) begin + count <= 0; + state <= `WAIT; + end + else + count <= count + 1; + end + + default: begin end + endcase + end +/* + always @(posedge negclkedge) begin + case (state) + `READORWRITE: begin + if (wr_enable == 1) begin + state <= `READ; + q3 <= 1; + buffer <=1; + end + end + default: begin end + endcase + end +*/ + +endmodule diff --git a/fsmTest.png b/fsmTest.png new file mode 100644 index 0000000..905e43a Binary files /dev/null and b/fsmTest.png differ diff --git a/fsmTest.t.v b/fsmTest.t.v new file mode 100644 index 0000000..19f1800 --- /dev/null +++ b/fsmTest.t.v @@ -0,0 +1,78 @@ +// 32-bit alu testbench + +//`timescale 1 ns / 1 ps +`include "finiteStateMachine.v" + +module testFSM(); + + reg clk, clk_fall; + reg chipSelect; + reg rw_select; + + wire MISObuff, memWE, addrWE, srWE; + + wire csFalling; + not(csFalling, chipSelect); + initial chipSelect = 1; + fsm test(MISObuff, memWE, addrWE, srWE, clk, clk_fall, csFalling, rw_select); + + // generate clock + initial clk = 0; + always begin + #10; + clk = !clk; //50 MHz clock + clk_fall = !clk; + end + + initial + #10000 $finish; + + initial begin + $dumpfile("fsm.vcd"); + $dumpvars(); + + $display(" chip select | read/write | MISObuff | memWE | addrWE | srWE | state"); + $display(); + $display("Chip Not Selected -------------------------------------------------------------------------------------"); + chipSelect=1; rw_select=0; + #30; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Not Selected -------------------------------------------------------------------------------------"); + chipSelect=1; rw_select=1; + #20; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Selected: 1 clk cycle read -------------------------------------------------------------------------------------"); + chipSelect=0; rw_select=1; + #30; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Selected: 7 clk cycles read -------------------------------------------------------------------------------------"); + #120; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Selected: 9 clk cycles read -------------------------------------------------------------------------------------"); + #40; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Not Selected -------------------------------------------------------------------------------------"); + #130; + chipSelect=1; rw_select=0; + #20; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Selected: 1 clk cycle write -------------------------------------------------------------------------------------"); + chipSelect=0; rw_select=0; + #30; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Selected: 7 clk cycles write -------------------------------------------------------------------------------------"); + #120; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Selected: 9 clk cycles write -------------------------------------------------------------------------------------"); + #40; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Selected: 16 clk cycles write -------------------------------------------------------------------------------------"); + #140; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + $display("Chip Selected: 20 clk cycles write -------------------------------------------------------------------------------------"); + #220; + $display("| %b | %b | %b | %b | %b | %b | %b", chipSelect, rw_select, MISObuff, memWE, addrWE, srWE, test.state); + end + +endmodule + diff --git a/inputconditioner.v b/inputconditioner.v index 736a866..ea6ec2e 100644 --- a/inputconditioner.v +++ b/inputconditioner.v @@ -1,9 +1,11 @@ +// TAKEN FROM LISA'S 2016 REPOSITORY //------------------------------------------------------------------------ // Input Conditioner // 1) Synchronizes input to clock domain // 2) Debounces input // 3) Creates pulses at edge transitions //------------------------------------------------------------------------ +`timescale 1 ns / 1 ps module inputconditioner ( @@ -14,25 +16,41 @@ output reg positiveedge, // 1 clk pulse at rising edge of conditioned output reg negativeedge // 1 clk pulse at falling edge of conditioned ); + initial positiveedge = 0; + initial negativeedge = 0; + initial conditioned = 0; + parameter counterwidth = 3; // Counter size, in bits, >= log2(waittime) parameter waittime = 3; // Debounce delay, in clock cycles - - reg[counterwidth-1:0] counter = 0; + + reg[counterwidth-1:0] counter = 0; //not sure what this syntax is reg synchronizer0 = 0; reg synchronizer1 = 0; - + always @(posedge clk ) begin - if(conditioned == synchronizer1) + if(conditioned == synchronizer1) begin //if conditioned is same as we thought counter <= 0; - else begin - if( counter == waittime) begin - counter <= 0; - conditioned <= synchronizer1; + positiveedge <= 0; //not sure if this should be nonblockingit + negativeedge <= 0; + end + else begin //if conditioned has changed + if( counter == waittime) begin //when debouncing is done + counter <= 0; //reset counter + conditioned <= synchronizer1; //save conditioned in synchronizer1 + positiveedge <= synchronizer1; //set negativeedge opposite + negativeedge <= !synchronizer1; //set positiveedge opposite end - else - counter <= counter+1; + else begin + counter <= counter+1; //wait for debouncing + end + end + if (counter == 0) begin + synchronizer0 <= noisysignal; + synchronizer1 <= synchronizer0; end - synchronizer0 <= noisysignal; - synchronizer1 <= synchronizer0; end + + //max glitch is 6 clock cycles + + endmodule diff --git a/shiftregister.v b/shiftregister.v index b4ec057..760d641 100644 --- a/shiftregister.v +++ b/shiftregister.v @@ -1,3 +1,4 @@ +// USING SHIFT REGISTER FROM LISA'S 2016 REPOSITORY //------------------------------------------------------------------------ // Shift Register // Parameterized width (in bits) @@ -5,6 +6,8 @@ // - serial in, parallel out // - parallel in, serial out //------------------------------------------------------------------------ +`timescale 1 ns / 1 ps +//`include "inputconditioner.v" module shiftregister #(parameter width = 8) @@ -14,12 +17,35 @@ input peripheralClkEdge, // Edge indicator input parallelLoad, // 1 = Load shift reg with parallelDataIn input [width-1:0] parallelDataIn, // Load shift reg in parallel input serialDataIn, // Load shift reg serially -output [width-1:0] parallelDataOut, // Shift reg data contents -output serialDataOut // Positive edge synchronized +output reg [width-1:0] parallelDataOut, // Shift reg data contents +output reg serialDataOut // Positive edge synchronized ); - reg [width-1:0] shiftregistermem; + reg [width-1:0] shiftregistermem; + //wire conditioned; + //wire positiveedge; + //wire negativeedge; + //inputconditioner inputc(clk, peripheralClkEdge, conditioned, positiveedge, negativeedge); + + always @(posedge clk) begin - // Your Code Here + // Parallel load will happen if parallel load is high. + // this takes priority over the serial shift + if (parallelLoad) begin // Parallel + shiftregistermem <= parallelDataIn; + end + //the shift register advances one position: serialDataIn is loaded into the LSB (Least Significant Bit), and the rest of the bits shift up by one + else begin + if (peripheralClkEdge) begin + shiftregistermem <= {{shiftregistermem[width-2:0]}, {serialDataIn}}; + end + end + + + //serialDataOut always presents the Most Significant Bit of the shift register. + serialDataOut <= shiftregistermem[width-1]; + //parallelDataOut always presents the entirety of the contents of the shift register. + parallelDataOut <= shiftregistermem; + end endmodule diff --git a/spimemory.t.v b/spimemory.t.v new file mode 100644 index 0000000..bfdca67 --- /dev/null +++ b/spimemory.t.v @@ -0,0 +1,214 @@ +// Test Bench for full SPI memory + +`include "spimemory.v" + +module testSPImem(); + + // inputs and outputs for function + reg clk; + reg spi_clk; + reg chip_select = 1; + wire miso; + reg mosi = 0; + wire[3:0] leds; + + // registers for testing + reg[6:0] address; + reg rw_select; + reg[7:0] write_data; + reg[7:0] read_data; + wire[7:0] cmd = {address, rw_select}; + reg[3:0] i = 0; + reg success = 1; + + spiMemory test(clk, spi_clk, chip_select, miso, mosi, leds); + + // generate clock + initial clk = 0; + always #1 clk = !clk; //100 MHz clock + + initial spi_clk = 0; + always #100 spi_clk = !spi_clk; //25 MHz clock + + initial + #200000 $finish; + + initial begin + $dumpfile("spimemory.vcd"); + $dumpvars(); + $display("testing SPI memory"); + +// TEST 1: write data and read it back + // initialize values to write + address = 7'd5; // set address to 5 + write_data = 8'd155; // set write data to 155 + rw_select = 0; // write first + #500; // wait at the beginning for fun + @(negedge spi_clk); //wait for negative clock edge + // start with a normal write opperation + chip_select = 0; // select chip + for (i=0; i<7; i=i+1) begin + mosi = address[6-i]; + @(negedge spi_clk); + end + mosi = rw_select; + for (i=0; i<8; i=i+1) begin + @(negedge spi_clk); + mosi = write_data[7-i]; + end + + // toggle chip select + @(negedge spi_clk); + chip_select = 1; + @(negedge spi_clk); + chip_select = 0; + + // read back data + address = 7'd5; // set address to 5 + rw_select = 1; // read + for (i=0; i<7; i=i+1) begin + mosi = address[6-i]; + @(negedge spi_clk); + end + mosi = rw_select; + @(negedge spi_clk); + for (i=0; i<8; i=i+1) begin + @(posedge spi_clk); + read_data[7-i]=miso; + end + if (read_data != 8'd155) begin + $display("Test1: write data and read it back FAILED:"); + $display("data returned is: %d", read_data); + success = 0; + end + + // toggle chip select + @(negedge spi_clk); + chip_select = 1; + @(negedge spi_clk); + chip_select = 0; +// TEST 2: write to second address, read back from both + // initialize values to write + address = 7'd120; // set address to 120 + write_data = 8'd3; // set write data to 3 + rw_select = 0; // write + // start with a normal write opperation + for (i=0; i<7; i=i+1) begin + mosi = address[6-i]; + @(negedge spi_clk); + end + mosi = rw_select; + for (i=0; i<8; i=i+1) begin + @(negedge spi_clk); + mosi = write_data[7-i]; + end + + // toggle chip select + @(negedge spi_clk); + chip_select = 1; + @(negedge spi_clk); + chip_select = 0; + + // read back data + address = 7'd5; // set address to 5 + rw_select = 1; // read + for (i=0; i<7; i=i+1) begin + mosi = address[6-i]; + @(negedge spi_clk); + end + mosi = rw_select; + @(negedge spi_clk); + for (i=0; i<8; i=i+1) begin + @(posedge spi_clk); + read_data[7-i]=miso; + end + + if (read_data != 8'd155) begin + $display("Test2: write to second address, read back both FAILED:"); + $display("data returned is: %d", read_data); + $display("original data has changed"); + success = 0; + end + + // toggle chip select + @(negedge spi_clk); + chip_select = 1; + @(negedge spi_clk); + chip_select = 0; + + // read back data + address = 7'd120; // set address to 120 + rw_select = 1; // read + for (i=0; i<7; i=i+1) begin + mosi = address[6-i]; + @(negedge spi_clk); + end + mosi = rw_select; + @(negedge spi_clk); + for (i=0; i<8; i=i+1) begin + @(posedge spi_clk); + read_data[7-i]=miso; + end + + if (read_data != 8'd3) begin + $display("Test2: write to second address, read back both FAILED:"); + $display("data returned is: %d", read_data); + $display("new address write/read back failed"); + success = 0; + end + + // toggle chip select + @(negedge spi_clk); + chip_select = 1; + @(negedge spi_clk); + chip_select = 1; + +// TEST 3: write new value to original address with cs disabled + // initialize values to write + address = 7'd5; // set address to 5 + write_data = 8'd12; // set write data to 12 + rw_select = 0; // write + // start with a normal write opperation + for (i=0; i<7; i=i+1) begin + mosi = address[6-i]; + @(negedge spi_clk); + end + mosi = rw_select; + for (i=0; i<8; i=i+1) begin + @(negedge spi_clk); + mosi = write_data[7-i]; + end + + // toggle chip select + @(negedge spi_clk); + chip_select = 1; + @(negedge spi_clk); + chip_select = 0; + + // read back data + address = 7'd5; // set address to 5 + rw_select = 1; // read + for (i=0; i<7; i=i+1) begin + mosi = address[6-i]; + @(negedge spi_clk); + end + mosi = rw_select; + @(negedge spi_clk); + for (i=0; i<8; i=i+1) begin + @(posedge spi_clk); + read_data[7-i]=miso; + end + + if (read_data != 8'd155) begin + $display("Test3: write to original addrss with chip disabled FAILED"); + $display("data returned is: %d", read_data); + $display("original data has changed"); + success = 0; + end + + if (success==1) begin + $display("All Tests Passed!"); + end + end + +endmodule diff --git a/spimemory.v b/spimemory.v index c6ed4f7..2293756 100644 --- a/spimemory.v +++ b/spimemory.v @@ -1,17 +1,81 @@ -//------------------------------------------------------------------------ -// SPI Memory -//------------------------------------------------------------------------ - -module spiMemory -( - input clk, // FPGA clock - input sclk_pin, // SPI clock - input cs_pin, // SPI chip select - output miso_pin, // SPI master in slave out - input mosi_pin, // SPI master out slave in - output [3:0] leds // LEDs for debugging -) - - -endmodule - +`include "inputconditioner.v" +`include "finiteStateMachine.v" +`include "datamemory.v" +`include "shiftregister.v" +`include "testAnd.v" + +module bufferSwitch +( + output buff_out, + input buff_in, + input buff_enable +); + and bufenable(buff_out, buff_enable, buff_in); +endmodule + +module dff +( + input d, + //input ce, + input clk, + output reg q +); + always @(posedge clk) begin + //if (ce == 1) begin + q <= d; + //end + end +endmodule + +module dff7Bit +( + input [6:0] d, + //input ce, + input clk, + output reg [6:0] q +); + always @(posedge clk) begin + //if (ce == 1) begin + q <= d; + //end + end +endmodule + + +//------------------------------------------------------------------------ +// SPI Memory +//------------------------------------------------------------------------ +module spiMemory +( + input clk, // FPGA clock + input sclk_pin, // SPI clock + input cs_pin, // SPI chip select + output miso_pin, // SPI master in slave out + input mosi_pin, // SPI master out slave in + output [3:0] leds // LEDs for debugging +); + + wire mosi_rising, mosi_falling, mosi_conditioned; + wire sclk_rising, sclk_falling, sclk_conditioned; + wire cs_rising, cs_falling, cs_conditioned; + wire [7:0] parallelMemToSR, parallelSRtoMem; + wire serialOut, parallelLoad; + wire [6:0] address; + wire MISObuff, memWE, addrWE, srWE; + wire miso_pin_pre_buffer; + + bufferSwitch buffswitch0(miso_pin, miso_pin_pre_buffer, MISObuff); + + inputconditioner mosiIC(clk, mosi_pin, mosi_conditioned, mosi_rising, mosi_falling); + inputconditioner csIC(clk, cs_pin, cs_conditioned, cs_rising, cs_falling); + inputconditioner sclkIC(clk, sclk_pin, sclk_conditioned, sclk_rising, sclk_falling); + + shiftregister shifreg(clk, sclk_falling, srWE, parallelMemToSR, mosi_conditioned, parallelSRtoMem, serialOut); + + datamemory memory1(clk, parallelMemToSR, address, memWE, parallelSRtoMem); + + dff dff1(serialOut, sclk_falling, miso_pin_pre_buffer); + dff7Bit dff2(parallelSRtoMem[6:0], addrWE, address); + + fsm fsm1( MISObuff, memWE, addrWE, srWE, sclk_rising, sclk_falling, cs_falling, mosi_conditioned); +endmodule diff --git a/writeRead2.png b/writeRead2.png new file mode 100644 index 0000000..8649f0b Binary files /dev/null and b/writeRead2.png differ diff --git a/writeReadBack.png b/writeReadBack.png new file mode 100644 index 0000000..ad1bd8a Binary files /dev/null and b/writeReadBack.png differ diff --git a/writeup.md b/writeup.md new file mode 100644 index 0000000..b0f7418 --- /dev/null +++ b/writeup.md @@ -0,0 +1,32 @@ +## Lab 2 Writeup +Rocco, Judy, Chris + +### Testing + +#### Shift Register +To test the shift register, we just wrote a test script to cycle the clock and change the inputs, then looked at the output to make sure it was shifting correctly. We also uploaded it to the FPGA and tested a number of cases there. + +#### State Machine +For the state machine, we wrote a script with a clock, then set the chip select pin and checked the state and enable outputs after a set number of clock cycles. This was mostly based on our logic about how the rest of the system would work, so we wanted to look at the output instead of trying to write a test which would output a pass or fail. Testing this before putting everything together helped with both our confidence in the system and with our logic about how the parts needed to connect. The final test of the state machine is shown below. + +![fsm test](fsmTest.png) + +The states are maped: 000:Wait, 001:ReadAddress, 010:ReadOrWrite, 011:Write, 100:Read, 0 is a write opperation. + +No flags are set until the end of the ReadAddress state (in the 7th clock cycle), at which point addrWE is set. For a read opperation, srWE is set momentarily (not shown), then MISObuf si set for the duration of the read. For a write opperation, nothing is set while the shift register is filled again, then memWE is set after the last value is recieved. + +#### SPI memory +To test the memory, we did three tests. The first was to write to an address in memory and read the value back. The second was to write to a second address and read back the values from both addresses, and the third was to deselect the device, write to the first memory address again, and read back to make sure the value hadn't changed. This test prints messages if the tests fail, or just "all tests passed" if none fail. + +### Waveforms + +The waveform from the SPI test for writing to the second memory address, then reading back from the first and second address, is shown below: + +![waveform of SPI memory](writeRead2.png) + +The top trace is the spi clock, followed by the value in the shift register, the state (from the state machine), the memory address from the memory block, dataOut of the memory block, chip select, MOSI, and MISO. The first action is a write action, where the value 3 is written to address 78. Next, we read the value from address 5 (value is 9B), and finally, we read back the value from address 78. + +### Analysis and Reflection +Aside from logistical problems, I think this is a good lab, The SPI memory appears to work, and I think we have a good understanding of all of the parts of the system. We spent a lot of time before the midpoint deliverable understanding how the shift register worked and what all of the inputs meant, so I think we had a good idea of how the overall memory should work based on that. The only other part that was difficult from an understanding perspective was the timing of the actual SPI protocol. The picture in the lab description was very useful, and we pretty much used that as a reference to compare with GTKwave outputs. + +I think that the only thing we underestimated on our work plan was how long we would need to debug small problems in verilog relating to timing and overdriven variables. There were a few hours of just looking at GTKwave and finding timing bugs or unexpected outputs which we didn't account for.