I am trying to build an SPI module in verilog which transmits 8 bits of data, but when doing the shift operation I have noticed that shifting does not shift bits at all, while MOSI and MISO only take value of zero after the first cycle, which results in data on both side decaying to zero. What can I do to fix this?
Code for master:
module Master(input clk, input MISO,
output reg MOSI, output reg SS);
initial SS = 0;
reg [2:0] counter;
reg [7:0] Master_reg = 8'b11011011;
always # (posedge clk)
begin
if(!SS)
begin
if(^counter === 1'bx)
counter = 0;
else
counter = counter + 1;
MOSI = Master_reg[7];
Master_reg = Master_reg >> 1;
Master_reg[0] = MISO;
end
if(counter == 7)
SS = 1;
end
endmodule
Code for slave:
module Slave(input clk, input MOSI, input SS,
output reg MISO);
reg [2:0] counter;
reg [7:0] Slave_reg = 8'b11111111;
always # (posedge clk)
begin
if(!SS)
begin
if(^counter === 1'bx)
counter = 0;
else
counter = counter + 1;
MISO = Slave_reg[0];
Slave_reg = Slave_reg << 1;
Slave_reg[7] = MOSI;
end
end
endmodule
Transmission of given data (11011011 from master, 11111111 from slave) gives following result:
Edit: I am using EDA Playground as a simulator
There's a mistake in both master and slave. You're sending out the most significant bit of master_reg, but shifting that register to the right. You must shift it left instead.
Same with slave, the bit that's being sent is not the one toward which the data is shifted.
Btw, both the master and slave must shift to the same direction. Otherwise you'll get data reversed between master and slave.
Related
I'm designing an 8-bit signed sequential multiplier using Verilog. The inputs are clk (clock), rst (reset), a (8 bit multiplier), b (8 bit multiplicand), and the outputs are p (product) and rdy (ready signal, indicating multiplication is over). For negative inputs, I do a sign extension and save it in the 15 bit register variables multiplier and multiplicand. Here's my code:
module seq_mult (p, rdy, clk, reset, a, b);
input clk, reset;
input [7:0] a, b;
output [15:0] p;
output rdy;
reg [15:0] p;
reg [15:0] multiplier;
reg [15:0] multiplicand;
reg rdy;
reg [4:0] ctr;
always #(posedge clk or posedge reset) begin
if (reset)
begin
rdy <= 0;
p <= 0;
ctr <= 0;
multiplier <= {{8{a[7]}}, a};
multiplicand <= {{8{b[7]}}, b};
end
else
begin
if(ctr < 16)
begin
if(multiplier[ctr]==1)
begin
multiplicand = multiplicand<<ctr;
p <= p + multiplicand;
end
ctr <= ctr+1;
end
else
begin
rdy <= 1;
end
end
end //End of always block
endmodule
And here's my testbench:
`timescale 1ns/1ns
`define width 8
`define TESTFILE "test_in.dat"
module seq_mult_tb () ;
reg signed [`width-1:0] a, b;
reg clk, reset;
wire signed [2*`width-1:0] p;
wire rdy;
integer total, err;
integer i, s, fp, numtests;
// Golden reference - can be automatically generated in this case
// otherwise store and read from a file
wire signed [2*`width-1:0] ans = a*b;
// Device under test - always use named mapping of signals to ports
seq_mult dut( .clk(clk),
.reset(reset),
.a(a),
.b(b),
.p(p),
.rdy(rdy));
// Set up 10ns clock
always #5 clk = !clk;
// A task to automatically run till the rdy signal comes back from DUT
task apply_and_check;
input [`width-1:0] ain;
input [`width-1:0] bin;
begin
// Set the inputs
a = ain;
b = bin;
// Reset the DUT for one clock cycle
reset = 1;
#(posedge clk);
// Remove reset
#1 reset = 0;
// Loop until the DUT indicates 'rdy'
while (rdy == 0) begin
#(posedge clk); // Wait for one clock cycle
end
if (p == ans) begin
$display($time, " Passed %d * %d = %d", a, b, p);
end else begin
$display($time, " Fail %d * %d: %d instead of %d", a, b, p, ans);
err = err + 1;
end
total = total + 1;
end
endtask // apply_and_check
initial begin
// Initialize the clock
clk = 1;
// Counters to track progress
total = 0;
err = 0;
// Get all inputs from file: 1st line has number of inputs
fp = $fopen(`TESTFILE, "r");
s = $fscanf(fp, "%d\n", numtests);
// Sequences of values pumped through DUT
for (i=0; i<numtests; i=i+1) begin
s = $fscanf(fp, "%d %d\n", a, b);
apply_and_check(a, b);
end
if (err > 0) begin
$display("FAIL %d out of %d", err, total);
end else begin
$display("PASS %d tests", total);
end
$finish;
end
endmodule // seq_mult_tb
I also created a file called test_in.dat in which the test cases are stored (first line indicates number of test cases):
10
5 5
2 3
10 1
10 2
20 20
-128 2
10 -128
-1 -1
10 0
0 2
Now the problem is: the code works for only the first two inputs and for the last two inputs. For the remaining inputs, I get a different number than is expected. Can someone point out any logical error in my code that is causing this? Or if there's a much simpler strategy for doing the same, please let me know of that as well.
multiplicand is shifted to the left by ctr in each iteration if multiplier[ctr] is 1.
But ctr already includes the previous shift amounts, so you are shifting too far.
You should just shift multiplicand by 1 in every iteration unconditionally:
multiplicand <= multiplicand << 1;
if (multiplier[ctr] == 1)
begin
p <= p + multiplicand;
end
ctr <= ctr + 1;
You should also use nonblocking assignment for multiplicand. You might need to move the shifting to after adding it to p.
I tried to flatten an array with numbers into a variable in order to pass it as an input to a module in verilog. But, I get the error:
Port 1 (DATA_IN) of process_data expects 64 bits, got 4096. Pruning
4032 high bits of the expression.
I know that my module process_data in not ready yet and hence it does not work properly, but my problem for now is that the input is a lot more bits than it should.
Do you know how could I fix it?
module process_data(input wire [63:0] DATA_IN , input wire [6:0]AdrR , input wire [6:0]AdrW, input R_W , input Cen, input clk, input reset, output reg [63:0]Reg_Data_Out);
integer i;
reg [63:0]Memory[63:0]; //64 * 64 bit array
initial
begin
i=0;
//++for
repeat (64)
begin
Memory[i]=64'd1; //64 = number of the thesis that the vector has
i=i+1;
end
end
always #(negedge(clk))
//initial AdrR ,AdrW = 0; // 7'b0000_000;
begin
if(Cen == 1'b1) begin // cen = chip enabled
case (R_W)
1'b1:
//++check if not empty
Reg_Data_Out = Memory[AdrR]; // (read) out put memory context
1'b0:
//++check if not full
Memory[AdrW] = DATA_IN; // write input to memory
default:
Reg_Data_Out = 64'bxxxxxxxx;
endcase
end
end
endmodule
module TOP();
reg [63:0] inputdata1 [0:127]; //array
reg [64*64-1:0] flattened_inputdata1;
reg [6:0] AddressR,AddressW;
reg cen,clk, R_W, reset;
wire [63:0] Data_Out;
//pass the numbers
integer count;
initial
begin
count = 0;
while (count < 128) // Execute loop till count is 127. exit at count 128
begin
// every timh that the integer variable count takes must be also passed into reg inputdata1
inputdata1[count] = count;
count = count + 1;
end
end
//flattening
initial
begin
count = 0;
while (count < 128) // Execute loop till count is 127. exit at count 128
begin
flattened_inputdata1[64*count +: 64] = inputdata1[count];
//flattened_inputdata1[(64*count) +63) : (64*count)] = inputdata1[count]; //declare a number is dekadikos
count = count + 1;
end
end
//call module for data I/O
process_data process_data( flattened_inputdata1, AddressR, AddressW, R_W , cen, clk, reset, Data_Out); //reset does not do anything yet
always #10 clk=~clk;
initial
begin
$display("flattenedinputdata1=%d", flattened_inputdata1);
cen=1'b1; //chip enabled
#50
R_W=1'b1; //read
AddressR=7'b0000_000;
#50
//R_W=1'b1; //read
//AddressR=7'b0000_001;
$finish; //#50 $finish;
end
endmodule
edaplayground link
You can see from the declarations that the sizes are different:
input wire [63:0] DATA_IN
and the thing you're passing in to it:
reg [64*64-1:0] flattened_inputdata1;
DATA_IN is 64 bits and flattened_inputdata1 is 4096 bits. So you'll need to change one of them so that the two sizes match.
I'm trying to implement a Verilog module that writes in a Lattice UP5K SPRAM hardware core using the Yosys SB_SPRAM256KA block. Note that there are little or no documentation/examples about usage of this black box block. The main purpose is implementing an echo or delay in an audio digital system.
I have two clocks the frame clock lrclk and the bit clock bclk, note that each period of frame clock has 64 bit clocks periods.
I tried to, with a sensitivity list in the blck, cycle a read/write process in the SPRAM. I implement a state machina that:
S1: Put the input data in the input port of the RAM, enable the write_enable signal and set the writing pointer to RAM address.
S2: (Data supposed to be written) Disables write_enable signal and set the reading pointer to RAM address.
S3: (Data supposed to be loaded on output buffer of the RAM). Set the module output from the RAM output buffer and resets the state machine.
This is the module code:
module echo(
input wire bclk,
input wire lrclk,
input wire [DATALEN-1:0] right_in,
output reg [DATALEN-1:0] right_out,
);
localparam ADDRLEN = 14;
localparam DATALEN = 16;
reg [ADDRLEN-1:0] rd_ptr = 0;
reg [ADDRLEN-1:0] wr_ptr = (2**ADDRLEN)/2;
reg [2:0] sm = 0;
reg wren;
reg [ADDRLEN-1:0] memaddr;
reg [DATALEN-1:0] datain;
reg [DATALEN-1:0] dataout;
SB_SPRAM256KA M1 (
.ADDRESS(memaddr),
.DATAIN(datain),
.MASKWREN(4'b1111),
.WREN(wren),
.CHIPSELECT(1'b1),
.CLOCK(bclk),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b0),
.DATAOUT(dataout)
);
always #(posedge lrclk) begin
sm <= 1;
end
always #(posedge bclk) begin
if (sm === 1) begin
datain <= right_in;
wren <= 1;
memaddr <= wr_ptr;
sm <= 2;
end else if (sm === 2) begin
wren <= 0;
memaddr <= rd_ptr;
sm <= 3;
end else if (sm === 3) begin
right_out <= dataout;
wr_ptr <= (wr_ptr + 1);
rd_ptr <= (rd_ptr + 1);
sm <= 0;
end
end
endmodule
I expect to have errors on systhesis time or misfunctional behaving of the implementation, but I obtain this Yosis error:
5.11. Executing WREDUCE pass (reducing word size of cells).
Removed top 31 bits (of 32) from port B of cell main.$add$main.v:70$2 ($add).
Removed top 1 bits (of 32) from port Y of cell main.$add$main.v:70$2 ($add).
Removed top 2 bits (of 3) from FF cell main.$techmap\E1.$procdff$117 ($dff).
make: *** [main.bin] Segmentation fault: 11
.POWEROFF(1'b0) should be 1'b1 right?
See the "iCE40 SPRAM Usage Guide" for more information.
I am making an average that resets every period on EDA Playground. No errors are displayed on the simulator, Icarus Verilog, but the outputs are continually unassigned (which, of course, is not what I intended).
Here is my design:
module shift
(
input [13:0] in,
input clock,
output [31:0] sum,
output [14:0] avg);
integer reset;
reg [31:0] sum_reg;
reg [14:0] avg_reg;
always #(posedge clock)
if (reset == 8) begin
avg_reg = sum_reg >> 3;
sum_reg = 0;
reset = 0;
end else begin
sum_reg = sum_reg + in;
reset = reset + 1;
end
assign sum = sum_reg;
assign avg = avg_reg;
endmodule
Here is my testbench:
module shift_tb;
reg [13:0] in;
reg clock = 1'b0;
reg reset;
wire [31:0] sum;
wire [14:0] avg;
shift s
(
.in(in),
.clock(clock),
.sum(sum),
.avg(avg));
integer f;
initial begin
for (f = 9000; f < 10000; f = f + 10) begin
in = f;
$display("in = %d, sum = %d, avg = %d", in, sum, avg);
end
end
always
#1 clock = ~clock;
endmodule
What is wrong with this code?
One problem is reset is an integer that is initially x and stays that way. You need a way of initializing it to 0.
Another problem is your testbench for-loop has no delay. You should add #(nedgedge clk)
I am trying to simulate the following code for an asynchronous ram in verilog. But dout remains xxxx all the time.
The first time I tried the code dout was equal to din for the time when write signal was 1.After that it was all xxxx.Can anyone tell me the problem?It'd be great if you could suggest a better code.
module ram(cs,wr,addr,din,dout);
parameter adds = 10, wsize =16, memsize =1024;
input cs,wr;
input [adds-1:0] addr;
input [wsize-1 : 0]din;
output [wsize-1:0]dout;
reg [wsize-1:0] mem [memsize-1:0];
assign dout = mem[addr];
always #(cs or wr)
begin
if(wr) mem[addr]= din;
end
endmodule
The test bench for the above code is :
module ramtest;
// Inputs
reg cs;
reg wr;
reg [9:0] addr;
reg [15:0] din;
// Outputs
wire [15:0] dout;
integer k,myseed;
// Instantiate the Unit Under Test (UUT)
ram uut (
.cs(cs),
.wr(wr),
.addr(addr),
.din(din),
.dout(dout)
);
initial begin
for(k = 0; k<=1023; k = k+1)
begin
din = k % 256; wr = 1; cs= 1;addr= k ;
end
repeat(20)
begin
#2 addr = $random(myseed) % 1024 ;
wr = 0; cs =1;
$display("Address = %5d, data = %4d",addr,dout);
end
end
initial myseed = 35 ;
endmodule
Several errors:
Your wr and cs do not change so the always #( cs or wr) is only
entered once for write and once for read.
Your 'write' code in
the testbench for(k = 0; k<=1023; k = k+1) does not have a delay.
So there is no time for the write to actually happen.
However the biggest danger is that you 'just' add the address to the sensitivity list and it all 'works':
always #(cs or wr or addr)
It would probably have helped you if you had first looked up a datasheet of an async RAM. They do not work the way you model it. There data is stored when the CS or Write goes away (which ever first). The data and address have to be stable a certain time before and after that.
In your model you change the address whilst keeping the WR and CS active. In real life the address does not change from one value to another instantaneous. It will go from for example 0000 to 000F but the bits will change one at a time: 0000 => 0004 => 0005 => 000D ==> 000F. Thus you could have messed up the contents of 5 different addresses.
Make a write signal from CS and WR: do_write = cs & wr; Do the actual write when that signal goes away: always #(negedge do_write) .....`.
It appears that you are trying to write an asynchronous RAM. In that case, you need to also add addr and din to your sensitivity list. Also, dout should get mem[addr] when cs is high and wr is low. In your testbench, you need to add a delay in your for loop before supplying the next input. One possible implementation is as follows:
module ram(oe, cs, wr, addr, din, dout);
parameter adds = 6,
wsize = 16,
memsize = 1 << adds;
input cs, wr;
input oe; // output enable
input [adds-1:0] addr;
input [wsize-1:0] din;
output [wsize-1:0] dout;
reg [wsize-1:0] dout;
reg [wsize-1:0] mem [memsize-1:0];
always #(cs, wr, oe, addr, din)
begin
if (cs) begin
if (wr) mem[addr] <= din;
else if (oe) dout <= mem[addr];
end
end
endmodule
And corresponding testbench could be:
module ram_tb;
parameter adds = 6,
wsize = 16,
memsize = 1 << adds;
reg cs, wr;
reg oe; // output enable
reg [adds-1:0] addr;
reg [wsize-1:0] din;
wire [wsize-1:0] dout;
integer k, myseed;
// Instantiate the Unit Under Test (UUT)
ram uut (
.cs(cs),
.wr(wr),
.oe(oe),
.addr(addr),
.din(din),
.dout(dout)
);
initial myseed = 35;
initial begin
for(k = 0; k < memsize; k = k+1) begin
#2
din <= k % 256;
wr <= 1;
cs <= 1;
addr <= k;
oe <= 0;
end
repeat(20) begin
#2
addr <= ($random(myseed)) % memsize ;
wr <= 0;
cs <= 1;
oe <= 1;
$display("Address = %5d, data = %4d", addr, dout);
end
#10 $finish;
end
endmodule