From 07b33baf944c02a7041c90199f2fcb2847212b63 Mon Sep 17 00:00:00 2001 From: liangkangnan Date: Tue, 5 May 2020 18:31:08 +0800 Subject: [PATCH] perips: add spi master Signed-off-by: liangkangnan --- rtl/core/rib.v | 43 ++++++- rtl/perips/spi.v | 246 ++++++++++++++++++++++++++++++++++++ rtl/soc/tinyriscv_soc_top.v | 39 +++++- sim/sim_default_nowave.bat | 2 +- sim/sim_new_nowave.bat | 2 +- 5 files changed, 328 insertions(+), 4 deletions(-) create mode 100644 rtl/perips/spi.v diff --git a/rtl/core/rib.v b/rtl/core/rib.v index 1b784b0..f596f03 100644 --- a/rtl/core/rib.v +++ b/rtl/core/rib.v @@ -87,6 +87,14 @@ module rib( output reg s4_req_o, // 从设备4访问请求标志 output reg s4_we_o, // 从设备4写标志 + // slave 5 interface + output reg[`MemAddrBus] s5_addr_o, // 从设备5读、写地址 + output reg[`MemBus] s5_data_o, // 从设备5写数据 + input wire[`MemBus] s5_data_i, // 从设备5读取到的数据 + input wire s5_ack_i, // 从设备5访问完成标志 + output reg s5_req_o, // 从设备5访问请求标志 + output reg s5_we_o, // 从设备5写标志 + output reg hold_flag_o // 暂停流水线标志 ); @@ -99,6 +107,7 @@ module rib( parameter [3:0]slave_2 = 4'b0010; parameter [3:0]slave_3 = 4'b0011; parameter [3:0]slave_4 = 4'b0100; + parameter [3:0]slave_5 = 4'b0101; parameter [1:0]grant0 = 2'h0; parameter [1:0]grant1 = 2'h1; @@ -191,21 +200,25 @@ module rib( s2_addr_o = `ZeroWord; s3_addr_o = `ZeroWord; s4_addr_o = `ZeroWord; + s5_addr_o = `ZeroWord; s0_data_o = `ZeroWord; s1_data_o = `ZeroWord; s2_data_o = `ZeroWord; s3_data_o = `ZeroWord; s4_data_o = `ZeroWord; + s5_data_o = `ZeroWord; s0_req_o = `RIB_NREQ; s1_req_o = `RIB_NREQ; s2_req_o = `RIB_NREQ; s3_req_o = `RIB_NREQ; s4_req_o = `RIB_NREQ; + s5_req_o = `RIB_NREQ; s0_we_o = `WriteDisable; s1_we_o = `WriteDisable; s2_we_o = `WriteDisable; s3_we_o = `WriteDisable; s4_we_o = `WriteDisable; + s5_we_o = `WriteDisable; end else begin m0_ack_o = `RIB_NACK; m1_ack_o = `RIB_NACK; @@ -219,21 +232,25 @@ module rib( s2_addr_o = `ZeroWord; s3_addr_o = `ZeroWord; s4_addr_o = `ZeroWord; + s5_addr_o = `ZeroWord; s0_data_o = `ZeroWord; s1_data_o = `ZeroWord; s2_data_o = `ZeroWord; s3_data_o = `ZeroWord; s4_data_o = `ZeroWord; + s5_data_o = `ZeroWord; s0_req_o = `RIB_NREQ; s1_req_o = `RIB_NREQ; s2_req_o = `RIB_NREQ; s3_req_o = `RIB_NREQ; s4_req_o = `RIB_NREQ; + s5_req_o = `RIB_NREQ; s0_we_o = `WriteDisable; s1_we_o = `WriteDisable; s2_we_o = `WriteDisable; s3_we_o = `WriteDisable; s4_we_o = `WriteDisable; + s5_we_o = `WriteDisable; case (grant) grant0: begin @@ -278,6 +295,14 @@ module rib( m0_ack_o = s4_ack_i; m0_data_o = s4_data_i; end + slave_5: begin + s5_req_o = m0_req_i; + s5_we_o = m0_we_i; + s5_addr_o = {{4'h0}, {m0_addr_i[27:0]}}; + s5_data_o = m0_data_i; + m0_ack_o = s5_ack_i; + m0_data_o = s5_data_i; + end default: begin end @@ -325,6 +350,14 @@ module rib( m1_ack_o = s4_ack_i; m1_data_o = s4_data_i; end + slave_5: begin + s5_req_o = m1_req_i; + s5_we_o = m1_we_i; + s5_addr_o = {{4'h0}, {m1_addr_i[27:0]}}; + s5_data_o = m1_data_i; + m1_ack_o = s5_ack_i; + m1_data_o = s5_data_i; + end default: begin end @@ -372,13 +405,21 @@ module rib( m2_ack_o = s4_ack_i; m2_data_o = s4_data_i; end + slave_5: begin + s5_req_o = m2_req_i; + s5_we_o = m2_we_i; + s5_addr_o = {{4'h0}, {m2_addr_i[27:0]}}; + s5_data_o = m2_data_i; + m2_ack_o = s5_ack_i; + m2_data_o = s5_data_i; + end default: begin end endcase end default: begin - + end endcase end diff --git a/rtl/perips/spi.v b/rtl/perips/spi.v new file mode 100644 index 0000000..6a394e3 --- /dev/null +++ b/rtl/perips/spi.v @@ -0,0 +1,246 @@ + /* + Copyright 2020 Blue Liang, liangkangnan@163.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +// spi master模块 +module spi( + + input wire clk, + input wire rst, + + input wire[31:0] data_i, + input wire[31:0] addr_i, + input wire we_i, + input wire req_i, + + output reg[31:0] data_o, + output reg ack_o, + + output reg spi_mosi, // spi控制器输出、spi设备输入信号 + input wire spi_miso, // spi控制器输入、spi设备输出信号 + output wire spi_ss, // spi设备片选 + output reg spi_clk // spi设备时钟,最大频率为输入clk的一半 + + ); + + + localparam SPI_CTRL = 4'h0; // spi_ctrl寄存器地址偏移 + localparam SPI_DATA = 4'h4; // spi_data寄存器地址偏移 + localparam SPI_STATUS = 4'h8; // spi_status寄存器地址偏移 + + // spi控制寄存器 + // addr: 0x00 + // [0]: 1: enable, 0: disable + // [1]: CPOL + // [2]: CPHA + // [3]: select slave, 1: select, 0: deselect + // [15:8]: clk div + reg[31:0] spi_ctrl; + // spi数据寄存器 + // addr: 0x04 + // [7:0] cmd or inout data + reg[31:0] spi_data; + // spi状态寄存器 + // addr: 0x08 + // [0]: 1: busy, 0: idle + reg[31:0] spi_status; + + reg[8:0] clk_cnt; // 分频计数 + reg en; // 使能,开始传输信号,传输期间一直有效 + reg[4:0] spi_clk_edge_cnt; // spi clk时钟沿的个数 + reg spi_clk_edge_level; // spi clk沿电平 + reg[7:0] rdata; // 从spi设备读回来的数据 + reg done; // 传输完成信号 + reg[3:0] bit_index; // 数据bit索引 + wire[8:0] div_cnt; + + + assign spi_ss = ~spi_ctrl[3]; // SPI设备片选信号 + + assign div_cnt = spi_ctrl[15:8];// 0: 2分频,1:4分频,2:8分频,3:16分频,4:32分频,以此类推 + + + // 产生使能信号 + // 传输期间一直有效 + always @ (posedge clk) begin + if (rst == 1'b0) begin + en <= 1'b0; + end else begin + if (spi_ctrl[0] == 1'b1) begin + en <= 1'b1; + end else if (done == 1'b1) begin + en <= 1'b0; + end else begin + en <= en; + end + end + end + + // 对输入时钟进行计数 + always @ (posedge clk) begin + if (rst == 1'b0) begin + clk_cnt <= 9'h0; + end else if (en == 1'b1) begin + if (clk_cnt == div_cnt) begin + clk_cnt <= 9'h0; + end else begin + clk_cnt <= clk_cnt + 1'b1; + end + end else begin + clk_cnt <= 9'h0; + end + end + + // 对spi clk沿进行计数 + // 每当计数到分频值时产生一个上升沿脉冲 + always @ (posedge clk) begin + if (rst == 1'b0) begin + spi_clk_edge_cnt <= 5'h0; + spi_clk_edge_level <= 1'b0; + end else if (en == 1'b1) begin + // 计数达到分频值 + if (clk_cnt == div_cnt) begin + if (spi_clk_edge_cnt == 5'd17) begin + spi_clk_edge_cnt <= 5'h0; + spi_clk_edge_level <= 1'b0; + end else begin + spi_clk_edge_cnt <= spi_clk_edge_cnt + 1'b1; + spi_clk_edge_level <= 1'b1; + end + end else begin + spi_clk_edge_level <= 1'b0; + end + end else begin + spi_clk_edge_cnt <= 5'h0; + spi_clk_edge_level <= 1'b0; + end + end + + // bit序列 + always @ (posedge clk) begin + if (rst == 1'b0) begin + spi_clk <= 1'b0; + rdata <= 8'h0; + spi_mosi <= 1'b0; + bit_index <= 4'h0; + end else begin + if (en) begin + if (spi_clk_edge_level == 1'b1) begin + case (spi_clk_edge_cnt) + // 第奇数个时钟沿 + 1, 3, 5, 7, 9, 11, 13, 15: begin + spi_clk <= ~spi_clk; + if (spi_ctrl[2] == 1'b1) begin + spi_mosi <= spi_data[bit_index]; // 送出1bit数据 + bit_index <= bit_index - 1'b1; + end else begin + rdata <= {rdata[6:0], spi_miso}; // 读1bit数据 + end + end + // 第偶数个时钟沿 + 2, 4, 6, 8, 10, 12, 14, 16: begin + spi_clk <= ~spi_clk; + if (spi_ctrl[2] == 1'b1) begin + rdata <= {rdata[6:0], spi_miso}; // 读1bit数据 + end else begin + spi_mosi <= spi_data[bit_index]; // 送出1bit数据 + bit_index <= bit_index - 1'b1; + end + end + 17: begin + spi_clk <= spi_ctrl[1]; + end + endcase + end + end else begin + // 初始状态 + spi_clk <= spi_ctrl[1]; + if (spi_ctrl[2] == 1'b0) begin + spi_mosi <= spi_data[7]; // 送出最高位数据 + bit_index <= 4'h6; + end else begin + bit_index <= 4'h7; + end + end + end + end + + // 产生结束(完成)信号 + always @ (posedge clk) begin + if (rst == 1'b0) begin + done <= 1'b0; + end else begin + if (en && spi_clk_edge_cnt == 5'd17) begin + done <= 1'b1; + end else begin + done <= 1'b0; + end + end + end + + // write reg + always @ (posedge clk) begin + if (rst == 1'b0) begin + spi_ctrl <= 32'h0; + spi_data <= 32'h0; + spi_status <= 32'h0; + end else begin + spi_status[0] <= en; + if (we_i == 1'b1) begin + case (addr_i[3:0]) + SPI_CTRL: begin + spi_ctrl <= data_i; + end + SPI_DATA: begin + spi_data <= data_i; + end + default: begin + + end + endcase + end else begin + spi_ctrl[0] <= 1'b0; + // 发送完成后更新数据寄存器 + if (done == 1'b1) begin + spi_data <= {24'h0, rdata}; + end + end + end + end + + // read reg + always @ (*) begin + if (rst == 1'b0) begin + data_o = 32'h0; + end else begin + case (addr_i[3:0]) + SPI_CTRL: begin + data_o = spi_ctrl; + end + SPI_DATA: begin + data_o = spi_data; + end + SPI_STATUS: begin + data_o = spi_status; + end + default: begin + data_o = 32'h0; + end + endcase + end + end + +endmodule diff --git a/rtl/soc/tinyriscv_soc_top.v b/rtl/soc/tinyriscv_soc_top.v index 282b906..d458987 100644 --- a/rtl/soc/tinyriscv_soc_top.v +++ b/rtl/soc/tinyriscv_soc_top.v @@ -33,7 +33,12 @@ module tinyriscv_soc_top( input wire jtag_TCK, // JTAG TCK引脚 input wire jtag_TMS, // JTAG TMS引脚 input wire jtag_TDI, // JTAG TDI引脚 - output wire jtag_TDO // JTAG TDO引脚 + output wire jtag_TDO, // JTAG TDO引脚 + + input wire spi_miso, // SPI MISO引脚 + output wire spi_mosi, // SPI MOSI引脚 + output wire spi_ss, // SPI SS引脚 + output wire spi_clk // SPI CLK引脚 ); @@ -102,6 +107,14 @@ module tinyriscv_soc_top( wire s4_req_o; wire s4_we_o; + // slave 5 interface + wire[`MemAddrBus] s5_addr_o; + wire[`MemBus] s5_data_o; + wire[`MemBus] s5_data_i; + wire s5_ack_i; + wire s5_req_o; + wire s5_we_o; + // rib wire rib_hold_flag_o; @@ -227,6 +240,22 @@ module tinyriscv_soc_top( .io_pin(io_pin) ); + // spi模块例化 + spi spi_0( + .clk(clk), + .rst(rst), + .data_i(s5_data_o), + .addr_i(s5_addr_o), + .we_i(s5_we_o), + .req_i(s5_req_o), + .data_o(s5_data_i), + .ack_o(s5_ack_i), + .spi_mosi(spi_mosi), + .spi_miso(spi_miso), + .spi_ss(spi_ss), + .spi_clk(spi_clk) + ); + // rib模块例化 rib u_rib( .clk(clk), @@ -296,6 +325,14 @@ module tinyriscv_soc_top( .s4_req_o(s4_req_o), .s4_we_o(s4_we_o), + // slave 5 interface + .s5_addr_o(s5_addr_o), + .s5_data_o(s5_data_o), + .s5_data_i(s5_data_i), + .s5_ack_i(s5_ack_i), + .s5_req_o(s5_req_o), + .s5_we_o(s5_we_o), + .hold_flag_o(rib_hold_flag_o) ); diff --git a/sim/sim_default_nowave.bat b/sim/sim_default_nowave.bat index 86be20c..fc893f2 100644 --- a/sim/sim_default_nowave.bat +++ b/sim/sim_default_nowave.bat @@ -1,2 +1,2 @@ -iverilog -s tinyriscv_soc_tb -o out.vvp -I ..\rtl\core tinyriscv_soc_tb.v ..\rtl\core\defines.v ..\rtl\core\ex.v ..\rtl\core\id.v ..\rtl\core\tinyriscv.v ..\rtl\core\pc_reg.v ..\rtl\core\id_ex.v ..\rtl\core\ctrl.v ..\rtl\core\regs.v ..\rtl\perips\ram.v ..\rtl\perips\rom.v ..\rtl\core\if_id.v ..\rtl\core\div.v ..\rtl\core\rib.v ..\rtl\core\clint.v ..\rtl\core\csr_reg.v ..\rtl\debug\jtag_dm.v ..\rtl\debug\jtag_driver.v ..\rtl\debug\jtag_top.v ..\rtl\perips\timer.v ..\rtl\perips\uart_tx.v ..\rtl\perips\gpio.v ..\rtl\soc\tinyriscv_soc_top.v +iverilog -s tinyriscv_soc_tb -o out.vvp -I ..\rtl\core tinyriscv_soc_tb.v ..\rtl\core\defines.v ..\rtl\core\ex.v ..\rtl\core\id.v ..\rtl\core\tinyriscv.v ..\rtl\core\pc_reg.v ..\rtl\core\id_ex.v ..\rtl\core\ctrl.v ..\rtl\core\regs.v ..\rtl\perips\ram.v ..\rtl\perips\rom.v ..\rtl\perips\spi.v ..\rtl\core\if_id.v ..\rtl\core\div.v ..\rtl\core\rib.v ..\rtl\core\clint.v ..\rtl\core\csr_reg.v ..\rtl\debug\jtag_dm.v ..\rtl\debug\jtag_driver.v ..\rtl\debug\jtag_top.v ..\rtl\perips\timer.v ..\rtl\perips\uart_tx.v ..\rtl\perips\gpio.v ..\rtl\soc\tinyriscv_soc_top.v vvp out.vvp diff --git a/sim/sim_new_nowave.bat b/sim/sim_new_nowave.bat index 1e7675e..864e3ea 100644 --- a/sim/sim_new_nowave.bat +++ b/sim/sim_new_nowave.bat @@ -1,3 +1,3 @@ ..\tools\BinToMem_CLI.exe %1 %2 -iverilog -s tinyriscv_soc_tb -o out.vvp -I ..\rtl\core tinyriscv_soc_tb.v ..\rtl\core\defines.v ..\rtl\core\ex.v ..\rtl\core\id.v ..\rtl\core\tinyriscv.v ..\rtl\core\pc_reg.v ..\rtl\core\id_ex.v ..\rtl\core\ctrl.v ..\rtl\core\regs.v ..\rtl\perips\ram.v ..\rtl\perips\rom.v ..\rtl\core\if_id.v ..\rtl\core\div.v ..\rtl\core\rib.v ..\rtl\core\clint.v ..\rtl\core\csr_reg.v ..\rtl\debug\jtag_dm.v ..\rtl\debug\jtag_driver.v ..\rtl\debug\jtag_top.v ..\rtl\perips\timer.v ..\rtl\perips\uart_tx.v ..\rtl\perips\gpio.v ..\rtl\soc\tinyriscv_soc_top.v +iverilog -s tinyriscv_soc_tb -o out.vvp -I ..\rtl\core tinyriscv_soc_tb.v ..\rtl\core\defines.v ..\rtl\core\ex.v ..\rtl\core\id.v ..\rtl\core\tinyriscv.v ..\rtl\core\pc_reg.v ..\rtl\core\id_ex.v ..\rtl\core\ctrl.v ..\rtl\core\regs.v ..\rtl\perips\ram.v ..\rtl\perips\rom.v ..\rtl\perips\spi.v ..\rtl\core\if_id.v ..\rtl\core\div.v ..\rtl\core\rib.v ..\rtl\core\clint.v ..\rtl\core\csr_reg.v ..\rtl\debug\jtag_dm.v ..\rtl\debug\jtag_driver.v ..\rtl\debug\jtag_top.v ..\rtl\perips\timer.v ..\rtl\perips\uart_tx.v ..\rtl\perips\gpio.v ..\rtl\soc\tinyriscv_soc_top.v vvp out.vvp