I am doing a timer ip project.
// timer.v
// Code your design here
// Code your design here
`include "register_control.sv"
`include "logic_control.sv"
`include "counter.sv"
module timer #(parameter ADDR_WIDTH = 8,
parameter DATA_WIDTH = 8,
parameter WAIT = 0
)
(pclk, presetn, psel, penable, pwrite, paddr, pwdata, prdata, pready, pslverr, s_ovf, s_udf, clk_in1, clk_in2, clk_in3, clk_in4);
input wire pclk;
input wire presetn;
input wire psel;
input wire penable;
input wire pwrite;
input wire [ADDR_WIDTH-1:0] paddr;
input wire [DATA_WIDTH-1:0] pwdata;
output reg [DATA_WIDTH-1:0] prdata;
output reg pready;
output reg pslverr;
output reg s_ovf;
output reg s_udf;
input wire clk_in1;
input wire clk_in2;
input wire clk_in3;
input wire clk_in4;
reg [DATA_WIDTH-1:0] tdr_reg;
reg [DATA_WIDTH-1:0] tcr_reg;
reg [DATA_WIDTH-1:0] tsr_reg;
wire clk_in;
wire up_down;
wire enable;
wire load_tdr;
reg [DATA_WIDTH-1:0] cnt;
register_control #(.WAIT(WAIT)) dut1 (
.pclk (pclk),
.presetn (presetn),
.psel (psel),
.penable (penable),
.pwrite (pwrite),
.paddr (paddr),
.pwdata (pwdata),
.prdata (prdata),
.pready (pready),
.pslverr (pslverr),
.s_ovf (s_ovf),
.s_udf (s_udf),
.tdr_reg (tdr_reg),
.tcr_reg (tcr_reg),
.tsr_reg (tsr_reg)
);
logic_control dut2 (
.clk_in1 (clk_in1),
.clk_in2 (clk_in2),
.clk_in3 (clk_in3),
.clk_in4 (clk_in4),
.tcr_reg (tcr_reg),
.clk_in (clk_in),
.up_down (up_down),
.enable (enable),
.load_tdr (load_tdr)
);
counter dut3 (
.pclk (pclk),
.presetn (presetn),
.clk_in (clk_in),
.up_down (up_down),
.tdr_reg (tdr_reg),
.enable (enable),
.load_tdr (load_tdr),
.cnt (cnt),
.s_ovf (s_ovf),
.s_udf (s_udf)
);
endmodule
// Code your design here
module register_control #(parameter ADDR_WIDTH = 8,
parameter DATA_WIDTH = 8,
parameter WAIT = 0
)
(pclk, presetn, psel, penable, pwrite, paddr, pwdata, prdata, pready, pslverr, tdr_reg, tcr_reg, tsr_reg, s_ovf, s_udf);
input wire pclk;
input wire presetn;
input wire psel;
input wire penable;
input wire pwrite;
input wire [ADDR_WIDTH-1:0] paddr;
input wire [DATA_WIDTH-1:0] pwdata;
output reg [DATA_WIDTH-1:0] prdata;
output reg pready;
output reg pslverr;
input wire s_ovf;
input wire s_udf;
output reg [DATA_WIDTH-1:0] tdr_reg;
output reg [DATA_WIDTH-1:0] tcr_reg;
output reg [DATA_WIDTH-1:0] tsr_reg;
localparam IDLE = 2'b00,
SETUP = 2'b01,
ACCESS = 2'b10;
reg [WAIT-1:0] wait_signal;
reg [1:0] current_state;
reg [1:0] next_state;
always @(*) begin
case(current_state)
IDLE: begin
wait_signal = WAIT + 1;
pready = 1'b0;
pslverr = 1'b0;
if(psel & ~penable) begin
next_state = SETUP;
end else begin
next_state = IDLE;
end
end
SETUP: begin
if(psel & penable) begin
if(wait_signal == 0) begin
pready = 1'b1;
if(paddr > 8'h02) begin
pslverr = 1'b1;
end
next_state = IDLE;
end else begin
next_state = ACCESS;
end
end else begin
next_state = SETUP;
end
end
ACCESS: begin
if(wait_signal != 0) begin
next_state = ACCESS;
end else begin
pready = 1'b1;
if(paddr > 8'h02) begin
pslverr = 1'b1;
end
next_state = IDLE;
end
end
default:
next_state = IDLE;
endcase
end
always @(posedge pclk or negedge presetn) begin
if(~presetn) begin
current_state <= IDLE;
end else begin
current_state <= next_state;
wait_signal <= wait_signal - 1;
end
end
always @(posedge pclk or negedge presetn) begin
if(~presetn) begin
tdr_reg <= 8'h00;
tcr_reg <= 8'h00;
tsr_reg <= 8'h00;
end else begin
// write transaction
if(pready & psel & penable & pwrite) begin
// configure tdr register
tdr_reg <= (paddr == 8'h00) ? pwdata : tdr_reg;
// configure tcr register
if(paddr == 8'h01) begin
tcr_reg[7] <= pwdata[7];
tcr_reg[6] <= 1'b0;
tcr_reg[5:4] <= pwdata[5:4];
tcr_reg[3:2] <= 2'b00;
tcr_reg[1:0] <= pwdata[1:0];
end
// configure tsr register
if(paddr == 8'h02) begin
// if(tsr_reg[1] && pwdata[1]) tsr_reg[1] <= 0;
// else if (tsr_reg[0] && pwdata[0]) tsr_reg[0] <= 0;
// else begin
// tsr_reg[0] <= tsr_reg[0];
// tsr_reg[1] <= tsr_reg[1];
// end
// tsr_reg[DATA_WIDTH-1:2] = pwdata[DATA_WIDTH-1:2];
// if((tsr_reg[0] & tsr_reg[1]) & (~pwdata[0] & ~pwdata[1])) begin
// tsr_reg[1:0] <= 2'b11;
// end else begin
// tsr_reg[1:0] <= 2'b00;
// end
// Nếu chỉ có 1 cặp tsr và pwdata == 1 thì sao? Cách bên dưới vẫn sai
if((tsr_reg[0] & tsr_reg[1]) & (pwdata[0] & pwdata[1])) begin
tsr_reg[1:0] <= 2'b00;
end else begin
tsr_reg[1:0] <= tsr_reg[1:0];
end
tsr_reg[DATA_WIDTH-1:2] <= 0;
end
// read transaction
end else if(pready & psel & penable & ~pwrite) begin
case(paddr)
8'h00: prdata <= tdr_reg;
8'h01: prdata <= tcr_reg;
8'h02: prdata <= tsr_reg;
endcase
end else begin
tdr_reg <= tdr_reg;
tcr_reg <= tcr_reg;
tsr_reg <= tsr_reg;
end
end
end
always @(*) begin
tsr_reg[0] = s_ovf;
tsr_reg[1] = s_udf;
end
endmodule
// Code your design here
module logic_control #(parameter DATA_WIDTH = 8)(clk_in1, clk_in2, clk_in3, clk_in4, tcr_reg, clk_in, up_down, enable, load_tdr);
input wire clk_in1;
input wire clk_in2;
input wire clk_in3;
input wire clk_in4;
input wire [DATA_WIDTH-1:0] tcr_reg;
output reg clk_in;
output reg up_down;
output reg enable;
output reg load_tdr;
reg [1:0] sel;
always @(*) begin
sel = tcr_reg[1:0];
// $display("sel is %0b", sel);
case(sel)
2'b00: clk_in = clk_in1;
2'b01: clk_in = clk_in2;
2'b10: clk_in = clk_in3;
2'b11: clk_in = clk_in4;
default: $display("Invalid tcr_reg[1:0]!!!");
endcase
// $display("clk_in is %0d", clk_in);
up_down = tcr_reg[5];
enable = tcr_reg[4];
load_tdr = tcr_reg[7];
// $display("up_down is %0d", up_down);
// $display("enable is %0d", enable);
// $display("load_tdr is %0d", load_tdr);
end
endmodule
module counter #(parameter DATA_WIDTH = 8) (pclk, presetn, clk_in, up_down, tdr_reg, enable, load_tdr, cnt, s_ovf, s_udf);
input wire pclk;
input wire presetn;
input wire clk_in;
input wire up_down;
input wire [DATA_WIDTH-1:0] tdr_reg;
input wire enable;
input wire load_tdr;
output reg [DATA_WIDTH-1:0] cnt;
output reg s_ovf;
output reg s_udf;
reg delay_clk_in;
wire posedge_detector;
integer count = 0;
always @(*) begin
$display("updown %0d", up_down);
$display("posedge_detector %0d", posedge_detector);
$display("clk_in %0d", clk_in);
$display("combinational cnt: %0d at %0t", cnt, $time);
if(load_tdr && count == 0) begin
$display("combinational 1st cnt: %0d at %0t", cnt, $time);
cnt = tdr_reg;
count = count + 1;
$display("combinational 2nd cnt: %0d at %0t", cnt, $time);
end else begin
cnt = cnt;
$display("combinational 3rd cnt: %0d at %0t", cnt, $time);
end
end
always @(posedge pclk or negedge presetn) begin
if(~presetn) begin
cnt <= 8'h00;
end else begin
if(enable) begin
if(up_down && posedge_detector) begin
cnt <= cnt + 8'h01;
$display("sequential cnt: %0d at %0t", cnt, $time);
end else if(~up_down && posedge_detector) begin
cnt <= cnt - 8'h01;
$display("sequential cnt: %0d at %0t", cnt, $time);
end
end else begin
cnt <= cnt;
end
end
end
always @(posedge pclk or negedge presetn) begin
if(~presetn) begin
s_udf <= 0;
s_ovf <= 0;
end else begin
if(~up_down && (cnt == 8'hff)) begin
s_udf <= 1;
end else if(up_down && (cnt == 8'h00)) begin
s_ovf <= 1;
end else begin
s_udf <= s_udf;
s_ovf <= s_ovf;
end
end
end
always @(posedge pclk or negedge presetn) begin
delay_clk_in <= clk_in;
end
assign posedge_detector = clk_in & ~delay_clk_in;
endmodule
and this is the testbench file
// Code your testbench here
// or browse Examples
module tb_timer;
parameter ADDR_WIDTH = 8;
parameter DATA_WIDTH = 8;
parameter WAIT = 3;
reg pclk;
reg presetn;
reg psel;
reg penable;
reg pwrite;
reg [ADDR_WIDTH-1:0] paddr;
reg [DATA_WIDTH-1:0] pwdata;
wire [DATA_WIDTH-1:0] prdata;
wire pready;
wire pslverr;
wire s_ovf;
wire s_udf;
reg clk_in1;
reg clk_in2;
reg clk_in3;
reg clk_in4;
integer count;
integer i;
timer #(.WAIT(WAIT)) dut (
.pclk (pclk),
.presetn (presetn),
.psel (psel),
.penable (penable),
.pwrite (pwrite),
.paddr (paddr),
.pwdata (pwdata),
.prdata (prdata),
.pready (pready),
.pslverr (pslverr),
.s_ovf (s_ovf),
.s_udf (s_udf),
.clk_in1 (clk_in1),
.clk_in2 (clk_in2),
.clk_in3 (clk_in3),
.clk_in4 (clk_in4)
);
task apb_write;
input [ADDR_WIDTH-1:0] addr;
input [DATA_WIDTH-1:0] data_in;
begin
@(posedge pclk);
psel <= 1;
paddr <= addr;
pwdata <= data_in;
pwrite <= 1;
@(posedge pclk);
penable <= 1;
wait(pready);
@(posedge pclk);
psel <= 0;
penable <= 0;
pwrite <= 0;
end
endtask
task apb_read;
input [ADDR_WIDTH-1:0] addr;
begin
@(posedge pclk);
psel <= 1;
paddr <= addr;
pwrite <= 0;
@(posedge pclk);
penable <= 1;
wait(pready);
@(posedge pclk);
psel <= 0;
penable <= 0;
end
endtask
// clock generator
initial begin
pclk = 0;
clk_in1 = 0;
clk_in2 = 0;
clk_in3 = 0;
clk_in4 = 0;
count = 0;
end
always #5 pclk = ~pclk;
always @(posedge pclk) begin
count <= count + 1;
if (count % 1 == 0) clk_in1 <= ~clk_in1;
if (count % 2 == 0) clk_in2 <= ~clk_in2;
if (count % 4 == 0) clk_in3 <= ~clk_in3;
if (count % 8 == 0) clk_in4 <= ~clk_in4;
end
/////////////////
initial begin
presetn = 0;
psel = 0;
penable = 0;
pwrite = 0;
paddr = 0;
pwdata = 0;
#20;
presetn = 1;
// write transaction
apb_write(8'h00, 8'b11111000);
apb_write(8'h01, 8'b11111100);
apb_write(8'h01, 8'b11111101);
apb_write(8'h01, 8'b11111110);
apb_write(8'h01, 8'b11111111);
apb_write(8'h01, 8'b11111100);
apb_write(8'h01, 8'b11011100);
apb_write(8'h01, 8'b11101111);
apb_write(8'h02, 8'b11010000);
apb_write(8'h02, 8'b11010011);
// read transaction
@(posedge pclk);
apb_read(8'h00);
apb_read(8'h02);
apb_read(8'h01);
apb_read(8'h07);
#2000;
$finish;
end
initial begin
// Dump waves
$dumpfile("dump.vcd");
$dumpvars(1, tb_timer);
$dumpvars(1, dut);
$dumpvars(1, dut.dut1);
$dumpvars(1, dut.dut2);
$dumpvars(1, dut.dut3);
end
endmodule
I test the code and it runs very well in edaplayground.
But when I test the project in questasim-64 10.2 I get errors. I do not know to fix it. This is the error.
** Error: (vopt-8884) timer_ip/timer.v(62): Illegal output port connection for "'prdata' (8th connection)" to reg type.
#
# ** Error: (vopt-8884) timer_ip/timer.v(62): Illegal output port connection for "'pready' (9th connection)" to reg type.
#
# ** Error: (vopt-8884) timer_ip/timer.v(62): Illegal output port connection for "'pslverr' (10th connection)" to reg type.
#
# ** Error: (vopt-8884) timer_ip/timer.v(62): Illegal output port connection for "'tdr_reg' (13th connection)" to reg type.
#
# ** Error: (vopt-8884) timer_ip/timer.v(62): Illegal output port connection for "'tcr_reg' (14th connection)" to reg type.
#
# ** Error: (vopt-8884) timer_ip/timer.v(62): Illegal output port connection for "'tsr_reg' (15th connection)" to reg type.
#
# ** Error: (vopt-8884) timer_ip/timer.v(87): Illegal output port connection for "'cnt' (8th connection)" to reg type.
#
# ** Error: (vopt-8884) timer_ip/timer.v(87): Illegal output port connection for "'s_ovf' (9th connection)" to reg type.
#
# ** Error: (vopt-8884) timer_ip/timer.v(87): Illegal output port connection for "'s_udf' (10th connection)" to reg type.
#
# Optimization failed
# Error loading design