/**************************
1、移位寄存器
**************************/
module shift(
input[3:0] din;
input clk;
input rstn;
input left;
input right;
input so;
input s1;
output reg[3:0] dout
);
always@(posedge clk) begin
if(!rstn) dout <= 4'b0000;
else begin
case({s0,s1})
2'b00:dout <= dout; //输出保持不变
2'b01:dout <= {din[2:0],right};//右移
2'b10:dout <= {left,din[3:1]};
2'b11:dout <= din;//并行置数
//组合逻辑没有default会产生latch,这里是时序逻辑可以不加。
endcase
end
end
endmodule
/**************************
2、同步FIFO
**************************/
module tong_fifo(
input clk;
input rstn;
input wren;
input rden;
input[31:0] din;
output reg full;
output reg empty;
output reg[31:0] dout;
);
reg [31:0]fifo[7:0];
reg [2:0] wraddr;
reg [2:0] rdaddr;
reg [3:0] datacnt;
//判断空满
assign full = datacnt ==8;
assign empty = datacnt ==0;
always@(posedge clk or negedge rstn) begin
if(!rstn) datacnt <= 4'b0000;
else if((wren & ~full) & (~(rden & ~empty)))
datacnt <= datacnt + 1;
else if(~(wren & ~full) & ((rden & ~empty)))
datacnt <= datacnt - 1;
end
//写数据
always@(posedge clk or negedge rstn)begin
if(wren & ~full)
fifo[wraddr] <= din;
//写数据的地址
always@(posedge clk or negedge rstn)begin
if(!rstn) wraddr <= 3'h0; //注意是3'h0
else if(wren & ~full)
wraddr <= wraddr +1; //注意是地址加一
end
//读数据
assign dout <= (rden & ~empty) ? fifo[rdaddr] : 32'h0;//注意是32'h0
//读数据的地址
always@(posedge clk or negedge rstn)begin
if(!rstn) rdaddr <= 3'b0; //注意是3'h0
else if(rden & ~empty)
rdaddr <= rdaddr +1;
end
endmodule
/**************************
3、异步FIFO
**************************/
module yi_fifo(
input rclk;
input wclk;
input rstn;
input wren;
input rden;
input[31:0] din;
output full;
output empty;
output reg[31:0] dout;
);
reg [31:0]fifo[15:0];
reg [4:0] wrptr,rdptr;
wire[4:0] wrptrgray,rdptrgray;
reg [4:0] wrptr0,rdptr0,wrptr1,rdptr1,wrptr2,rdptr2;
//判断空满
assign full = rdptr2 == {~wrptrgray[4:3],wrptrgray[2:0]};
assign empty = wrptr2 == rdptrgray;
//格雷码
assign wrptrgray = (wrptr >> 1) ^ wrptr;
assign rdptrgray = (rdptr >> 1) ^ rdptr;
always@(posedge wclk or negedge rstn) begin
if(!rstn) wrptr0 <= 5'b00000;
else wrptr0 <= wrptrgray;
end
always@(posedge rclk or negedge rstn) begin //注意写地址这边是读时钟,RCLK
if(!rstn) begin wrptr1 <= 5'b00000; wrptr2 <= 5'b00000; end
else begin wrptr1 <= wrptr0; wrptr2 <= wrptr1; end
end
always@(posedge rclk or negedge rstn) begin
if(!rstn) rdptr0 <= 5'b00000;
else rdptr0 <= rdptrgray;
end
always@(posedge wclk or negedge rstn) begin //注意读地址这边是写时钟,WCLK
if(!rstn) begin rdptr1 <= 5'b00000; rdptr2 <= 5'b00000; end
else begin rdptr1 <= rdptr0; rdptr2 <= rdptr1; end
end
//写数据
always@(posedge wclk or negedge rstn)begin
if(!rstn) wrptr <= 0; //注意是0,我也不知道应该是4位还是5位
else if(wren & ~full)
wrptr <= wrptr +1; //注意是地址加一
fifo[wrptr[3:0]] <= din;
end
//读数据
always@(posedge rclk or negedge rstn)begin
if(!rstn) rdptr <= 0; //注意是0,我也不知道应该是4位还是5位
else if(wren & ~empty)
rdptr <= rdptr +1; //注意是地址加一
dout <= fifo[wrptr[3:0]];
end
endmodule
/**************************
4、UART发送
**************************/
module tx(
input send;
input [7:0] din;
input clk;
input rstn;
input parity;
output reg dout;
output reg busy
);
//奇偶校验
wire paritybit;
assign paritybit = parity ? ~(^din) : ^din;
//busy
//假设穿一位要1个周期,11个数据要11个周期;
reg [3:0] cnt;
parameter cntmax = 11;//注意这边用parameter
reg busyreg;
assign busy = busyreg;
always@(posedge clk)begin
if(!rstn) busyreg <= 0;
else if(send & ~busy) busyreg <= 1;
else if(cnt == cntmax) busyreg <= 0;
end
//计数
always@(posedge clk)begin
if(!rstn) cnt <= 0;
else if(busyreg) cnt <= cnt + 1;
else if(!busyreg || cnt >= cntmax) cnt <=0;
end
//输入数据放入缓存
reg [10:0] databuf;
always@(posedge clk)begin
if(!rstn) databuf <= 0;
else if(!busy & send)
databuf <= {1'b1,paritybit,din[7:0],1'b0};
end
//并转串发送
always@(posedeg clk)begin
if(!rst) dout <= 1;
else if(busyreg)begin
case(cnt)
0:dout <= databuf[0];
1:
2:
3:
4:
5:
6:
...
10:dout <= databuf[10];
cntmax:dout <= 1;//空闲位
//如果穿一个bit要16个周期,cntmax 是176,而上一个是160,
default:;
endcase
end
else if(busyreg) dout <= 1;
end
endmodule
/**************************
5、APB定时器
**************************/
module apbtimer(
input clk;
input rstn;
input pesl;
input pwrite;
input penable;
input[31:0] paddr;
input[31:0] pwdata;
output inter;
output[31:0] pread
);
reg [31:0] timer,upth;
reg inten,enable;
//功能部分
always@(posedge clk or negedge rstn)begin
if(!rstn) timer <= 32'b0;
else if(enable)begin
if(timer <= upth) timer <= timer + 1;
else timer <= 32'b0;
end
end
//APB部分
//写入,定义寄存器地址00为中断使能,计数使能;
//04为阈值。08为读取任意时刻timer的值。
always@(posedge clk or negedge rstn)begin
if(!rstn) inten <= 0; enable <= 0; upth <= 0;//清除寄存器里的值
else if(penable & pwrite & psel)begin
if(paddr[7:0] == 8'b0) {inten,enable} <= pwdata[1:0];
if(paddr[7:0] == 8'b4) upth <= pwdata;
end
end
//APB读取数据
assign prdata = (psel & penable & ~pwrite) ? ((paddr[7:0] == 8'h0) ? {30'h0, inten, enable} :
(paddr[7:0] == 8'h4) ? upth :
(paddr[7:0] == 8'h8) ? timer : 32'h0) : 32'h0;
assign inter = (int_en & enable) ? (timer == upth) : 1'b0;//中断结束返回值
endmodule
/**************************
6、38译码器
**************************/
module decoder38(
input clk;
input rstn;
input[2:0] din;
output[7:0] dout;
);
//可以用组合逻辑@*,直接case
always@(posedge clk or negedge rstn)begin
if(!rstn) dout <= 8'b0;
else begin
case(din)
3'b000:dout <= 8'b0000_0001;
...
3'b111:dout <= 8'b1000_0000;
default:;
endcase
end
end
endmodule
/**************************
7、串并转换
**************************/
module ser_par(
input din;
input clk;
input ret_n,en;
output[7:0] dout
);
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0)
dout <= 8'b0;
else if (en)
//dout <= {dout[6:0], din}; //低位先赋值
dout <= {din,dout[7:1],}; //高位先赋值
else
dout <= dout;
end
endmodule
module par_ser(
input clk;
input[7:0] din;
output reg dout
);
reg[3:0] count;
always@(posedge clk)begin
if(count == 4'd7) count <= 0;
else begin
dout <= din[count];
count <= count + 1;
end
end
endmodule
/**************************
8、加法器
**************************/
module half_add(
input[3:0] a;
input[3:0] b;
output[3:0] sum;
output count
);
assign {count,sum} = a + b;
endmodule
module full_add();
input[3:0] a;
input[3:0] b;
input ci;
output[3:0] sum;
output count
);
assign {count,sum} = a + b + ci;
endmodule
/**************************
9、偶分频
**************************/
//系统MHZ➗想要的MHZ = 几分频,比如N
//计数到N/2-1,翻转clkdiv
//以四分频为例
module div4(
input clk;
output reg clkdiv;
);
parameter N = 4;
reg[2:0] count;
always@(posedge clk)begin
if(count == N/2 - 1) count <= 0;
else begin
clkdiv <= ~clkdiv;
count <= count + 1;
end
end
endmodule
/**************************
10、三段状态机
**************************/
module FSM(
);
parameter
reg cs,ns;
always@(posedge clk or negedge)
//状态判断
always@(posedge clk or negedge)
case(现态)
always@(posedge clk or negedge)
case(next state)
endmodule
一些SOC代码
最新推荐文章于 2024-04-14 13:22:26 发布