一些SOC代码

/**************************
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位还是5else 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位还是5else 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
/**************************
638译码器
**************************/
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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值