12-hour clock code output "pm" has one hour less than the standard answer - verilog

HDLBits 12-hour clock
I wrote the answer for this question, but something wrong occurred. I can't find out where I'm wrong because the answer just tells me how many mismatches I have. Can some one tell me please?
Here are results from HDLBIts:
result
result
result
And here is my code:
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
wire [1:0] ssc, mmc, hhc;
assign ssc[0] = ss[3]&ss[0];
counter4buenld cssl(clk, ena, reset, ssc[0], 4'h0, ss[3:0]);
assign ssc[1] = ss[4]&ss[6]&ssc[0];
counter4buenld cssh(clk, ena&ssc[0], reset, ssc[1], 4'h0, ss[7:4]);
assign mmc[0] = mm[3]&mm[0]&ssc[1];
counter4buenld cmml(clk, ena&ssc[1], reset, mmc[0], 4'h0, mm[3:0]);
assign mmc[1] = mm[4]&mm[6]&mmc[0];
counter4buenld cmmh(clk, ena&mmc[0], reset, mmc[1], 4'h0, mm[7:4]);
assign hhc[0] = hh[3]&hh[0]&mmc[1];
assign hhc[1] = hh[4]&hh[1]&mmc[1];
counter4buenld chhl(clk, ena&mmc[1], 1'b0, reset|hhc[0]|hhc[1], {2'b00, reset, ~reset}, hh[3:0]);
counter4buenld chhh(clk, ena&hhc[0], 1'b0, reset|hhc[1], {3'b000, reset}, hh[7:4]);
reg pml;
assign pm = pml;
always#(posedge clk) begin
if(reset) begin
pml <= 1'b0;
end
else begin
if(hh[4]&hh[0]&mmc[1]) begin
pml <= ~pml;
end
else begin
pml <= pml;
end
end
end
endmodule
module counter4buenld(
input clk,
input ena,
input reset,
input load,
input [3:0] d,
output reg [3:0] q
);
always#(posedge clk) begin
if(reset)
q <= 4'h0;
else
if(load)
q <= d;
else
q <= q + ena;
end
endmodule

The HDLBits waveform snapshots do not give you enough visibility to debug your problem. You need to create your own testbench and view the complete waveforms.
When you do so, you would see that your hour increments from 9 to 11. It skips 10.
Your Verilog code is too difficult to understand. Here is a simpler approach, including a trivial testbench:
module top_module (
input clk,
input reset,
input ena,
output reg pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss
);
reg [7:0] hhd, mmd, ssd;
function [7:0] bcd ([7:0] in);
bcd[3:0] = in % 10;
bcd[7:4] = in / 10;
endfunction
assign ss = bcd(ssd);
assign mm = bcd(mmd);
assign hh = bcd(hhd);
always#(posedge clk) begin
if (reset) begin
pm <= 0;
end else if (ena && hhd==11 && mmd==59 && ssd==59) begin
pm <= ~pm;
end
end
always#(posedge clk) begin
if (reset) begin
ssd <= 0;
end else if (ena) begin
if (ssd==59) begin
ssd <= 0;
end else begin
ssd <= ssd + 1;
end
end
end
always#(posedge clk) begin
if (reset) begin
mmd <= 0;
end else if (ena && ssd==59) begin
if (mmd==59) begin
mmd <= 0;
end else begin
mmd <= mmd + 1;
end
end
end
always#(posedge clk) begin
if (reset) begin
hhd <= 12;
end else if (ena && mmd==59 && ssd==59) begin
if (hhd==12) begin
hhd <= 1;
end else begin
hhd <= hhd + 1;
end
end
end
endmodule
module tb;
bit clk;
bit ena=1;
bit reset=1;
wire pm;
wire [7:0] hh;
wire [7:0] mm;
wire [7:0] ss;
top_module dut (
// Inputs:
.clk (clk),
.ena (ena),
.reset (reset),
// Outputs:
.hh (hh),
.mm (mm),
.pm (pm),
.ss (ss)
);
always #5 clk++;
initial begin
#12 reset=0;
#5ms $finish;
end
endmodule
Compare MINE vs. YOURS:

Related

incrementing mod counter every n clock cycle

This is the verilog code for mod 64 counter, incrementing every clock cycle
module modulus64counter
#(parameter N=64,
parameter WIDTH=5)
(input clk,
input rstn,
output reg[WIDTH-1:0] out);
integer i;
always #(posedge clk) begin
if(!rstn) begin
out<=0;
end
else begin
if(out==N-1)
out<=0;
else
out<= out+1;
end
end
endmodule
and the test bench is
module modulus64countertb;
// Inputs
reg clk;
reg rstn;
// Outputs
wire [4:0] out;
// Instantiate the Unit Under Test (UUT)
modulus64counter uut (
.clk(clk),
.rstn(rstn),
.out(out)
);
always #10 clk = ~clk;
initial begin
// Initialize Inputs
clk = 1;
rstn = 0;
$monitor ("T=%0t rstn=%0b out=0X%h", $time,rstn,out);
repeat(2) #(posedge clk);
rstn <=1;
repeat(50) #(posedge clk);
$finish;
end
endmodule
Now if i want to increment the value of out every "n" clock cycle instead of consecutive clock cycle , how can i modify the program
Kindly help
Updated 20220131
Updated the code to produce output after every 2 clock cycles. Similarly, if you wish to delay for even more clock cycle, the simplest way is to continuously flopping it.
For a better implementation, you can try out a shift register.
module modulus64counter #(
parameter N=64,
parameter WIDTH=8,
parameter DELAY_CYCLE=2
)(
input clk,
input rstn,
output reg[WIDTH-1:0] out,
output reg[WIDTH-1:0] actual_out
);
integer i;
reg [WIDTH-1:0] cntr;
reg [WIDTH-1:0] dly1clk;
always #(posedge clk) begin
if(!rstn) begin
out <= 0;
dly1clk <= 0;
end else if(out == DELAY_CYCLE-1) begin
out <= 0;
dly1clk <= dly1clk + 1;
end else begin
out <= out + 1;
end
end
always #(posedge clk) begin
if(!rstn) begin
actual_out <= 0;
end else begin
actual_out <= dly1clk;
end
end
endmodule
The code below should work for you. You can always swap the out and actual_out if you insist on using out as the final counting variable.
Also, removing the out on the monitor line in the testbench will only print the value when it reaches mod n. I kept both out and actual_out on testbench's monitor to ease debugging purpose.
Verilog code
module modulus64counter #(
parameter N=64,
parameter WIDTH=8
)(
input clk,
input rstn,
output reg[WIDTH-1:0] out,
output reg[WIDTH-1:0] actual_out
);
integer i;
reg [WIDTH-1:0] cntr;
always #(posedge clk) begin
if(!rstn) begin
out <= 0;
actual_out <= 0;
end else if(out == N-1) begin
out <= 0;
actual_out <= actual_out + 1;
end else begin
out <= out + 1;
end
end
endmodule
Testbench
module modulus64countertb;
// Inputs
reg clk;
reg rstn;
// Outputs
wire [7:0] out;
wire [7:0] actual_out;
// Instantiate the Unit Under Test (UUT)
modulus64counter uut (
.clk(clk),
.rstn(rstn),
.out(out),
.actual_out(actual_out)
);
always #10 clk = ~clk;
initial begin
// Initialize Inputs
clk = 1;
rstn = 0;
$monitor ("T=%0t rstn=%0b out=%d actual_out=%d", $time,rstn,out,actual_out);
repeat(2) #(posedge clk);
rstn <=1;
repeat(200) #(posedge clk);
$finish;
end
endmodule
Output result simulated using edaplayground:

