I'm working on an SPI in Verilog. I will post what I came up with here. This is an educational project compiled according to the general principle from Wikipedia. There is only one mode - exchange along the rising edge of synchronizing pulses. The problem is this: my code is not very good. It does not implement all functions (only the basic one); due to confusion with discontinuous/continuous assignment, a discrepancy arises between the command for selecting peripherals and signals for the slave, etc.
Please tell me how to improve it and what techniques are best to use? I deliberately did not use ready-made projects in order to understand in general how the SPI works.
Master code:
module Master(clock,AIBO,AOBI,periphery,iSS_out,rCount_out);
input clock; //Standart clock
input periphery; //Future command on "you must work with periphery!"
input [3:0] AIBO; //data to periphery
output [3:0] AOBI; //data from periphery
output [3:0] rCount_out; //Count out
output iSS_out; //SS out after //conditional processing
//Registers and starting points
reg [3:0] RA = 4'b0101;
reg [3:0] rCount = 4'b0000;
reg iSS;
always @(negedge periphery) begin //Count restart
rCount = 4'b0000;
end
always @(posedge clock) begin
if ((periphery == 1'b1 || periphery == 1'b0) && rCount < 3) begin //SS conditional processing
iSS <= periphery;
end
else if ((periphery == 1'b1 || periphery == 1'b0) && rCount >= 3) begin
iSS <= 1'b1;
end
if (iSS == 1'b1) begin
RA <= RA;
rCount <= rCount;
end
else if (iSS == 1'b0) begin
RA <= {AIBO[0],RA[3:1]}; //Exchanging
rCount <= rCount + 4'b0001;
end
else if (iSS == 1'b0) begin
RA <= RA;
rCount <= rCount;
end
end
assign AOBI = RA;
assign rCount_out = rCount;
assign iSS_out = iSS;
endmodule
Slave code:
module Slave(clock,BIAO,BOAI,iSS);
input clock;
input iSS;
input [3:0] BIAO;
output [3:0] BOAI;
//Registers
reg [3:0] RB = 4'b1110;
always @(posedge clock) begin
if (iSS == 1'b1) begin
RB <= RB;
end
else if (iSS == 1'b0) begin
RB <= {BIAO[0],RB[3:1]};
end
end
assign BOAI = RB;
endmodule
Top code (testbench):
`timescale 1ns / 1ps
module Top;
reg clock;
reg periphery;
wire [3:0] A_out;
wire [3:0] B_out;
wire [3:0] rCount_out;
wire iSS_out;
Master uut1(.clock(clock),.AIBO(B_out),.AOBI(A_out),.periphery(periphery),.iSS_out(iSS_out),.rCount_out(rCount_out));
Slave uut2(.clock(clock),.BIAO(A_out),.BOAI(B_out),.iSS(iSS_out));
initial begin
// Initialize Inputs
clock = 1'b0;
periphery = 1'b1; #5;
periphery = 1'b0; #10;
periphery = 1'b1; #15;
periphery = 1'b0; #10;
periphery = 1'b1; #15;
periphery = 1'b0; #10;
// Wait 100 ns for global reset to finish
end
always #1 clock = ~clock;
endmodule
The code seems to work, information is exchanged between Master and Slave, but there is a feeling that the code can be significantly improved.