4 digital BCD adder
module top_module(
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
wire cout1[3:0];
assign cout = cout1[3];
bcd_fadd bcd_u1(
.a(a[3:0]),
.b(b[3:0]),
.cin(cin),
.cout(cout1[0]),
.sum(sum[3:0]) );
genvar i;
generate
for(i = 1;i<4;i++) begin:name_u1
bcd_fadd bcd_u2(
.a(a[i*4+3:i*4]),
.b(b[i*4+3:i*4]),
.cin(cout1[i-1]),
.cout(cout1[i]),
.sum(sum[i*4+3:i*4]) );
end
endgenerate
endmodule
3-variable
module top_module(
input a,
input b,
input c,
output out );
assign out = (~a)&(~b)&(~c);
//assign out = a|b|c;
endmodule
4-variable -1
//最小项积之和
assign out = (~c&~b)|(~a&~d)|(a&c&d)|(b&c&d);
//最大项和之积,原则上化简时圈的大小为1,2,2的n次方格
//还要注意的是代码中的或是|,文本或是+,要注意转换
assign out = (~a|~c|d)&(a|b|~c|~d)&(~b|c|~d)&(~a|~b|c);
4-variable -2
assign out = a|(~b&c); //最小项
assign out = (a|c)&(a|~b); //最大项
4-variable -3
//考虑一下只能这样写,有其他更加简便的方法请在评论区讨论
assign out = (~a&b&~c&~d)|(a&~b&~c&~d)|(~a&~b&~c&d)|(a&b&~c&d)|(~a&b&c&d)|(a&~b&c&d)|(~a&~b&c&~d)|(a&b&c&~d);
minimum SOP and POS
module top_module (
input a,
input b,
input c,
input d,
output out_sop,
output out_pos
);
assign out_sop = ((c&d)|(~a&~b&c));
assign out_pos = (c)&(~a|d)&(~b|d);
endmodule
karnaugh map
module top_module (
input [4:1] x,
output f );
assign f = (x[1]|x[3])&(~x[1]|~x[3])&(~x[1]|x[2]);
endmodule
karnaugh map -1
module top_module (
input [4:1] x,
output f
);
assign f = (x[3]|~x[4])&(~x[2]|x[3])&(~x[1]|x[2]|~x[4])&(~x[1]|~x[2]|x[4]);
endmodule
k-map implement with a multiplexer
module top_module (
input c,
input d,
output [3:0] mux_in
);
wire [1:0] data;
assign data = {c,d};
always@(*)begin
case(data)
2'b00:mux_in = 4'b0100;
2'b01:mux_in = 4'b0001;
2'b11:mux_in = 4'b1001;
2'b10:mux_in = 4'b0101;
endcase
end
endmodule
Dff16e
module top_module (
input clk,
input resetn,
input [1:0] byteena,
input [15:0] d,
output [15:0] q
);
always@(posedge clk) begin
if(~resetn)
q <= 16'b0;
else if(byteena[0] | byteena[1]) begin
if(byteena[0])
q [7:0] <= d[7:0];
if(byteena[1])
q [15:8] <= d[15:8];
end
end
endmodule
Exams/m2014 q4a
上图显示的元件没有 clk 端口,取而代之的是 ena 端口,所以这是一个锁存器,有clk的是触发器。
锁存器的特征在于,锁存器锁存的触发事件发生于使能端 ena 的电平。当使能信号有效时,输出端 Q 的值为输入端 D 的值,当门使能信号无效时,输入数据保持在锁存器中,锁存器是一种电平敏感电路。相比之下,触发器属于边沿敏感电路,数据输入 D 端的值只会在时钟信号的上下边沿才会被保存到寄存器中。
FPGA 中使用相同的物理资源实现触发器和锁存器,在结构上有一定的不同。但锁存器会给电路的时序分析带来困扰。导通期间,锁存器会直接将输入信号的毛刺带入后级。在对触发器做时序分析时,只需要考虑时钟的上下边沿触发的时刻,即在上下边沿计算输入输出信号的建立时间和保持时间。但对于锁存器做分析时,还需要考虑使能信号上下边沿之间的持续时间。
Xilinx 在综合出锁存器后,会提醒用户注意补全不完整的 if 语句的表达,并表示因为时序问题,在 FPGA/CPLD 设计中不推荐使用锁存器。
总结来说就是,由于时序问题,不推荐电平触发,但若触发为电平敏感电路,要注意补全If-else的情况,电平信号不变时默认是保持,如果要为其他值(eg:0)要注意补全
Exams/m2014 q4d
//输出可以出现在运算符的右边
module top_module (
input clk,
input in,
output out);
always@(posedge clk) begin
out <= in^out;
end
endmodule
Mt2015 muxdff
module top_module (
input clk,
input L,
input r_in,
input q_in,
output reg Q);
wire D;
assign D = (L)?r_in:q_in;
always@(posedge clk) begin
Q <= D;
end
endmodule
Exams/2014 q4a
module top_module (
input clk,
input w, R, E, L,
output Q
);
wire d1,d2;
assign d1 = (E)?w:Q;
assign d2 = (L)?R:d1;
always@(posedge clk) begin
Q <= d2;
end
endmodule
Exams/ece241 2014 q4
这里写的代码仿真出现的错误改正方法如下链接添加链接描述
module top_module (
input clk,
input x,
output z
);
reg Q1,Q2,Q3;
initial z = 1;
always@(posedge clk) begin
Q1 = x^Q1;
Q2 = x&(~Q2);
Q3 = x|(~Q3);
z = ~(Q1|Q2|Q3);
end
endmodule
Exams/ece241 2013 q7
module top_module (
input clk,
input j,
input k,
output Q);
initial Q = 0;
always@(posedge clk) begin
if(j^k)
Q = (j)?1:0;
else if(j&k)
Q = ~Q;
else
Q = Q;
end
endmodule
Edgedetect
//这题和下题不同处在于上升沿检测
//关于上升沿检测,我的理解是这里相当与把输入信号打一拍,相对于原输入信号有一定的编译,然后在上升沿进行判断
//我第一次写的是阻塞符号,这是错误的,这里注意要非阻塞符号,只有这样才能达到,判断新旧值得同时,用新值覆盖旧值。
module top_module (
input clk,
input [7:0] in,
output [7:0] pedge
);
reg [7:0] temp;
always@(posedge clk) begin
temp <= in;
pedge <= ~temp∈
end
endmodule
Edgedetect2
//这里就可以使用异或进行全检测
module top_module (
input clk,
input [7:0] in,
output [7:0] pedge
);
reg [7:0] temp;
always@(posedge clk) begin
temp <= in;
pedge <= temp^in;
end
endmodule
Edgecapture
下面的代码得思路是,检测到输入为0时,说明发生了32b矢量减少的事件,然后或运算计算输出,单仿真出来有部分不正确,
module top_module (
input clk,
input reset,
input [31:0] in,
output [31:0] out
);
reg [31:0] temp;
always@(posedge clk)begin
temp <= in;
end
always@(posedge clk)begin
if(reset)
out <= 32'b0;
// 错误 else if(in == 32'b0)
// 错误 out <= temp|out;
else
out <= ~in&temp|out;
//修改为前面~in&temp检测下降沿,后面是输出时序图的逻辑就正确通过了
end
endmodule
Dualedge
//该题还是有点难度,这种思路挺好的,需要学习
module top_module (
input clk,
input d,
output q
);
reg q1,q2;
assign q = clk?q1:q2;
always@(posedge clk) begin
q1 <= d;
end
always@(negedge clk) begin
q2 <= d;
end
endmodule
Count15/10
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always@(posedge clk) begin
if(reset)
q <= 0;
else
q <= q + 1;
end
endmodule
//count10//
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always@(posedge clk) begin
if(reset)
q <= 0;
else if(q == 4'b1001)
q <= 0;
else
q <= q +1;
end
endmodule
//count1to10/
module top_module (
input clk,
input reset,
output [3:0] q);
always@(posedge clk) begin
if(reset)
q <= 1;
else if(q == 4'b1010)
q <= 1;
else
q <= q + 1;
end
endmodule
//Countslow
module top_module (
input clk,
input slowena,
input reset,
output [3:0] q);
reg [3:0] cnt; //这是自己要注意的点
//period is 10
always @ (posedge clk)
begin
if(reset)
cnt <= 4'b0;
else if(slowena == 1'b1)
//slowena 为高,计数器才能正常运行
begin
if(cnt == 4'd9)
cnt <= 4'b0;
//因为题目要求周期为10,所以0~9之后下一个为0;
else
cnt <= cnt + 4'd1;
end
end
assign q = cnt;
endmodule
Exams/ece241 2014 q7a
c_enable在上升沿有效时,计数器计数,但是c_load结合了复位和重置两种功能,所以该控制信号在复位信号或者输出为12时有效(因为是连续赋值语句,所以信号是同步变化,自己要区分好),但是通过分析波形图可知,c_load在置数时还要满足enable信号同样有效,其实这个逻辑是我没考虑到的逻辑,及只有加法器被使能的情况下,才能够加载数值,不然如果在enable之前正好空出一个上升沿,会提早加载数值,同时题目还提到,load的优先级高于enable,两者信号同时有效时,优先数值置数。
//这段代码,仿真出来又部分错误,在代码中给出错误前后分析
module top_module (
input clk,
input reset,
input enable,
output [3:0] Q,
output c_enable,
output c_load,
output [3:0] c_d
); //
assign c_enable = enable;
//这种是错误的 assign c_load = reset | Q == 4'b1100
assign c_load = reset | (Q == 4'b1100 & enable) ;
assign c_d = 4'b0001;
count4 the_counter(
.clk(clk),
.load(c_load),
.enable(enable),
.d(c_d),
.Q(Q));
endmodule
Exams/ece241 2014 q7b
这个题需要注意的点有:
1.给出的BCD码是一个模10的计数器,所以本题的考察希望用101010,利用三个计数器来完成1000的计数,我们只需要考虑下一个计数器的使能问题,而不需要考虑置数的问题,我刚开始被这个问题困扰了一会。
2.整理的思路就是计数快的计数器是个位,然后是十位,百位,所以OneHerz判断的时候要三位都进行考虑,我这个刚开始认为只需要判断最高位count[2]就可以了,这就会导致990之后OneHerz信号都是有效的,是错误的,必须三位同时满足,OneHerz才能正确表达状态。
module top_module (
input clk,
input reset,
output OneHertz,
output [2:0] c_enable
);
reg [3:0] cout0,cout1,cout2;
assign c_enable[0] = 1;
assign c_enable[1]= (cout0 == 4'b1001)?1:0;
assign c_enable[2] = (cout1 == 4'b1001&&cout0 == 4'b1001)?1:0;
assign OneHertz = (cout2 == 4'b1001 && cout1 == 4'b1001 && cout0 == 4'b1001);
bcdcount counter0 (
.clk(clk),
.reset(reset),
.enable(c_enable[0]),
.Q(cout0));
bcdcount counter1 (
.clk(clk),
.reset(reset),
.enable(c_enable[1]),
.Q(cout1));
bcdcount counter2 (
.clk(clk),
.reset(reset),
.enable(c_enable[2]),
.Q(cout2));
endmodule
Countbcd
这个题就是4个模10的BCD计数器组成4位的计数器,需要自己书写模10的BCD代码,然后进行例化,其中的ena[3:1]波形图上看起来是每位计数器的一个计数为9的flag计数器,相应的也作为下一位计数器的一个使能信号,这是这个题的关键,要注意的点和上一个类似,就是ena的判断信号要考虑低位的情况。
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
reg [15:0] Q;
assign ena[1] = (Q[3:0] == 4'b1001);
assign ena[2] = (Q[7:4] == 4'b1001&&Q[3:0] == 4'b1001);
assign ena[3] = (Q[11:8] == 4'b1001&&Q[7:4] == 4'b1001&&Q[3:0] == 4'b1001);
BCD BCD_inst0(clk,reset,1,Q[3:0]);
BCD BCD_inst1(clk,reset,ena[1],Q[7:4]);
BCD BCD_inst2(clk,reset,ena[2],Q[11:8]);
BCD BCD_inst3(clk,reset,ena[3],Q[15:12]);
assign q = Q;
endmodule
module BCD(
input clk,
input reset,
input enable,
output [3:0] Q);
always@(posedge clk)begin
if(reset)
Q <= 4'b0;
else if(enable) begin
if(Q == 4'b1001)
Q <= 4'b0;
else
Q <= Q + 1;
end
end
endmodule
Count clock(12小时制时钟计数器)
12小时制时钟计数器,接下来记录一下我对这部分代码的一个理解,我考虑的时候是每次从12:00开始计数,然后计12个小时后,11.59.59分重新计数,其中有几个难点了,记录如下:
1.代码的逻辑顺序是优先考虑秒,分,时,因为高位时间是以低位时间的信号作为使能信号,所以先写秒,再写分,每个变量的改变使用一个always块,这样足够清晰。
2.低位给高位的使能信号要叠加考虑,通过前面练习题,可以掌握该知识点,eg:时,改变时要结合判断分和秒都计数到59,而12点归为01时,在增加使能信号的基础上加上判断是否为12的判断逻辑即可
3.同时还要考虑的点是,因为是16进制计数但是要显示为十进制,所以在自增时还要增加一些判断条件,我的方法是分高四位和第四位来进行自增,低位进行0~9的自增,高位判断低位达到9时自增,同时置低位为0。
//今天在图书馆完成了这部分代码,很有成就感,还是要坚持联系
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
wire [3:1] flag;
always@(posedge clk) begin
if(reset)
pm <= 0;
else if(hh == 8'h11 && mm == 8'h59 && ss == 8'h59)
pm <= ~pm;
end
always@(posedge clk) begin
if(reset) begin
hh <= 8'h12;
end
else if(ena) begin
if(hh == 8'h12 && mm == 8'h59 && ss == 8'h59)
hh <= 8'h1;
else if(mm == 8'h59 && ss == 8'h59)
if (hh[3:0] == 4'b1001) begin
hh[3:0] <= 4'h0;
hh[7:4] <= hh[7:4] + 1;
end
else
hh[3:0] <= hh[3:0] + 1;
end
end
always@(posedge clk) begin
if(reset) begin
mm <= 8'h00;
end
else if(ena) begin
if(mm == 8'h59 && ss == 8'h59)
mm <= 8'h0;
else if(ss == 8'h59) begin
if (mm[3:0] == 4'b1001) begin
mm[3:0] <= 4'h0;
mm[7:4] <= mm[7:4] + 1;
end
else
mm[3:0] <= mm[3:0] + 1;
end
end
end
always@(posedge clk) begin
if(reset) begin
ss <= 8'h00;
end
else if(ena) begin
if(ss == 8'h59)
ss <= 8'h0;
else begin
if (ss[3:0] == 4'b1001) begin
ss[3:0] <= 4'h0;
ss[7:4] <= ss[7:4] + 1;
end
else
ss[3:0] <= ss[3:0] + 1;
end
end
end
endmodule
3-bit LFSR
module top_module (
input [2:0] SW, // R
input [1:0] KEY, // L and clk
output reg [2:0] LEDR); // Q
wire clk = KEY[0];
wire l = KEY[1];
wire [2:0] d = l?SW:{LEDR[1]^LEDR[2],LEDR[0],LEDR[2]};
always @(posedge clk)begin
LEDR <= d;
end
endmodule
cLfsr32 and Exams/m2014 q4k
module top_module(
input clk,
input reset, // Active-high synchronous reset to 32'h1
output [31:0] q
);
wire [31:0] temp;
assign temp = {q[0],q[31:23],q[22]^q[0],q[21:3],q[2]^q[0],q[1]^q[0]};
always@(posedge clk) begin
if(reset)
q <= 32'h1;
else begin
q <= temp;
end
end
endmodule
Exams/m2014 q4k
module top_module (
input clk,
input resetn, // synchronous reset
input in,
output reg out);
reg q0,q1,q2;
always@(posedge clk ) begin
if(~resetn) begin
q0 <= 1'b0;
q1 <= 1'b0;
q2 <= 1'b0;
out <= 1'b0;
end
else begin
q0 <= in;
q1 <= q0;
q2 <= q1;
out <= q2;
end
end
endmodule
Exams/2014 q4b
找到的思路都是要通过例化模块来完成,这道题做的时候就不想例化,这里要注意几点:
1.两个MUX级联,后面的选择器的优先级大于前面的选择器,后面一旦不选择前面送过来的信号,那么第一级的选择就是无用的
2.在对于信号的判断的时候要用当下的信号,也就是LEDR而不能是q,这个问题卡了好久。
module top_module (
input [3:0] SW,
input [3:0] KEY,
output [3:0] LEDR
); //
wire clk;
wire [3:0] q;
reg [3:0] temp;
assign LEDR = temp;
assign q[0] = KEY[2]?
SW[0]:
KEY[1]?LEDR[1]:LEDR[0];
assign q[1] = KEY[2]?
SW[1]:
KEY[1]?LEDR[2]:LEDR[1];
assign q[2] = KEY[2]?
SW[2]:
KEY[1]?LEDR[3]:LEDR[2];
assign q[3] = KEY[2]?
SW[3]:
KEY[1]?KEY[3]:LEDR[3];
/*这是错误的,会导致闩锁问题
assign q[0] = KEY[2]?
SW[0]:
KEY[1]?q[1]:q[0];
assign q[1] = KEY[2]?
SW[1]:
KEY[1]?q[2]:q[1];
assign q[2] = KEY[2]?
SW[2]:
KEY[1]?q[3]:q[2];
assign q[3] = KEY[2]?
SW[3]:
KEY[1]?KEY[3]:q[3];*/
always@(posedge KEY[0]) begin
temp <= q;
end
endmodule
这是参考代码
module top_module (
input [3:0] SW,
input [3:0] KEY,
output [3:0] LEDR
); //
MUXDFF ins3_MUXDFF(.clk(KEY[0]), .R(SW[3]),.E(KEY[1]),.L(KEY[2]),.w(KEY[3]), .Q(LEDR[3]));
MUXDFF ins2_MUXDFF(.clk(KEY[0]),.R(SW[2]),.E(KEY[1]),.L(KEY[2]),.w(LEDR[3]),.Q(LEDR[2]));
MUXDFF ins1_MUXDFF(.clk(KEY[0]),.R(SW[1]),.E(KEY[1]),.L(KEY[2]),.w(LEDR[2]),.Q(LEDR[1]));
MUXDFF ins0_MUXDFF(.clk(KEY[0]),.R(SW[0]),.E(KEY[1]),.L(KEY[2]),.w(LEDR[1]),.Q(LEDR[0]));
endmodule
module MUXDFF (
input clk,
input w, R, E, L,
output reg Q
);
wire D_i;
assign D_i = L?R:(E?w:Q);
always @(posedge clk) begin
Q <= D_i;
end
endmodule
Exams/ece241 2013 q12
//这里要注意的问题是在做case的匹配如果使用拼接运算符,要主要先是括号然后再是拼接运算符。
module top_module (
input clk,
input enable,
input S,
input A, B, C,
output Z );
reg [7:0] NUM;
always@(posedge clk) begin
if(enable) begin
NUM <= {NUM[6:0],S};
end
else
NUM <= NUM;
end
always@(*) begin
case({A,B,C})
3'b000: Z = NUM[0];
3'b001: Z = NUM[1];
3'b010: Z = NUM[2];
3'b011: Z = NUM[3];
3'b100: Z = NUM[4];
3'b101: Z = NUM[5];
3'b110: Z = NUM[6];
3'b111: Z = NUM[7];
endcase
end
endmodule
Rule90
//这道题我卡了好久,题目的描述让我刚开始考虑偏了,导致思路一直没有在正确的道路上,题目的意思就是计算一位的结果需要左右两边的值异或得到,这就意味着三位数只能输出一位结果,如果想要两位结果,那么就需要前后补零来计算,所以我的思路是,将数值向后移动^数值向前移动,相当当前位的结果由自己的前后决定。当然也可以循环来计算每一位。
module top_module(
input clk,
input load,
input [511:0] data,
output [511:0] q );
always@(posedge clk) begin
if(load) begin
q <= data;
end
else
q <= ({1'b0,q[511:1]}^{q[510:0],1'b0});
end
endmodule
rule 110
//这种移动的方法的好吃是每一位都是一致的逻辑,不需要分开讨论,只需要根据化简得逻辑进行运算即可。
//这里我刚开始犯的错误是,left和right得取值都是来自输入data,没有考虑周全
//通过这一点体会到了Verilog代码虽然在等式得前后都是相同变量,但是有先后之分,后面代码得书写一定要注意。
module top_module(
input clk,
input load,
input [511:0] data,
output [511:0] q );
wire [511:0] left,right;
integer i;
assign right = {q[510:0],1'b0};
assign left = {1'b0,q[511:1]};
always@(posedge clk) begin
if(load) begin
q <= data;
end
else begin
q <= (q&~right)|(right&~left)|(right&~q);
end
end
endmodule
Conwaylife
这道题我做的时间也有点长,刚开始用添加patch的方法,变换为18*18的矩阵,应为verilog截取向量比较方便,所以这种相对比较简单,实现代码在下面。
module top_module(
input clk,
input load,
input [255:0] data,
output [255:0] q );
reg [2:0] sum [255:0];//[2:0]表示位宽,256表示的是个数
reg [17:0] q_temp [17:0];
integer i,j;
integer up,down,left,right;
always@(*) begin
q_temp[0][17:0] = {q[240], q[255:240], q[255]}; ///这里要注意,第一次拼接我有点写反了
q_temp[17][17:0] = {q[0], q[15:0],q[15]};
for(i=1;i<17;i=i+1)begin
q_temp[i][17:0] = {q[16*i-16], q[(i*16-1)-:16], q[16*i-1]};
end
end
always@(*) begin
for(i = 1;i<17;i++) begin
for (j = 1;j<17;j++) begin
up = i-1;
down = i+1;
left = j-1;
right = j+1;
sum[16*(i-1) + (j-1)] = q_temp[up][left] + q_temp[up][j] + q_temp[up][right]+
q_temp[i][left] + q_temp[i][right]+
q_temp[down][left] + q_temp[down][j] + q_temp[down][right]; //这种写法非常好理解
end
end
end
always@(posedge clk) begin
if(load) begin
q <= data;
end
else begin
for(i = 0;i<256;i++) begin
case(sum[i]) //case的判断要注意:在关注长度的同时也要注意位宽,8个数的相加至少位宽应该为3bit
//
//这是我改掉的最后一个bug,
//因为q的变化是受时钟控制的,所以虽然等式两边都是q变量,
//但是之间有一个时钟误差,而如果是q[i] <= q_temp[x][x];q_temp刚开始确实里面的16*16和q没有区别
//但是因为不受时钟控制,所以,内部再任意时刻取值是一个错误的值。
3'b010:q[i] = q[i];
3'b011:q[i] = 1'b1;
default:q[i] = 1'b0;
endcase
end
end
end
endmodule
第二种思路:参考知乎上给出的答案,我觉得我的思维容易直接从输入得到输出,不善于使用中间变量的使用,从而导致时序的混乱。答案中巧妙的借助了二位数组,使得输入输出依据clk的变化。
module top_module(
input clk,
input load,
input [255:0] data,
output [255:0] q );
reg [15:0] q_temp [15:0] ;
int up,down,left ,right;
wire [2:0] sum [255:0];
integer i,j;
always@(posedge clk) begin
if(load)begin
for(i = 0;i<16;i++) begin
for (j = 0;j<16;j++) begin
q_temp[i][j] <= data[i*16+j];
end
end
end
else begin
for(i = 0;i < 16;i++) begin
for(j = 0;j < 16;j++) begin
case(sum[16*i + j])
3'b010:q_temp[i][j] = q_temp[i][j];
3'b011:q_temp[i][j] = 1'b1;
default:q_temp[i][j] = 1'b0;
endcase
end
end
end
end
always@(*) begin
for(i = 0;i<16;i++) begin
for (j = 0;j<16;j++) begin
up = (i == 0)? 15:i-1;
down = (i == 15)? 0:i+1;
left = (j == 0)? 15:j-1;
right = (j == 15)? 0:j+1;
sum[16*i + j] = q_temp[up][left] + q_temp[up][j] + q_temp[up][right]+
q_temp[i][left] + q_temp[i][right]+
q_temp[down][left] + q_temp[down][j] + q_temp[down][right];
end
end
end
always@(*) begin
for(i = 0;i<16;i++) begin
for (j = 0;j<16;j++) begin
q[16*i +j] <= q_temp[i][j];
end
end
end
endmodule