Clock Divider for 50MHz to 1MHz - Verilog

I have written the code for SPI Master and I want the output SPI frequency to be 1MHz.
But, when I run the behaviroal simulation, I don't get a 1MHz spi_sclk. Any suggestions what is wrong with my code? Thanks!
module spi_master(
input wire clk,
input wire reset,
input wire [15:0] datain,
output wire spi_cs_l,
output wire spi_sclk,
output wire spi_data,
output wire [4:0] counter
);
reg [15:0] MOSI;
reg [4:0] count;
reg cs_l;
reg sclk = 1'b0;
reg [2:0] state;
reg [4:0] clk_counter = 0;
// SPI Output Clock frequency = 1MHz
always #(posedge clk) begin
if (clk_counter == 24) begin
clk_counter <= 0;
sclk <= ~sclk;
end
else begin
clk_counter <= clk_counter + 1'd1;
end
end
always #(posedge clk or posedge reset) begin
if(reset) begin
MOSI <= 16'b0;
count <= 5'd16;
cs_l <= 1'b1;
end
else begin
case (state)
0:begin
cs_l <= 1'b1;
state <= 1;
end
1:begin
cs_l <= 1'b0;
MOSI <= datain[count-1];
count <= count-1;
state <= 2;
end
2:begin
if(count > 0) begin
state <= 1;
end
else begin
count <= 16;
state <= 0;
end
end
default:state<=0;
endcase
end
end
assign spi_cs_l = cs_l;
assign spi_sclk = sclk;
assign spi_data = MOSI;
assign counter = count;
endmodule
Testbench
module spi_master_tb;
// Inputs
reg clk;
reg reset;
reg [15:0] datain;
// Outputs
wire spi_cs_l;
wire spi_sclk;
wire spi_data;
wire [4:0] counter;
spi_master dut(
.clk(clk),
.reset(reset),
.counter(counter),
.datain(datain),
.spi_cs_l(spi_cs_l),
.spi_sclk(spi_sclk),
.spi_data(spi_data)
);
initial begin
clk = 0;
reset = 1;
datain = 0;
end
always #5 clk=~clk;
initial begin
#10 reset = 1'b0;
#10 datain = 16'hA569;
#335 datain = 16'h2563;
#335 datain = 16'h9B63;
#335 datain = 16'h6A61;
end
endmodule
Waveform
It helps if you create Minimal reproducible example. Also your waveform don't include an important signal clk_counter.
Try this in your testbench, if it doesn't work you at least have the minimum reproducible example.
I changed the initialization of clk_counter and in the increment I simply added 1 instead of 1'b1, if you wanted to be strict you could add a 5-bit wide 1 (5'b1).
module spi_master(
input wire clk,
input wire reset,
output wire spi_sclk,
);
reg [4:0] clk_counter;
// SPI Output Clock frequency = 1MHz
always #(posedge clk) begin
if(reset) begin
sclk <= 1'b0;
clk_counter <= 1;
end
else begin
if (clk_counter == 24) begin
clk_counter <= 0;
sclk <= ~sclk;
end
else begin
clk_counter <= clk_counter + 1;
end
end
end
assign spi_sclk = sclk;
endmodule

