diff --git a/Test_Sequence.txt b/Test_Sequence.txt new file mode 100644 index 0000000..aa3e10c --- /dev/null +++ b/Test_Sequence.txt @@ -0,0 +1,27 @@ +Test Sequence + +Controls: + +Button0: Parallel Data In +Button1: Show Last 4 Bits +Button2: Show First 4 Bits + +Switch0: Serial Data In +Switch1: Serial Data In CLk Edge + +To begin testing first press Button0, then Button1. +You should see the following sequence in the 4 LEDS: 0011 +Press Button2 to see the first 4 bits which should be: 1100 + +Now to test the serial data in functionality set switch0 to HIGH and toggle Switch1 to high +This should write a 1 bit to the back of the shift register and you should see the following: +Press Button1: 0111 +Press Button2: 1000 + +Now set switch0 to low and toggle switch1 to high +This should write a 0 bit to the back of the shift register and you should see the following: +Press Button1: 1110 +Press Button2: 0000 + + +Now press Button0 again and the output should be 11000011 again. \ No newline at end of file diff --git a/datamemory.v b/datamemory.v index 0d82131..02225af 100644 --- a/datamemory.v +++ b/datamemory.v @@ -17,7 +17,7 @@ module datamemory input [addresswidth-1:0] address, input writeEnable, input [width-1:0] dataIn -) +); reg [width-1:0] memory [depth-1:0]; diff --git a/fsm.v b/fsm.v new file mode 100644 index 0000000..e9ab029 --- /dev/null +++ b/fsm.v @@ -0,0 +1,156 @@ +// MISO_BUFF DM_WE ADDR_WE SR_WE +//CS 0 0 0 0 +//~CS 0 0 1 1 +//shiftRegOutP[0] 1 0 0 1 +//~shiftRegOutP[0]0 1 0 0 +module fsm(MISO_BUFF,DM_WE,ADDR_WE,SR_WE,POS_EDGE,CS,shiftRegOutP0,clk,state,counter,relevant_shiftRegOutP0,clk_counter); + input POS_EDGE; + input CS; + input shiftRegOutP0; + input clk; + output MISO_BUFF; + output DM_WE; + output ADDR_WE; + output SR_WE; + output [1:0] state; + output [5:0] counter; + output [1:0] relevant_shiftRegOutP0; + output [5:0] clk_counter; + + wire [1:0] state; + reg MISO_BUFF,DM_WE,ADDR_WE,SR_WE; + reg [1:0] next_state; + parameter counter_num_bits = 5; + reg[counter_num_bits-1:0] counter = 0; + reg start_counter; + wire [1:0] previous_state; + reg [1:0] counter_type; + reg [1:0] relevant_shiftRegOutP0; + reg already_counted; + reg [5:0] clk_counter; + reg [1:0] counter_flag; + + assign state = next_state; + + function [1:0] fsm_function; + input [1:0] state; + input CS; + input relevant_shiftRegOutP0; + case(state) + 2'b00:if(!CS) begin + fsm_function = 2'b01; + end + 2'b01:if(relevant_shiftRegOutP0 == 2'b10) begin + fsm_function = 2'b10; + end else if (relevant_shiftRegOutP0 == 2'b01) begin + fsm_function = 2'b11; + end else if (already_counted && counter == 0 && CS) begin + fsm_function = 2'b00; + end + 2'b10:if(CS) begin + fsm_function = 2'b00; + end + 2'b11:if(CS) begin + fsm_function = 2'b00; + end + default:fsm_function = 2'b00; + endcase + endfunction + + always @ (posedge clk) begin + if(counter == 7) begin + clk_counter <= 1; + counter_flag <= 2'b01; + end else if (counter == 10 && relevant_shiftRegOutP0 == 2'b10) begin + clk_counter <= 1; + counter_flag <= 2'b10; + end else if (counter == 18 && relevant_shiftRegOutP0 == 2'b10) begin + clk_counter <= 1; + counter_flag <= 2'b11; + end else if (clk_counter == 3 && counter_flag == 2'b01) begin + relevant_shiftRegOutP0 <= shiftRegOutP0 ? 2'b10 : 2'b01; + clk_counter <= 0; + end else if (clk_counter == 6 && counter_flag == 2'b10) begin + MISO_BUFF <= 1; + clk_counter <= 0; + end else if (clk_counter == 6 && counter_flag == 2'b11) begin + MISO_BUFF <= 0; + clk_counter <= 0; + counter <= 0; + relevant_shiftRegOutP0 <= 2'b00; + end else if (clk_counter > 0) begin + clk_counter <= clk_counter + 1; + end + end + + always @ (posedge POS_EDGE) begin + next_state <= fsm_function(state,CS,relevant_shiftRegOutP0); + if (next_state == 2'b00) begin + MISO_BUFF <= 0; + DM_WE <= 0; + SR_WE <= 0; + ADDR_WE <= 0; + already_counted <= 0; + end else if (next_state == 2'b01) begin + if(counter == 0 && !already_counted) begin + counter <= 1; + counter_type <= 2'b01; + already_counted <= 1; + end + end else if (next_state == 2'b10) begin + ADDR_WE <= 0; + DM_WE <= 0; + if(counter > 0) begin + SR_WE <= 1; + MISO_BUFF <= 1; + end + end else if (next_state == 2'b11) begin + DM_WE <= 0; + ADDR_WE <= 0; + SR_WE <= 0; + end + if (counter == 7) begin + ADDR_WE <= 1; + //relevant_shiftRegOutP0 <= shiftRegOutP0 ? 2'b10 : 2'b01; + counter <= counter + 1; + end else if (counter == 8) begin + ADDR_WE <= 0; + counter <= counter + 1; + end else if (counter == 9) begin + if (relevant_shiftRegOutP0 == 2'b10) begin + SR_WE <= 1; + end + counter <= counter + 1; + end else if (counter == 10) begin + SR_WE <= 0; + counter <= counter + 1; + //end else if (counter == ) begin + //if (next_state == 2'b10) begin + //MISO_BUFF <= 1; + //end + //counter <= counter + 1; + //end else if (counter == 10) begin + //if (relevant_shiftRegOutP0 == 2'b10) begin + // MISO_BUFF <= 1; + //end + end else if (counter == 15) begin + if (relevant_shiftRegOutP0 == 2'b01) begin + DM_WE <= 1; + end + counter <= counter + 1; + end else if (counter == 16) begin + DM_WE <= 0; + SR_WE <= 0; + //counter <= 0; + if (relevant_shiftRegOutP0 == 2'b01) begin + MISO_BUFF <= 0; + counter <= 0; + relevant_shiftRegOutP0 <= 2'b00; + end else if (relevant_shiftRegOutP0 == 2'b10) begin + counter <= counter + 1; + end + end else if (counter > 0) begin + counter <= counter + 1; + end + end +endmodule \ No newline at end of file diff --git a/inputconditioner.t.v b/inputconditioner.t.v index 2814163..8fb0918 100644 --- a/inputconditioner.t.v +++ b/inputconditioner.t.v @@ -1,10 +1,11 @@ //------------------------------------------------------------------------ // Input Conditioner test bench //------------------------------------------------------------------------ +`include "inputconditioner.v" module testConditioner(); - reg clk; + reg clk = 0; reg pin; wire conditioned; wire rising; @@ -14,16 +15,23 @@ module testConditioner(); .noisysignal(pin), .conditioned(conditioned), .positiveedge(rising), - .negativeedge(falling)) - + .negativeedge(falling)); // Generate clock (50MHz) - initial clk=0; - always #10 clk=!clk; // 50MHz Clock + initial begin + forever begin + clk = !clk; #10; + end + end initial begin - // Your Test Code - // Be sure to test each of the three conditioner functions: - // Synchronization, Debouncing, Edge Detection + pin = 0; #50; + pin = 1; #100; + pin = 0; #100; + pin = 1; #150; + pin = 0; #30; + pin = 1; #60; + pin = 0; #30; + end endmodule diff --git a/inputconditioner.v b/inputconditioner.v index 736a866..47618a5 100644 --- a/inputconditioner.v +++ b/inputconditioner.v @@ -6,33 +6,46 @@ //------------------------------------------------------------------------ module inputconditioner -( -input clk, // Clock domain to synchronize input to -input noisysignal, // (Potentially) noisy input signal -output reg conditioned, // Conditioned output signal -output reg positiveedge, // 1 clk pulse at rising edge of conditioned -output reg negativeedge // 1 clk pulse at falling edge of conditioned -); +(clk,noisysignal,conditioned,positiveedge,negativeedge); parameter counterwidth = 3; // Counter size, in bits, >= log2(waittime) parameter waittime = 3; // Debounce delay, in clock cycles + + input clk; + input noisysignal; + output reg conditioned; + output reg positiveedge; + output reg negativeedge; reg[counterwidth-1:0] counter = 0; reg synchronizer0 = 0; reg synchronizer1 = 0; + reg conditioned1 = 0; always @(posedge clk ) begin - if(conditioned == synchronizer1) + if(conditioned1 == 0 && conditioned == 1) begin + negativeedge = 1; + end else if (conditioned1 == 1 && conditioned == 0) begin + positiveedge = 1; + end else if (positiveedge == 1 || negativeedge == 1) begin + positiveedge = 0; + negativeedge = 0; + end + if(conditioned1 == synchronizer1) counter <= 0; else begin if( counter == waittime) begin counter <= 0; - conditioned <= synchronizer1; + conditioned1 <= synchronizer1; end else counter <= counter+1; end synchronizer0 <= noisysignal; synchronizer1 <= synchronizer0; + conditioned <= conditioned1; end endmodule + + + diff --git a/midpoint.v b/midpoint.v new file mode 100644 index 0000000..287a456 --- /dev/null +++ b/midpoint.v @@ -0,0 +1,203 @@ +//-------------------------------------------------------------------------------- +// Wrapper for Lab 2: Midpoint.v +// +// Rationale: +// The ZYBO board has 4 buttons, 4 switches, and 4 LEDs. But if we want to +// show the results of a 4-bit add operation, we will need at least 6 LEDs! +// +// This wrapper module allows for 4-bit operands to be loaded in one at a +// time, and multiplexes the LEDs to show the SUM and carryout/overflow at +// different times. +// +// +// Usage: +// btn0 - load parallel load into input conditioner -> shift register +// btn1 - show first 4 bits +// btn2 - show last 4 bits +// sw0 - Serial In Input into input conditioner -> shift register +// sw1 - Clk Edge +// +// Note: Buttons, switches, and LEDs have the least-significant (0) position +// on the right. +//-------------------------------------------------------------------------------- + +`timescale 1ns / 1ps + + +//-------------------------------------------------------------------------------- +// Basic building block modules +//-------------------------------------------------------------------------------- + +// JK flip-flop +module jkff1 +( + input trigger, + input j, + input k, + output reg q +); + always @(posedge trigger) begin + if(j && ~k) begin + q <= 1'b1; + end + else if(k && ~j) begin + q <= 1'b0; + end + else if(k && j) begin + q <= ~q; + end + end +endmodule + +// Two-input MUX with parameterized bit width (default: 1-bit) +module mux2 #( parameter W = 1 ) +( + input[W-1:0] in0, + input[W-1:0] in1, + input sel, + output[W-1:0] out +); + // Conditional operator - http://www.verilog.renerta.com/source/vrg00010.htm + assign out = (sel) ? in1 : in0; +endmodule + +//------------------------------------------------------------------------ +// Input Conditioner +// 1) Synchronizes input to clock domain +// 2) Debounces input +// 3) Creates pulses at edge transitions +//------------------------------------------------------------------------ + +module inputconditioner +(clk,noisysignal,conditioned,positiveedge,negativeedge); + + parameter counterwidth = 3; // Counter size, in bits, >= log2(waittime) + parameter waittime = 3; // Debounce delay, in clock cycles + + input clk; + input noisysignal; + output reg conditioned; + output reg positiveedge; + output reg negativeedge; + + reg[counterwidth-1:0] counter = 0; + reg synchronizer0 = 0; + reg synchronizer1 = 0; + reg conditioned1 = 0; + + always @(posedge clk ) begin + if(conditioned == 0 && conditioned1 == 1) begin + negativeedge = 1; + end else if (conditioned == 1 && conditioned1 == 0) begin + positiveedge = 1; + end else if (positiveedge == 1 || negativeedge == 1) begin + positiveedge = 0; + negativeedge = 0; + end + if(conditioned == synchronizer1) + counter <= 0; + else begin + if( counter == waittime) begin + counter <= 0; + conditioned <= synchronizer1; + end + else + counter <= counter+1; + end + synchronizer0 <= noisysignal; + synchronizer1 <= synchronizer0; + conditioned1 <= conditioned; + end +endmodule + +//------------------------------------------------------------------------ +// Shift Register +// Parameterized width (in bits) +// Shift register can operate in two modes: +// - serial in, parallel out +// - parallel in, serial out +//------------------------------------------------------------------------ + +module shiftregister +#(parameter width = 8) +( +input clk, // FPGA Clock +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 reg [width-1:0] parallelDataOut, // Shift reg data contents +output reg serialDataOut // Positive edge synchronized +); + + reg [width-1:0] shiftregistermem; + + always @(posedge clk) begin + + if(parallelLoad==1) begin + // load the register with parallelDataIn + shiftregistermem <= parallelDataIn; + end + + else if(parallelLoad==0) begin + if(peripheralClkEdge==1) begin + //grab the MSB as SDO and then shift everything over 1 place + serialDataOut <= shiftregistermem[width-1]; + shiftregistermem<={shiftregistermem[width-2:0],serialDataIn}; + end + end + //parallelDataOut is just the current state of the register + parallelDataOut <= shiftregistermem; + + end +endmodule + + +//-------------------------------------------------------------------------------- +// Main Lab 0 wrapper module +// Interfaces with switches, buttons, and LEDs on ZYBO board. Allows for two +// 4-bit operands to be stored, and two results to be alternately displayed +// to the LEDs. +//-------------------------------------------------------------------------------- + +module midpoint +( + input clk, + input [1:0] sw, + input [2:0] btn, + output [3:0] led +); + + reg[7:0] parallelData = 8'b11000011; //Assign default parallel in + wire[3:0] res0, res1; // + wire[7:0] shiftregister; // Current Shift Register Values + wire res_sel; // Select between display options + wire parallelslc; // select parallel input + wire serialin; // binary input for serial input + wire serialclk; // clk edge for serial input + + + // Capture button input to switch which MUX input to LEDs + jkff1 src_sel(.trigger(clk), .j(btn[1]), .k(btn[2]), .q(res_sel)); + mux2 #(4) output_select(.in0(res0), .in1(res1), .sel(res_sel), .out(led)); + + //Map to input conditioner + inputconditioner parallel(.noisysignal(btn[0]),.clk(clk),.negativeedge(parallelslc)); + inputconditioner serialinputs(.noisysignal(sw[0]),.clk(clk),.conditioned(serialin)); + inputconditioner serialclocks(.noisysignal(sw[1]),.clk(clk),.positiveedge(serialclk)); + + //Input into Shift Register + shiftregister shifted(.clk(clk),.peripheralClkEdge(serialclk),.parallelLoad(parallelslc),.parallelDataIn(parallelData),.serialDataIn(serialin),.parallelDataOut(shiftregister)); + + + // Assign bits of shiftregister to appropriate display boxes + assign res0[0] = shiftregister[0]; + assign res0[1] = shiftregister[1]; + assign res0[2] = shiftregister[2]; + assign res0[3] = shiftregister[3]; + assign res1[0] = shiftregister[4]; + assign res1[1] = shiftregister[5]; + assign res1[2] = shiftregister[6]; + assign res1[3] = shiftregister[7]; + +endmodule diff --git a/shiftregister.t.v b/shiftregister.t.v index abe5b48..663ed0f 100644 --- a/shiftregister.t.v +++ b/shiftregister.t.v @@ -1,6 +1,7 @@ //------------------------------------------------------------------------ // Shift Register test bench //------------------------------------------------------------------------ +`include "shiftregister.v" module testshiftregister(); @@ -22,7 +23,15 @@ module testshiftregister(); .serialDataOut(serialDataOut)); initial begin - // Your Test Code + forever begin + clk = !clk; #10; + end + end + + initial begin + parallelLoad = 1; parallelDataIn = 8'b10000000; #100; + serialDataIn = 1; peripheralClkEdge = 1; parallelLoad = 0; #20; + serialDataIn = 0; #200; end endmodule diff --git a/shiftregister.v b/shiftregister.v index b4ec057..dbadfa5 100644 --- a/shiftregister.v +++ b/shiftregister.v @@ -14,12 +14,28 @@ 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; + always @(posedge clk) begin - // Your Code Here + + if(parallelLoad==1) begin + // load the register with parallelDataIn + shiftregistermem <= parallelDataIn; + end + + else if(parallelLoad==0) begin + if(peripheralClkEdge==1) begin + //grab the MSB as SDO and then shift everything over 1 place + serialDataOut <= shiftregistermem[width-1]; + shiftregistermem<={shiftregistermem[width-2:0],serialDataIn}; + end + end + //parallelDataOut is just the current state of the register + parallelDataOut <= shiftregistermem; + end endmodule diff --git a/spimemory.t.v b/spimemory.t.v new file mode 100644 index 0000000..ed5c46e --- /dev/null +++ b/spimemory.t.v @@ -0,0 +1,157 @@ +`include "spimemory.v" + +module testspimemory(); + reg clk = 0; // FPGA clock + reg sclk_pin = 0; // SPI clock + reg cs_pin; // SPI chip select + wire miso_pin; // SPI master in slave out, has memory address + reg mosi_pin; // SPI master out slave in, for reading + wire [3:0] leds; // leds + reg [15:0] data; // data + wire buffered_serialin; + wire posSCLK; + wire CS; + wire miso_buff; + wire shiftRegOutP; + wire [7:0] parallelOut; + wire [7:0] parallelData; + wire sr_we; + wire dm_we; + wire [1:0] state; + wire conditioned_clk; + wire [4:0] counter; + wire output_ff_out; + wire addr_we; + wire [1:0] relevant_shiftRegOutP0; + wire [6:0] address; + wire [5:0] clk_counter; + + spiMemory dut(.clk(clk), + .sclk_pin(sclk_pin), + .cs_pin(cs_pin), + .miso_pin(miso_pin), + .mosi_pin(mosi_pin), + .leds(leds), + .buffered_serialin(buffered_serialin), + .posSCLK(posSCLK), + .CS(CS), + .miso_buff(miso_buff), + .shiftRegOutP(shiftRegOutP), + .parallelOut(parallelOut), + .parallelData(parallelData), + .sr_we(sr_we), + .dm_we(dm_we), + .state(state), + .conditioned_clk(conditioned_clk), + .counter(counter), + .output_ff_out(output_ff_out), + .addr_we(addr_we), + .relevant_shiftRegOutP0(relevant_shiftRegOutP0), + .address(address), + .clk_counter(clk_counter) + ); + + initial begin + forever begin + clk = !clk; #1; + end + end // 50MHz Clock + initial begin + forever begin + sclk_pin = !sclk_pin; #10; + end + end + + initial begin + cs_pin = 1; #500 + + //Test Case 1: Write: Address: 00000010 Data: 111111111 + + $display ("Initialize Testing"); + data = 16'b0000001011111111; + + cs_pin = 0; #20 + + mosi_pin = data[15]; #20 + mosi_pin = data[14]; #20 + mosi_pin = data[13]; #20 + mosi_pin = data[12]; #20 + mosi_pin = data[11]; #20 + mosi_pin = data[10]; #20 + mosi_pin = data[9]; #20 + + mosi_pin = 0; #20 + + mosi_pin = data[7]; #20 + mosi_pin = data[6]; #20 + mosi_pin = data[5]; #20 + mosi_pin = data[4]; #20 + mosi_pin = data[3]; #20 + mosi_pin = data[2]; #20 + mosi_pin = data[1]; #20 + mosi_pin = data[0]; #20 + + //checkSPI spi_case1(.data(16'b0000001011111111),.clk(clk),.slck(slck),.cs_pin(cs_pin),.mosi_pin(mosi_pin)); + + #500 + + cs_pin = 1; #600 + + // TestCase 2: Read: Address: 00000010 + + cs_pin = 0; #20 + + data = 16'b0000001111111111; + + mosi_pin = data[15]; #20 + mosi_pin = data[14]; #20 + mosi_pin = data[13]; #20 + mosi_pin = data[12]; #20 + mosi_pin = data[11]; #20 + mosi_pin = data[10]; #20 + mosi_pin = data[9]; #20 + + mosi_pin = 1; #20 + + if ((miso_pin != data[7])) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != data[6])) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != data[5])) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != data[4])) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != data[3])) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != data[2])) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != data[1])) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != data[0])) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + #500 + //checkSPI spi_case2(.data(16'b0000001111111111),.clk(clk),.slck(slck),.cs_pin(cs_pin),.mosi_pin(mosi_pin)); + cs_pin = 1; #600 + cs_pin = 0; #20 + + // TestCase 3: Read other Address: 000000101 + // Check to make sure that our Write didnt write to other parts + + data = 16'b0000010111111111; + + mosi_pin = data[15]; #20 + mosi_pin = data[14]; #20 + mosi_pin = data[13]; #20 + mosi_pin = data[12]; #20 + mosi_pin = data[11]; #20 + mosi_pin = data[10]; #20 + mosi_pin = data[9]; #20 + + mosi_pin = 1; #20 + + $display ("Testing ongoing"); + if ((miso_pin != 0)) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != 0)) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != 0)) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != 0)) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != 0)) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != 0)) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != 0)) $display ("Test Failed at Read Element 1: %b ", miso_pin); #20 + if ((miso_pin != 1)) begin $display ("Test Failed at Read Element 1: %b ", miso_pin); end #20; + + //checkSPI spi_case2(.data(16'b0000001111111111),.clk(clk),.slck(slck),.cs_pin(cs_pin),.mosi_pin(mosi_pin)); + end + +endmodule \ No newline at end of file diff --git a/spimemory.v b/spimemory.v index c6ed4f7..1e7e5f5 100644 --- a/spimemory.v +++ b/spimemory.v @@ -1,17 +1,308 @@ +`include "fsm.v" +`include "datamemory.v" + //------------------------------------------------------------------------ // SPI Memory //------------------------------------------------------------------------ -module spiMemory +//-------------------------------------------------------------------------------- +// Wrapper for Lab 2: Midpoint.v +// +// Rationale: +// The ZYBO board has 4 buttons, 4 switches, and 4 LEDs. But if we want to +// show the results of a 4-bit add operation, we will need at least 6 LEDs! +// +// This wrapper module allows for 4-bit operands to be loaded in one at a +// time, and multiplexes the LEDs to show the SUM and carryout/overflow at +// different times. +// +// +// Usage: +// btn0 - load parallel load into input conditioner -> shift register +// btn1 - show first 4 bits +// btn2 - show last 4 bits +// sw0 - Serial In Input into input conditioner -> shift register +// sw1 - Clk Edge +// +// Note: Buttons, switches, and LEDs have the least-significant (0) position +// on the right. +//-------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------- +// Basic building block modules +//-------------------------------------------------------------------------------- + +// JK flip-flop +module jkff1 +( + input trigger, + input j, + input k, + output reg q +); + always @(posedge trigger) begin + if(j && ~k) begin + q <= 1'b1; + end + else if(k && ~j) begin + q <= 1'b0; + end + else if(k && j) begin + q <= ~q; + end + end +endmodule + +module tristatebuffer(out,in,en); + input in; + input en; + output out; + + assign out = en ? in : 1'bz; + +endmodule + +// Two-input MUX with parameterized bit width (default: 1-bit) +module mux2 #( parameter W = 1 ) +( + input[W-1:0] in0, + input[W-1:0] in1, + input sel, + output[W-1:0] out +); + // Conditional operator - http://www.verilog.renerta.com/source/vrg00010.htm + assign out = (sel) ? in1 : in0; +endmodule + +module dff #(parameter W = 1) ( - 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 -) + input trigger, + input enable, + input [W-1:0] d, + output reg [W-1:0] q +); + always @ (posedge trigger) begin + if(enable) begin + q <=d; + end + end + +endmodule + +module dlatch +( + input [7:0] data , + input clk, + input addr_we, + output reg [6:0] addr +); + +always @(posedge clk) begin + if(addr_we) begin + addr <= data[7:1]; + end +end + +endmodule + +//------------------------------------------------------------------------ +// Input Conditioner +// 1) Synchronizes input to clock domain +// 2) Debounces input +// 3) Creates pulses at edge transitions +//------------------------------------------------------------------------ + +module inputconditioner +(clk,noisysignal,conditioned,positiveedge,negativeedge); + parameter counterwidth = 3; // Counter size, in bits, >= log2(waittime) + parameter waittime = 1; // Debounce delay, in clock cycles + input clk; + input noisysignal; + output reg conditioned; + output reg positiveedge; + output reg negativeedge; + + reg[counterwidth-1:0] counter = 0; + reg synchronizer0 = 0; + reg synchronizer1 = 0; + reg conditioned1 = 0; + + always @(posedge clk ) begin + if(conditioned1 == 0 && conditioned == 1) begin + negativeedge = 1; + end else if (conditioned1 == 1 && conditioned == 0) begin + positiveedge = 1; + end else if (positiveedge == 1 || negativeedge == 1) begin + positiveedge = 0; + negativeedge = 0; + end + if(conditioned1 == synchronizer1) + counter <= 0; + else begin + if( counter == waittime) begin + counter <= 0; + conditioned1 <= synchronizer1; + end + else + counter <= counter+1; + end + synchronizer0 <= noisysignal; + synchronizer1 <= synchronizer0; + conditioned <= conditioned1; + end endmodule - + +//------------------------------------------------------------------------ +// Shift Register +// Parameterized width (in bits) +// Shift register can operate in two modes: +// - serial in, parallel out +// - parallel in, serial out +//------------------------------------------------------------------------ + +module shiftregister +#(parameter width = 8) +( +input clk, // FPGA Clock +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 reg [width-1:0] parallelDataOut, // Shift reg data contents +output reg serialDataOut // Positive edge synchronized +); + + reg [width-1:0] shiftregistermem; + + always @(posedge clk) begin + + if(parallelLoad==1) begin + // load the register with parallelDataIn + shiftregistermem <= parallelDataIn; + end + + else if(parallelLoad==0) begin + if(peripheralClkEdge==1) begin + //grab the MSB as SDO and then shift everything over 1 place + serialDataOut <= shiftregistermem[width-1]; + shiftregistermem<={shiftregistermem[width-2:0],serialDataIn}; + end + end + //parallelDataOut is just the current state of the register + parallelDataOut <= shiftregistermem; + + end +endmodule + + +//-------------------------------------------------------------------------------- +// Main Lab 2 wrapper module +// Interfaces with switches, buttons, and LEDs on ZYBO board. Allows for two +// operations: read and write. 8 bits are entered (first 7 are address and the last is a R/W flag) +// Read: +// Write: +//-------------------------------------------------------------------------------- + +module spiMemory(clk,sclk_pin,cs_pin,miso_pin,mosi_pin,leds,buffered_serialin,posSCLK,CS,miso_buff,shiftRegOutP,parallelOut,parallelData,sr_we,dm_we,state,conditioned_clk,counter,output_ff_out,addr_we,relevant_shiftRegOutP0,address,clk_counter,serialin); + input clk; + input sclk_pin; + input cs_pin; + output miso_pin; + input mosi_pin; + output serialin; + output [3:0] leds; + output buffered_serialin; + output posSCLK; + output CS; + output miso_buff; + output shiftRegOutP; + output [7:0] parallelOut; + output [7:0] parallelData; + output sr_we; + output dm_we; + output [1:0] state; + output conditioned_clk; + output [4:0] counter; + output output_ff_out; + output addr_we; + output [1:0] relevant_shiftRegOutP0; + output [6:0] address; + output [5:0] clk_counter; + output posSCLK; + output CS; + output miso_buff; + output shiftRegOutP; + output [7:0] parallelOut; + output [7:0] parallelData; + output sr_we; + + wire[7:0] parallelData; // ParallelData Out + wire[6:0] address; // address + wire[7:0] parallelOut; // Current Shift Register Values + wire res_sel; // Select between display options + wire parallelslc; // select parallel input + wire serialin; // binary input for serial input + wire serialout; // serial output of shift register + wire posSCLK; // clk edge for serial input + wire negSCLK; // + wire CS ; // chip select + wire Flag; // R/W flag + wire miso_buff; // miso_buff + wire dm_we; // dm_we + wire addr_we; // addr_we + wire sr_we; // sr_we + wire output_ff_out; // output ff output + wire filler; // filler wire + wire shiftRegOutP; + wire [1:0] state; + wire conditioned_clk; + wire [4:0] counter; + wire buffered_serialin; + wire buffered_posSCLK; + wire [1:0] relevant_shiftRegOutP0; + wire miso_buff_d2,miso_buff_d1,dm_we_d2,dm_we_d1,addr_we_d2,addr_we_d1,sr_we_d2,sr_we_d1; + wire [5:0] clk_counter; + wire clk; + + assign shiftRegOutP = parallelOut[0]; + + //Map to input conditioners + //(clk,noisysignal,conditioned,positiveedge,negativeedge); + inputconditioner MOSI_conditioner(.clk(clk),.noisysignal(mosi_pin),.conditioned(serialin),.positiveedge(filler),.negativeedge(filler)); + inputconditioner SCLK(.clk(clk),.noisysignal(sclk_pin),.conditioned(conditioned_clk),.positiveedge(posSCLK),.negativeedge(negSCLK)); + inputconditioner CS_conditioner(.clk(clk),.noisysignal(cs_pin),.conditioned(CS),.positiveedge(filler),.negativeedge(filler)); + + //finite statemachine + //(MISO_BUFF,DM_WE,ADDR_WE,SR_WE,POS_EDGE,CS,shiftRegOutP0,clk) + fsm fsm_process(.MISO_BUFF(miso_buff),.DM_WE(dm_we),.ADDR_WE(addr_we),.SR_WE(sr_we),.POS_EDGE(posSCLK),.CS(CS),.shiftRegOutP0(parallelOut[0]),.clk(clk),.state(state),.counter(counter),.relevant_shiftRegOutP0(relevant_shiftRegOutP0),.clk_counter(clk_counter)); + + //dff miso_buff_buffer2(.trigger(clk),.enable(1'b1),.d(miso_buff_d2),.q(miso_buff_d1)); + //dff mis_buff_buffer1(.trigger(clk),.enable(1'b1),.d(miso_buff_d1),.q(miso_buff)); + + //dff dm_we_buffer2(.trigger(clk),.enable(1'b1),.d(dm_we_d2),.q(dm_we_d1)); + //dff dm_we_buffer1(.trigger(clk),.enable(1'b1),.d(dm_we_d1),.q(dm_we)); + + //dff addr_we_buffer2(.trigger(clk),.enable(1'b1),.d(addr_we_d2),.q(addr_we_d1)); + //dff addr_we_buffer1(.trigger(clk),.enable(1'b1),.d(addr_we_d1),.q(addr_we)); + + //dff sr_we_buffer2(.trigger(clk),.enable(1'b1),.d(sr_we_d2),.q(sr_we_d1)); + //dff sr_we_buffer1(.trigger(clk),.enable(1'b1),.d(sr_we_d1),.q(sr_we)); + + dff serialin_buffer(.trigger(posSCLK),.enable(1'b1),.d(serialin),.q(buffered_serialin)); + //Address Latch + dlatch addr_latch(.data(parallelOut),.clk(clk),.addr_we(addr_we),.addr(address)); + + dff output_ff(.trigger(clk),.enable(negSCLK),.d(serialout),.q(output_ff_out)); + + tristatebuffer outbuffer(.out(miso_pin),.in(output_ff_out),.en(miso_buff)); + + //(clk,peripheralClkEdge,parallelLoad,parallelDataIn,serialDataIn,parallelDataOut,serialDataOut) + shiftregister shifted(.clk(clk),.peripheralClkEdge(posSCLK),.parallelLoad(sr_we),.parallelDataIn(parallelData),.serialDataIn(buffered_serialin),.parallelDataOut(parallelOut),.serialDataOut(serialout)); + + //data memory + //clk,dataOut,address,writeEnable,dataIn + datamemory data(.clk(clk),.dataOut(parallelData),.address(address),.writeEnable(dm_we),.dataIn(parallelOut)); + +endmodule \ No newline at end of file diff --git a/spimemory_fpga.v b/spimemory_fpga.v new file mode 100644 index 0000000..526d0f8 --- /dev/null +++ b/spimemory_fpga.v @@ -0,0 +1,371 @@ +//------------------------------------------------------------------------ +// SPI Memory +//------------------------------------------------------------------------ + +//-------------------------------------------------------------------------------- +// Wrapper for Lab 2: spimemory +// +// Rationale: +// The ZYBO board has 4 buttons, 4 switches, and 4 LEDs. We want to be able to verify the miso pin +// so we need to display the current miso value and have another indicator to indicate if it is tristated to // differentiate between '0' and 'z'. +// Usage: +// sw0 - Serial In Input into input conditioner -> shift register +// sw1 - Clk Edge +// sw2 - Chip Select +// led0 - Miso +// led3 - Tristated? +// Note: Buttons, switches, and LEDs have the least-significant (0) position +// on the right. +//-------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------- +// Basic building block modules +//-------------------------------------------------------------------------------- + + +module dff #(parameter W = 1) +( + input trigger, + input enable, + input [W-1:0] d, + output reg [W-1:0] q +); + always @ (posedge trigger) begin + if(enable) begin + q <=d; + end + end + +endmodule + +module dlatch +( + input [7:0] data , + input clk, + input addr_we, + output reg [6:0] addr +); + +always @(posedge clk) begin + if(addr_we) begin + addr = data[7:1]; + end +end + +endmodule + + +module tristatebuffer(out,in,en); + input in; + input en; + output out; + + assign out = en ? in : 1'bz; + +endmodule + +//------------------------------------------------------------------------ +// Input Conditioner +// 1) Synchronizes input to clock domain +// 2) Debounces input +// 3) Creates pulses at edge transitions +//------------------------------------------------------------------------ + +//------------------------------------------------------------------------ +// Input Conditioner +// 1) Synchronizes input to clock domain +// 2) Debounces input +// 3) Creates pulses at edge transitions +//------------------------------------------------------------------------ + +module inputconditioner +(clk,noisysignal,conditioned,positiveedge,negativeedge); + + parameter counterwidth = 3; // Counter size, in bits, >= log2(waittime) + parameter waittime = 3; // Debounce delay, in clock cycles + + input clk; + input noisysignal; + output reg conditioned; + output reg positiveedge; + output reg negativeedge; + + reg[counterwidth-1:0] counter = 0; + reg synchronizer0 = 0; + reg synchronizer1 = 0; + reg conditioned1 = 0; + + always @(posedge clk ) begin + if(conditioned1 == 0 && conditioned == 1) begin + negativeedge = 1; + end else if (conditioned1 == 1 && conditioned == 0) begin + positiveedge = 1; + end else if (positiveedge == 1 || negativeedge == 1) begin + positiveedge = 0; + negativeedge = 0; + end + if(conditioned1 == synchronizer1) + counter <= 0; + else begin + if( counter == waittime) begin + counter <= 0; + conditioned1 <= synchronizer1; + end + else + counter <= counter+1; + end + synchronizer0 <= noisysignal; + synchronizer1 <= synchronizer0; + conditioned <= conditioned1; + end +endmodule + +//------------------------------------------------------------------------ +// Shift Register +// Parameterized width (in bits) +// Shift register can operate in two modes: +// - serial in, parallel out +// - parallel in, serial out +//------------------------------------------------------------------------ + +//------------------------------------------------------------------------ +// Shift Register +// Parameterized width (in bits) +// Shift register can operate in two modes: +// - serial in, parallel out +// - parallel in, serial out +//------------------------------------------------------------------------ + +module shiftregister +#(parameter width = 8) +( +input clk, // FPGA Clock +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 reg [width-1:0] parallelDataOut, // Shift reg data contents +output reg serialDataOut // Positive edge synchronized +); + + reg [width-1:0] shiftregistermem; + + always @(posedge clk) begin + + if(parallelLoad==1) begin + // load the register with parallelDataIn + shiftregistermem <= parallelDataIn; + end + + else if(parallelLoad==0) begin + if(peripheralClkEdge==1) begin + //grab the MSB as SDO and then shift everything over 1 place + serialDataOut <= shiftregistermem[width-1]; + shiftregistermem<={shiftregistermem[width-2:0],serialDataIn}; + end + end + //parallelDataOut is just the current state of the register + parallelDataOut <= shiftregistermem; + + end +endmodule + + +//------------------------------------------------------------------------ +// Data Memory +// Positive edge triggered +// dataOut always has the value mem[address] +// If writeEnable is true, writes dataIn to mem[address] +//------------------------------------------------------------------------ + +module datamemory +#( + parameter addresswidth = 7, + parameter depth = 2**addresswidth, + parameter width = 8 +) +( + input clk, + output reg [width-1:0] dataOut, + input [addresswidth-1:0] address, + input writeEnable, + input [width-1:0] dataIn +); + + + reg [width-1:0] memory [depth-1:0]; + + always @(posedge clk) begin + if(writeEnable) + memory[address] <= dataIn; + dataOut <= memory[address]; + end + +endmodule + + +//------------------------------------------------------------------------ +// Finite State Machine +// +// MISO_BUFF DM_WE ADDR_WE SR_WE +//CS 0 0 0 0 +//~CS 0 0 1 1 +//shiftRegOutP[0] 1 0 0 1 +//~shiftRegOutP[0]0 1 0 0 +// +//------------------------------------------------------------------------ + +// MISO_BUFF DM_WE ADDR_WE SR_WE +//CS 0 0 0 0 +//~CS 0 0 1 1 +//shiftRegOutP[0] 1 0 0 1 +//~shiftRegOutP[0]0 1 0 0 +module fsm(MISO_BUFF,DM_WE,ADDR_WE,SR_WE,POS_EDGE,CS,shiftRegOutP0,clk); + input POS_EDGE; + input CS; + input shiftRegOutP0; + input clk; + output MISO_BUFF; + output DM_WE; + output ADDR_WE; + output SR_WE; + + reg [1:0] state; + reg MISO_BUFF,DM_WE,ADDR_WE,SR_WE; + wire [1:0] next_state; + parameter counter_num_bits = 4; + reg[counter_num_bits-1:0] counter = 0; + + assign next_state = fsm_function(state,POS_EDGE,CS,shiftRegOutP0); + + function [1:0] fsm_function; + input [1:0] state; + input POS_EDGE; + input CS; + input shiftRegOutP0; + case(state) + 2'b00:if(!CS) begin + fsm_function = 2'b01; + end + 2'b01:if(shiftRegOutP0) begin + fsm_function = 2'b10; + end else if (!shiftRegOutP0) begin + fsm_function = 2'b11; + end + 2'b10:if(CS) begin + fsm_function = 2'b00; + end + 2'b11:if(CS) begin + fsm_function = 2'b00; + end + default:fsm_function = 2'b00; + endcase + endfunction + + always @ (posedge clk) begin + state <= next_state; + if (next_state == 2'b00) begin + MISO_BUFF <= 0; + DM_WE <= 0; + SR_WE <= 0; + ADDR_WE <= 0; + end else if (next_state == 2'b01) begin + if(POS_EDGE) begin + counter <= 1; + end + SR_WE <= 1; + end else if (next_state == 2'b10) begin + MISO_BUFF <= 1; + ADDR_WE <= 0; + end else if (next_state == 2'b11) begin + DM_WE <= 1; + ADDR_WE <= 0; + SR_WE <= 0; + end + if (counter==7)begin + ADDR_WE<=1; + counter <= counter + 1; + end + else if (counter==8)begin + ADDR_WE <=0; + counter<=0; + end + else if (counter>0)begin + counter<=counter+1; + end + end +endmodule + +//-------------------------------------------------------------------------------- +// Main Lab 2 wrapper module +// Interfaces with switches, buttons, and LEDs on ZYBO board. Allows for two +// operations: read and write. 8 bits are entered (first 7 are address and the last is a R/W flag) +// Read: +// Write: +// sw[0] = mosi pin +// sw[1] = clk edge +// sw[2] = chip select +// led0 = miso +// led3 = tristated +//-------------------------------------------------------------------------------- + +module spiMemory(clk,sw,led); + input clk; + input [2:0] sw; + output reg [3:0] led; + + wire[7:0] parallelData; // ParallelData Out + wire[6:0] address; // address + wire[3:0] res0, res1; // + wire[7:0] parallelOut; // Current Shift Register Values + wire res_sel; // Select between display options + wire parallelslc; // select parallel input + wire serialin; // binary input for serial input + wire serialout; // serial output of shift register + wire posSCLK; // clk edge for serial input + wire negSCLK; // + wire CS ; // chip select + wire Flag; // R/W flag + wire miso_buff; // miso_buff + wire dm_we; // dm_we + wire addr_we; // addr_we + wire sr_we; // sr_we + wire output_ff_out; // output ff output + wire miso; + + + //Map to input conditioners noisy signal sw[0]...sw[2] + //(clk,noisysignal,conditioned,positiveedge,negativeedge); + inputconditioner MOSI_conditioner(.clk(clk),.conditioned(serialin),.noisysignal(sw[0])); + inputconditioner SCLK(.clk(clk),.noisysignal(sw[1]),.positiveedge(posSCLK),.negativeedge(negSCLK)); + inputconditioner CS_conditioner(.clk(clk),.conditioned(CS),.noisysignal(sw[2])); + + //finite statemachine + //(MISO_BUFF,DM_WE,ADDR_WE,SR_WE,POS_EDGE,CS,shiftRegOutP0,clk) + fsm fsm_process(.MISO_BUFF(miso_buff),.DM_WE(dm_we),.ADDR_WE(addr_we),.SR_WE(sr_we),.POS_EDGE(posSCLK),.CS(CS),.shiftRegOutP0(parallelOut[0]),.clk(clk)); + + //Address Latch + dlatch addr_latch(.data(parallelOut),.clk(clk),.addr_we(addr_we),.addr(address)); + + dff output_ff(.trigger(clk),.enable(negSCLK),.d(serialout),.q(output_ff_out)); + + tristatebuffer outbuffer(.out(miso_pin),.in(output_ff_out),.en(miso_buff)); + + //(clk,peripheralClkEdge,parallelLoad,parallelDataIn,serialDataIn,parallelDataOut,serialDataOut) + shiftregister shifted(.clk(clk),.peripheralClkEdge(posSCLK),.parallelLoad(sr_we),.parallelDataIn(parallelData),.serialDataIn(serialin),.parallelDataOut(parallelOut),.serialDataOut(serialout)); + + //data memory + //clk,dataOut,address,writeEnable,dataIn + datamemory data(.clk(clk),.dataOut(parallelData),.address(address),.writeEnable(dm_we),.dataIn(parallelOut)); + + + + // Assign bits of shiftregister to appropriate display boxes + initial begin + if (miso) begin + led[0] <= 1; + end else if (miso === 1'bz ) begin + led[3] <= 1 ; + end + end +endmodule \ No newline at end of file diff --git a/spimemory_testbench.v b/spimemory_testbench.v new file mode 100644 index 0000000..17a9a85 --- /dev/null +++ b/spimemory_testbench.v @@ -0,0 +1,21 @@ +task read; +input sclk; +input clk; +input [7:0] readAddress; +wire i = 0; +begin + cs = 0; + repeat (16) begin + @ (posedge clk) begin + if (i<=7) begin + mosi_pin = readAddress[i]; + i = i + 1; + sclk_pin = sclk; //or whatever the sclk input is + end else begin + sclk_pin = sclk; + i = i + 1; + end + end + end + cs = 1; +end \ No newline at end of file diff --git a/work_plan.txt b/work_plan.txt new file mode 100644 index 0000000..db70b84 --- /dev/null +++ b/work_plan.txt @@ -0,0 +1,7 @@ +Input Conditioner First Pass - done 10/24 - 2 hours +Shift Register First Pass - done 10/24 - 2 hours +Implement Midpoint on FPGA - done 10/24 - 2 hours +Test Benches for Input Conditioner and Shift Register - done 10/27 - 2 hours +SPI Memory First Pass - done 10/29 - 1 hour +Final SPI Memory Testing - done 10/30 - 1.5 hours +Final Report - done 10/31 - 2 hours \ No newline at end of file diff --git a/writeup.pdf b/writeup.pdf new file mode 100644 index 0000000..6775a19 Binary files /dev/null and b/writeup.pdf differ