搜索
bottom↓
回复: 5

verilog新手发一个自己写的spi核

[复制链接]

出0入85汤圆

发表于 2021-8-31 23:02:32 | 显示全部楼层 |阅读模式
运行起来虽然没啥问题,但是完全自学的verilog,想让大牛们帮忙看看,写的verilog代码有没有什么不符合规范,不符合设计原则的地方。 晚点再附上linux驱动spi代码。

module quad_spi_ctrl(
                                                mem_data_i,
                                                mem_data_o,
                                                mem_addr_i,
                                                mem_sel_i,
                                                mem_we_i,
                                                mem_cyc_i,
                                                mem_stb_i,
                                                mem_ack_o,
                                                mem_err_o,
                                                mem_rty_o,
                        
        
                                                mem_clk_i,
                                                mem_rst_i,
                                                               
                                                spi_ctrl_cs,
                                                spi_ctrl_clk,
                                                spi_ctrl_io
                                                               
                      );
  parameter CRC_CODE         = 16'h1021;
  parameter NO_QUAD_SPI         = 0 ;

  parameter SPI_WIDTH         = NO_QUAD_SPI ? 2 : 4;

  

        input   [31:0]                        mem_data_i;

        output  [31:0]                        mem_data_o;

        input   [31:0]                        mem_addr_i;

        input   [3:0]                        mem_sel_i;

        input                                        mem_we_i;

        input                                        mem_cyc_i;

        input                                        mem_stb_i;

        output   reg                        mem_ack_o;

        output                                        mem_err_o;

        output                                        mem_rty_o;

       

       

        input                                        mem_clk_i;

        input                           mem_rst_i;

       

        output                                        spi_ctrl_cs;

        output reg                                spi_ctrl_clk;

        inout [SPI_WIDTH-1:0]        spi_ctrl_io;
  //---------------------------------------------------
  // outputs
  reg [31:0]         reg_sbuf = 0 ;
  reg [31:0]         reg_rbuf = 0 ;
  reg [7:0]                 state = 0;
  reg                                 stb ;
  reg                                  spi_cs;
  reg        [7:0]          clk_div;
  reg [8:0]                div_cnt;
  reg                                 spi_mode;
  reg        [15:0]         crc16_reg;

  reg                         mem_ack;
  
  assign mem_err_o = 1'b0;
  assign mem_rty_o = 1'b0;
  
  wire         quad_spi_io[3:0];

  

  generate
  if(NO_QUAD_SPI == 0) begin
                assign quad_spi_io[0]          = (state[6]) ?        reg_sbuf[28] : reg_sbuf[31];
                assign spi_ctrl_io[0]         = (state[6]^state[7] ) ? 1'bz : quad_spi_io[0];
          
                assign spi_ctrl_io[1]         = (state[7:6] == 2'b11) ? reg_sbuf[29] : 1'bz ;
          
                assign quad_spi_io[2]         = (state[7:6]==2'b11) ? reg_sbuf[30] : 1'b1 ;
                assign spi_ctrl_io[2]         = (state[7:6]==2'b10) ? 1'bz : quad_spi_io[2];
         
                assign quad_spi_io[3]         = (state[7:6]==2'b11) ? reg_sbuf[31] : 1'b1 ;
                assign spi_ctrl_io[3]         = (state[7:6]==2'b10) ? 1'bz : quad_spi_io[3];

                end

  else begin

                assign spi_ctrl_io[0]         = reg_sbuf[31];

                assign spi_ctrl_io[1]        = 1'bz;

        end
  endgenerate

  
  assign mem_data_o = mem_addr_i[2] ? reg_rbuf : {crc16_reg ,4'b0 , 1'b0 , spi_mode , spi_ctrl_clk , spi_cs , state };
  assign spi_ctrl_cs = spi_cs ? 1'b1 : 1'b0 ;

  wire div_trig = ( div_cnt == clk_div );

  wire stat_ok = ((state[5]==1'b1) && (state[0]==1'b0));
  
        always @(posedge mem_clk_i)
        if(div_trig || state[5])
                begin
                div_cnt        <= 8'b0;
                end
        else
                begin
                div_cnt <=  div_cnt + 1'b1;
                end

        always @(posedge mem_clk_i)
        if(mem_rst_i)
                begin
                state <= 8'b01100000;
                spi_cs <= 1'b1;
                spi_ctrl_clk <= 1'b0;
                reg_sbuf    <= 32'hffffffff;
                reg_rbuf         <= 32'hffffffff;
                mem_ack_o         <= 1'b0;
                stb                        <= 1'b0;
                clk_div                <= 8'b0;
                spi_mode           <= 1'b0;
                end
        else
                begin
                stb                <= mem_cyc_i & mem_stb_i;
                mem_ack        <= stat_ok;

                mem_ack_o <= stat_ok & (~mem_ack);

               
                casex(state)
                8'bxx1xxxx0:
                        begin
                        state[0]  <= ~(mem_cyc_i & mem_stb_i) ;
                        end
                8'bxx1xxxx1:
                        begin
                       
                        if( stb && mem_we_i && mem_sel_i[0] && (mem_addr_i[3:2]==2'b00) )
                                begin
                                state[0]                  <= (~mem_data_i[5]) & mem_data_i[0];
                                state[7:1]                 <= mem_data_i[7:1] ;
                                end                               
                        else
                                begin
                                state[0]  <= ~stb ;
                                end
                        if( stb && mem_we_i && (mem_addr_i[3:2]==2'b01))
                                begin
                                reg_sbuf[7:0]   <= mem_sel_i[0] ? mem_data_i[7:0]   : reg_sbuf[7:0];
                                reg_sbuf[15:8]  <= mem_sel_i[1] ? mem_data_i[15:8]  : reg_sbuf[15:8];
                                reg_sbuf[23:16] <= mem_sel_i[2] ? mem_data_i[23:16] : reg_sbuf[23:16];
                                reg_sbuf[31:24] <= mem_sel_i[3] ? mem_data_i[31:24] : reg_sbuf[31:24];
                                end
                        if( stb && mem_we_i && mem_sel_i[2] && (mem_addr_i[3:2]==2'b00) )
                                begin
                                clk_div        <= mem_data_i[23:16];
                                end
                        if( stb && mem_we_i && mem_sel_i[1] && (mem_addr_i[3:2]==2'b00) )
                                begin
                                spi_cs                         <=  mem_data_i[8];
                                spi_ctrl_clk         <=  mem_data_i[9];
                                spi_mode                        <=  mem_data_i[10];
                                if(mem_data_i[11])
                                        crc16_reg <= 16'b0;
                                end
                        end
                       
                8'b000xxxxx:
                        begin
                        if(div_trig)
                                begin

                                state[5:0] <= state[5:0] + spi_ctrl_clk;
                                if( spi_ctrl_clk ^ spi_mode )
                                        begin
                                        reg_sbuf <= {reg_sbuf[30:0],1'b1};
                                        end
                                else
                                        begin
                                        reg_rbuf <= {reg_rbuf[30:0],spi_ctrl_io[1]};
                                        crc16_reg <=  (spi_ctrl_io[1] ^ crc16_reg[15]) ?( { crc16_reg[14:0] , 1'b0 } ^ CRC_CODE) : { crc16_reg[14:0] , 1'b0 } ;
                                        end
                               
                                spi_ctrl_clk <= ~spi_ctrl_clk;
                                end
                        end
                8'b010xxxxx:

                        begin
                        if(div_trig)
                                begin
                                state[0] <= 1'b0;
                                state[5:1] <= state[5:1] + spi_ctrl_clk;
                                if( !spi_ctrl_clk )
                                        reg_rbuf <=  {reg_rbuf[29:0],spi_ctrl_io[1:0] };
                                spi_ctrl_clk <= ~spi_ctrl_clk;
                                end
                        end
                8'b100xxxxx:

                        begin
                        if(div_trig)
                                begin
                                state[1:0] <= 2'b00;
                                state[5:2] <= state[5:2] + spi_ctrl_clk;
                                if( !spi_ctrl_clk )
                                        reg_rbuf <=  {reg_rbuf[32-SPI_WIDTH-1:0] , spi_ctrl_io[SPI_WIDTH-1:0] };
                                spi_ctrl_clk <= ~spi_ctrl_clk;
                                end
                        end
                8'b110xxxxx:

                        begin
                        if(div_trig)
                                begin
                                state[1:0] <= 2'b00;
                                state[5:2] <= state[5:2] + spi_ctrl_clk;
                                if( spi_ctrl_clk )
                                        reg_sbuf <=  {reg_sbuf[27:0] , 4'b1111 };
                                spi_ctrl_clk <= ~spi_ctrl_clk;
                                end
                        end
                endcase

                end
         
endmodule

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入90汤圆

发表于 2021-9-1 01:17:13 来自手机 | 显示全部楼层
上次用verilog差不多10年前了,说的不一定对:
写的不够简洁、清晰
casex只是仿真时用的吧。改成case,状态机,one-hot编码
同一个时钟的上升沿,在两个always块中对同一个寄存器赋值和取值,可能存在不确定性

出0入442汤圆

发表于 2021-9-1 10:38:01 | 显示全部楼层
aammoo 发表于 2021-9-1 01:17
上次用verilog差不多10年前了,说的不一定对:
写的不够简洁、清晰
casex只是仿真时用的吧。改成case,状态 ...

casex原则上也可以综合;
2个always块赋值综合报错;

另外根据我的经验,新手建议从头就开始总线化,这样后面迁移不会有难度。目前FPGA方面建议axi4,axi4lite,axi4stream这三种,所有IP都设计为挂在总线上的模块。这样用起来方便,理解起来也容易,可移植性也好。

出0入85汤圆

 楼主| 发表于 2021-9-2 23:33:18 | 显示全部楼层
学习到了,按照两位大神的建议重新改了一下:



module quad_spi_ctrl(
                                                mem_data_i,
                                                mem_data_o,
                                                mem_addr_i,
                                                mem_sel_i,
                                                mem_we_i,
                                                mem_cyc_i,
                                                mem_stb_i,
                                                mem_ack_o,
                                                mem_err_o,
                                                mem_rty_o,
                        
        
                                                mem_clk_i,
                                                mem_rst_i,
                                                               
                                                spi_ctrl_cs,
                                                spi_ctrl_clk,
                                                spi_ctrl_io
                                                               
                      );
  parameter CRC_CODE         = 16'h1021;
  parameter NO_QUAD_SPI         = 0 ;
  parameter SPI_WIDTH         = NO_QUAD_SPI ? 2 : 4;
  
        input   [31:0]                        mem_data_i;
        output reg [31:0]                mem_data_o;
        input   [31:0]                        mem_addr_i;
        input   [3:0]                        mem_sel_i;
        input                                        mem_we_i;
        input                                        mem_cyc_i;
        input                                        mem_stb_i;
        output   reg                        mem_ack_o;
        output                                        mem_err_o;
        output                                        mem_rty_o;
       
       
        input                                        mem_clk_i;
        input                           mem_rst_i;
       
        output                                        spi_ctrl_cs;
        output reg                                spi_ctrl_clk;
        inout [SPI_WIDTH-1:0]        spi_ctrl_io;
  //---------------------------------------------------
  // outputs
  reg [31:0]         reg_sbuf;
  reg [31:0]         reg_rbuf;
  reg [1:0]                 state;
  reg [4:0]                xmit_cnt;
  reg                         idle;
  reg                                  spi_cs;
  reg        [7:0]          clk_div;
  reg [8:0]                div_cnt;
  reg                                 spi_mode;
  reg        [15:0]         crc16_reg;
  
  assign mem_err_o = 1'b0;
  assign mem_rty_o = 1'b0;
  
  wire         quad_spi_io[3:0];
  
  generate
  if(NO_QUAD_SPI == 0) begin
                assign quad_spi_io[0]          = (state[0]) ?        reg_sbuf[28] : reg_sbuf[31];
                assign spi_ctrl_io[0]         = (state[0]^state[1] ) ? 1'bz : quad_spi_io[0];
          
                assign spi_ctrl_io[1]         = (state[1:0] == 2'b11) ? reg_sbuf[29] : 1'bz ;
          
                assign quad_spi_io[2]         = (state[1:0]==2'b11) ? reg_sbuf[30] : 1'b1 ;
                assign spi_ctrl_io[2]         = (state[1:0]==2'b10) ? 1'bz : quad_spi_io[2];
         
                assign quad_spi_io[3]         = (state[1:0]==2'b11) ? reg_sbuf[31] : 1'b1 ;
                assign spi_ctrl_io[3]         = (state[1:0]==2'b10) ? 1'bz : quad_spi_io[3];
                end
  else begin
                assign spi_ctrl_io[0]         = reg_sbuf[31];
                assign spi_ctrl_io[1]        = 1'bz;
        end
  endgenerate

  assign spi_ctrl_cs = spi_cs ;

  wire div_trig = ( div_cnt == clk_div );
  wire stb = mem_cyc_i & mem_stb_i;
  wire wb_rw_ctrl_reg = (mem_addr_i[3:2]==2'b00);
  wire wb_rw_data_reg = (mem_addr_i[3:2]==2'b01);

        always @(posedge mem_clk_i)
        if(mem_rst_i) begin
                state <= 2'b01;
                xmit_cnt[4:0] <= 0;
                idle        <= 1'b1;
                spi_cs <= 1'b1;
                spi_ctrl_clk <= 1'b0;
                reg_sbuf    <= 32'hffffffff;
                reg_rbuf         <= 32'hffffffff;
                mem_ack_o         <= 1'b0;
                clk_div                <= 8'b0;
                spi_mode           <= 1'b0;
        end else begin
                mem_ack_o  <= idle & stb ;
                if(div_trig || idle) begin
                        div_cnt        <= 8'b0;
                end else begin
                        div_cnt <=  div_cnt + 1'b1;
                end
               
                if(idle) begin
                        if(stb) begin
                                if(mem_we_i) begin
                                        if( mem_sel_i[0] && wb_rw_ctrl_reg )begin
                                                state                                         <= mem_data_i[7:6] ;
                                                idle                                        <= mem_data_i[5];
                                                xmit_cnt[4:0]                 <= mem_data_i[4:0] ;
                                        end
                                       
                                        if(wb_rw_data_reg) begin
                                                reg_sbuf[7:0]   <= mem_sel_i[0] ? mem_data_i[7:0]   : reg_sbuf[7:0];
                                                reg_sbuf[15:8]  <= mem_sel_i[1] ? mem_data_i[15:8]  : reg_sbuf[15:8];
                                                reg_sbuf[23:16] <= mem_sel_i[2] ? mem_data_i[23:16] : reg_sbuf[23:16];
                                                reg_sbuf[31:24] <= mem_sel_i[3] ? mem_data_i[31:24] : reg_sbuf[31:24];
                                        end
                                               
                                        if( mem_sel_i[2] && wb_rw_ctrl_reg ) begin
                                                clk_div        <= mem_data_i[23:16];
                                        end
                                        if( mem_sel_i[1] && wb_rw_ctrl_reg ) begin
                                                spi_cs                         <=  mem_data_i[8];
                                                spi_ctrl_clk         <=  mem_data_i[9];
                                                spi_mode                        <=  mem_data_i[10];
                                                if(mem_data_i[11]) begin
                                                        crc16_reg <= 16'b0;
                                                end
                                        end
                                end else begin
                                                mem_data_o <= wb_rw_data_reg ? reg_rbuf : {crc16_reg ,4'b0 , 1'b0 , spi_mode , spi_ctrl_clk , spi_cs , state,idle,xmit_cnt};
                                end
                        end
                end else if(div_trig) begin
                        spi_ctrl_clk <= ~spi_ctrl_clk;
                        case(state)
                                2'b00: begin
                                                xmit_cnt[4:0] <= xmit_cnt[4:0] + spi_ctrl_clk;
                                                if(xmit_cnt[4:0] == 5'b11111 && spi_ctrl_clk)
                                                        idle <= 1;
                                                if( spi_ctrl_clk ^ spi_mode ) begin
                                                        reg_sbuf <= {reg_sbuf[30:0],1'b1};
                                                end else begin
                                                        reg_rbuf <= {reg_rbuf[30:0],spi_ctrl_io[1]};
                                                        crc16_reg <=  (spi_ctrl_io[1] ^ crc16_reg[15]) ?( { crc16_reg[14:0] , 1'b0 } ^ CRC_CODE) : { crc16_reg[14:0] , 1'b0 } ;
                                                end
                                end
                                2'b01:  begin
                                                xmit_cnt[4:1] <= xmit_cnt[4:1] + spi_ctrl_clk;
                                                if(xmit_cnt[4:1] == 4'b1111 && spi_ctrl_clk)  
                                                        idle <= 1;
                                                if( !spi_ctrl_clk )
                                                        reg_rbuf <=  {reg_rbuf[29:0],spi_ctrl_io[1:0] };
                                end
                                2'b10: begin
                                                xmit_cnt[4:2] <= xmit_cnt[4:2] + spi_ctrl_clk;
                                                if(xmit_cnt[4:2] == 3'b111 && spi_ctrl_clk)  
                                                        idle <= 1;
                                                if( !spi_ctrl_clk )  
                                                        reg_rbuf <=  {reg_rbuf[32-SPI_WIDTH-1:0] , spi_ctrl_io[SPI_WIDTH-1:0] };
                                end
                                2'b11:  begin
                                                xmit_cnt[4:2] <= xmit_cnt[4:2] + spi_ctrl_clk;
                                                if(xmit_cnt[4:2] == 3'b111 && spi_ctrl_clk)  
                                                        idle <= 1;
                                               
                                                if( spi_ctrl_clk )  
                                                        reg_sbuf <=  {reg_sbuf[27:0] , 4'b1111 };
                                end
                        endcase
                end
        end
         
endmodule

出0入224汤圆

发表于 2021-9-3 06:45:31 来自手机 | 显示全部楼层
zdg102 发表于 2021-9-2 23:33
学习到了,按照两位大神的建议重新改了一下:



已经改成AXi4总线?

出0入85汤圆

 楼主| 发表于 2021-9-3 20:26:05 | 显示全部楼层
yyts 发表于 2021-9-3 06:45
已经改成AXi4总线?

没有,我这个是用在 openrisc 上面,因此必须是 wishbone 总线。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-13 23:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表