Designing cpu but Value isn't moving in verilog

module sram(addr,clk,din,dout,we); //sram.v
parameter addr_width = 12, word_depth = 110, word_width = 16;
input clk,we;
input [addr_width-1:0] addr;
input [word_width-1:0] din;
output [word_width-1:0] dout;
reg [word_width-1:0]mem[0:word_depth-1];
reg [word_width-1:0]dout;
always # (posedge clk) begin
if(!we)
mem[addr] <= din[word_width-1:0];
end
always # (posedge clk) begin
if(we)
dout[word_width-1:0] <= mem[addr];
end
endmodule
module cpu(clk,reset); //cpu.v
input clk, reset;
reg [15:0] dr, ac, ir;
reg [11:0] addr, pc;
reg [2:0] opcode;
reg [5:0]t;
reg we;
reg sc;
reg [15:0] din;
wire [15:0] dout;
sram sram(addr,clk,din,dout,we);
always # (posedge clk or negedge reset) begin
if(!reset) begin
ir <= 16'd0; dr <= 16'd0; ac <= 16'd0; addr <= 12'd0; pc <= 12'd0; sc <= 0; t <= 0; we<=1;
end
else if(t==0) begin
addr <= pc; sc<=1;
end
else if(t==1) begin
ir[15:0] <= dout[addr]; pc <= pc+1;
end
else if(t==2) begin
opcode <= ir[14:12];
addr <= ir[11:0]; //no indirect mode, no i
sc<=0;
end
else if(t==3) begin
if(opcode==3'b111) begin
ac <= 0;
end
if(opcode==3'b000) begin
end
end
end
always # (negedge clk) begin
if(!sc) begin
t<=0;
end
else t<=t+1;
end
endmodule
module tbcpu(); //tbcpu.v
reg clk,reset;
integer file_pointer;
cpu cpu(clk,reset);
always #5 clk = ~clk;
initial begin
$readmemb("memory.dat", tbcpu.cpu.sram.mem); //assembly
clk = 0; reset = 1;
#1 reset = 0;
#1 reset = 1;
#100 $finish;
end
endmodule
I'm designing cpu and having hard time because ir[15:0] value doesn't change and fixed in 0000.
I'm expecting when t comes 01 (in 15ns),
this conditional sentence work :
else if(t==1) begin
ir[15:0] <= dout[addr]; pc <= pc+1;
so dout[0] value 7800 go into ir[15:0], but it doesn't work. How can I fix this? I'm also confusing about sc, t timing so I solved that problem by changing sc,t values in negedge clk.
Change:
ir[15:0] <= dout[addr];
to:
ir[15:0] <= dout;
dout[addr] selects a single bit of the 16-bit dout signal. You were treating dout as if it were a memory variable, instead of a vector signal. At 15ns, dout='h7800 and addr=0, which means ir=dout[addr]=dout[0]=0.

Verilog code 2 errors i can't find: Would be grateful for an extra pair of eyes to spot a mistake i might've overlooked

I'm writing a verilog code where i'm reading two files and saving those numbers into registers. I'm then multiplying them and adding them. Pretty much a Multiplication Accumulator. However i'm having a hard frustrating time with the code that i have. It read the numbers from the files correctly and it multiples but here is the problem? When i first run it using ModelSim, I reset everything so i can clear out the accumulator. I then begin the program, but there is always this huge delay in my "macc_out" and i cannot seem to figure out why. This delay should not be there and instead it should be getting the result out A*B+MAC. Even after the delay, it's not getting the correct output. My second problem is that if i go from reset high, to low (start the program) and then back to reset high ( to reset all my values), they do not reset! This is frustrating since i've been working on this for a week and don't know/can't see a bug. Im asking for an extra set of eyes to see if you can spot my mistake. Attached is my code with the instantiations and also my ModelSim functional Wave Form. Any help is appreciated!
module FSM(clk,start,reset,done,clock_count);
input clk, start, reset;
output reg done;
output reg[10:0] clock_count;
reg [0:0] macc_clear;
reg[5:0] Aread, Bread, Cin;
wire signed [7:0] a, b;
wire signed [18:0] macc_out;
reg [3:0] i,j,m;
reg add;
reg [0:0] go;
reg[17:0] c;
parameter n = 8;
reg[1:0] state;
reg [1:0] S0 = 2'b00;
reg [1:0] S1 = 2'b01;
reg [1:0] S2 = 2'b10;
reg [1:0] S3 = 2'b11;
ram_A Aout(.clk(clk), .addr(Aread), .q(a));
ram_B Bout(.clk(clk), .addr(Bread), .q(b));
mac macout(.clk(clk), .macc_clear(macc_clear), .A(a), .B(b), .macc_out(macc_out), .add(add));
ram_C C_in(.clk(clk), .addr(Cin), .q(c));
always #(posedge clk) begin
if (reset == 1) begin
i <= 0;
add<=0;
j <= 0;
m <= 0;
clock_count <= 0;
go <= 0;
macc_clear<=1;
end
else
state<=S0;
case(state)
S0: begin
// if (reset) begin
// i <= 0;
// add<=0;
// j <= 0;
// m <= 0;
// clock_count <= 0;
// go <= 0;
// macc_clear<=1;
// state <= S0;
// end
macc_clear<=1;
done<=0;
state <= S1;
end
S1: begin
add<=1;
macc_clear<=0;
clock_count<=clock_count+1;
m<=m+1;
Aread <= 8*m + i;
Bread <= 8*j + m;
if (m==7) begin
state <= S2;
macc_clear<=1;
add<=0;
end
else
state <=S1;
end
S2: begin
add<=1;
macc_clear<=0;
m<=0;
i<=i+1;
if (i<7)
state<=S1;
else if (i==8) begin
state<=S3;
add<=0;
end
end
S3: begin
add<=1;
i<=0;
j<=j+1;
if(j<7)
state<=S1;
else begin
state<=S0;
done<=1;
add<=0;
end
end
endcase
end
always # (posedge macc_clear) begin
Cin <= 8*j + i;
c <= macc_out;
end
endmodule
module mac(clk, macc_clear, A, B, macc_out, add);
input clk, macc_clear;
input signed [7:0] A, B;
input add;
output reg signed [18:0] macc_out;
reg signed [18:0] MAC;
always #( posedge clk) begin
if (macc_clear) begin
macc_out <= MAC;
MAC<=0;
end
else if (add) begin
MAC<=(A*B)+ MAC;
macc_out<=MAC;
end
end
endmodule
module ram_A( clk, addr,q);
output reg[7:0] q;
input [5:0] addr;
input clk;
reg [7:0] mem [0:63];
initial begin
$readmemb("ram_a_init.txt", mem);
end
always #(posedge clk) begin
q <= mem[addr];
end
endmodule
module ram_C(clk,addr, q);
input [18:0] q;
input [5:0] addr;
input clk;
reg [18:0] mem [0:63];
always #(posedge clk) begin
mem[addr] <= q;
end
endmodule
ModelSim Functional Simulation Wave Form
1) Take a look at the schematic view for your MACC module - I think some of your "problems" will be obvious from that;
2) Consider using an always#(*) (Combinational) block for your FSM control signals (stuff like add or macc_clear) rather than a always#(posedge clk) (sequential) - it makes the logic to assert them easier. Right now they're registered, so you have a cycle delay. ;
3) In your MAC, you clear the MAC register on a reset, but you don't clear the macc_out register.
In short, I think you need to step back, and consider which signals are combinational logic, and which ones are sequential and need to be in registers.

Event counter in verilog

i'm a verilog beginner, i'm try to write a "event counter" on verilog.... this is my code, but it work only with "period" set to 16'b0000000000000001, if try set period to 16'b0000000000001000, result(out_event) is always '0'.
Someone can help me to fix it ?
module mymodule(
input wire clk,
input wire enable,
input wire reset,
input wire [15:0] period,
input wire in_event,
output reg out_event
);
reg en = 1'b0;
reg re = 1'b0;
reg [15:0] count = 16'b0000000000000000;
always #(posedge clk) en <= enable;
always #(posedge clk) re <= reset;
always #(in_event)begin
if(in_event == 1'b1)begin
if(re)begin
count <= 0 ;
out_event <= 1'b0;
end else begin
if(en) begin
if(count == period-1)begin
out_event <= 1'b1;
count <= 0;
end else begin
count <=count + 1;
out_event <= 1'b0;
end
end else begin
out_event <= 1'b0;
end
end
end else begin
out_event <= 1'b0;
end
end
endmodule
thanks in advance
The counter counts number of posedge of in_event wire. So, can you use #(posedge in_event)?
I simulated your code, providing a testbench to it.
I do not have much knowledge about hardware synthesis, but personally, I would suggest to write your logic based on edge/level of clock.
This code works completely well. Have a look at this link.
You can configure various values of period in testbench, hope this will be helpful.
I came up with a test bench and the design for your problem and it works.
`timescale 1s / 1s
module TB();
reg clk;
reg enable;
reg reset;
reg [15:0] period;
wire out_event;
wire [15:0] counter;
initial begin
clk = 1'b0;
forever begin
#1 clk = ~clk;
end
end
stack_exch_code test (.clk(clk),
.enable(enable),
.reset(reset),
.period(period),
.out_event(out_event),
.tb_counter(counter)
);
integer i;
initial
begin
#(negedge clk) reset = 1'b1; enable = 1'b0; period = 16'h0000;
#(negedge clk) reset = 1'b0; enable = 1'b1; period = 16'h00FF;
for (i = 0 ; i < 500 ; i = i + 1) begin
#(negedge clk) period = period - 1;
#(posedge clk) $display ("Period = %h , Counter = %h, Out_Event = %b ", period, counter, out_event);
end
#(negedge clk) $finish;
end
endmodule //TB
module stack_exch_code (input clk,
input enable,
input reset,
input [15:0] period,
//input inevent,
output reg out_event,
output [15:0] tb_counter
);
// initialization doesnt matter in hardware, its not C or C++
reg en;
reg re;
reg [15:0] count;
always # (posedge clk) begin
re <= reset;
en <= enable;
end
always # (posedge clk) begin
if (re) begin
count <= 16'h0000;
out_event <= 1'b0;
end
else if (en) begin
if ((count == period - 1) && !(period == 16'h0000)) begin
out_event <= 1'b1;
count <= 16'h0000;
end
else if (!(period == 16'h0000)) begin
count <= count + 1;
out_event <= 1'b0;
end
else if (period == 16'h0000)
out_event <= 1'b0;
end
end
assign tb_counter = count;
endmodule //stack_exch_code

Resources