当前位置: 首页 > news >正文

用vio_uart_rpc协议,测试IIC接口的AT24C64

用vio_uart_rpc协议,测试IIC接口的AT24C64

参考

基于串口实现可扩展的硬件函数 RPC 框架(附完整 Verilog 源码)

BD

在这里插入图片描述

IIC时序图

写时序

在这里插入图片描述

读时序

在这里插入图片描述

注意

在 Vivado 里,I²C 的 SDA 引脚如果你在 top-level HDL 里写成 inout,综合工具会自动在 IO 口推导出 IOBUF。
但如果你在 Block Design 里只拉出一个 output 或 input,Vivado 不会自动推导,必须你自己插入 IOBUF 这个 原语

测试用例

用例描述发送帧(→)响应帧(←)说明
写寄存器(地址 1)01 01 44 33 22 1101 01 44 33 22 11向寄存器1写入 0x11223344
读寄存器(地址 1)00 01 00 00 00 0000 01 44 33 22 11读取寄存器1,返回上一步数据
RPC:回显(方法 0)02 00 BE BA FE CA02 00 BE BA FE CA回显参数0 = 0xCAFEBABE
RPC:加法(方法 1)02 01 04 03 02 0102 01 05 05 05 05每字节加法:+1,+2,+3,+4
RPC:读IIC AT24C6402 02 09 00 00 0002 02 89 00 00 00读到地址9的数据为0x89
RPC:写IIC AT24C6402 03 09 34 00 0002 03 09 00 00 00 地址9写入0x34
非法地址读取00 1E 00 00 00 00无响应 / 忽略地址超出范围(>29)被忽略

源文件

vio_uart.v

module vio_uart #(parameter P_PACK_LEN = 6, //一 帧字节数parameter P_CLK_FREQ = 50_000_000,parameter P_UART_BPS = 115200
)(input               i_clk       ,input               i_rst_n     ,input               i_uart_rxd  ,output              o_uart_txd  ,output reg          o_done,        //整个事务完成标志//IICoutput               o_scl    ,      //eeprom的时钟线sclinput                i_sda_i,      // 从引脚读回来的 SDA (IOBUF.O)output               o_sda_o,      // 要驱动到引脚的 SDA 值 (IOBUF.I)output               o_sda_t,      // 三态控制 (IOBUF.T) 1=高阻, 0=驱动output               o_led               //led显示eeprom读写测试结果);// ========== RX / TX 接口 ==========
wire        w_rx_done;
wire [7:0]  w_rx_data;reg         r_tx_en;
reg [7:0]   r_tx_data;
wire        w_tx_busy;uart_rx  #(.P_CLK_FREQ(P_CLK_FREQ),.P_UART_BPS(P_UART_BPS)
) uart_rx_inst(.i_clk       (i_clk),.i_rst_n     (i_rst_n),.i_uart_rxd  (i_uart_rxd),.o_uart_rx_done (w_rx_done),.o_uart_rx_data (w_rx_data)
);uart_tx  #(.P_CLK_FREQ(P_CLK_FREQ),.P_UART_BPS(P_UART_BPS)
) uart_tx_inst(.i_clk        (i_clk),.i_rst_n      (i_rst_n),.i_uart_tx_en (r_tx_en),.i_uart_tx_data (r_tx_data),.o_uart_tx_busy  (w_tx_busy),.o_uart_txd      (o_uart_txd)
);// ========== 内部信号 ==========
//接收缓冲区
reg [7:0]   r_recv_buffer  [0:P_PACK_LEN-1];
//发送缓冲区
reg [7:0]   r_tx_buffer   [0:P_PACK_LEN-1];
//接收计数器
reg [3:0]   r_rx_cnt;
//发送计数器
reg [3:0]   r_tx_cnt;
//状态
reg [2:0]   r_state,r_pre_state;
reg         r_wait_busy;localparam  S_IDLE = 3'd0,S_RECV = 3'd1,S_CMD  = 3'd2,S_RESP = 3'd3,S_SEND = 3'd4,S_RPC_PROCESSING = 3'd5;reg [31:0]  r_mem [0:29];
reg [31:0]  r_resp_data;
reg [7:0]   r_cmd_type;
reg [7:0]   r_cmd_addr;
reg [31:0]  r_cmd_data;reg   r_rpc_start;
// RPC 处理器输出端口连接线
wire [31:0] w_res_reg_0, w_res_reg_1, w_res_reg_2, w_res_reg_3;
wire   w_rpc_busy,w_rpc_done;integer     idx;
integer      i;
always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) beginr_rx_cnt    <= 0;r_tx_cnt    <= 0;r_state     <= S_IDLE;r_pre_state <= S_IDLE;r_tx_en     <= 1'b0;r_tx_data   <= 8'd0;r_wait_busy <= 1'b0;o_done <= 1'b0;r_rpc_start<= 1'b0;r_resp_data<= 32'b0;for (i = 0; i <= 16; i = i + 1) beginr_mem[i] <= 0;endfor (i = 0; i < P_PACK_LEN; i = i + 1) beginr_tx_buffer[i] <= 0;endfor (i = 0; i < P_PACK_LEN; i = i + 1) beginr_recv_buffer[i] <= 0;endend else beginr_tx_en <= 1'b0;o_done <=  1'b0;r_pre_state<= r_state;case (r_state)S_IDLE: beginr_rx_cnt    <= 0;r_tx_cnt    <= 0;r_wait_busy <= 0;r_state     <= S_RECV;o_done <= 1'b0;endS_RECV: beginif (w_rx_done) beginr_recv_buffer[r_rx_cnt] <= w_rx_data;if (r_rx_cnt == P_PACK_LEN - 1) beginr_state <= S_CMD;endr_rx_cnt <= r_rx_cnt + 1;endendS_CMD: beginr_cmd_type <= r_recv_buffer[0];r_cmd_addr <= r_recv_buffer[1];r_cmd_data <= {r_recv_buffer[5], r_recv_buffer[4], r_recv_buffer[3], r_recv_buffer[2]};if (r_recv_buffer[1]< 30) beginidx = r_recv_buffer[1];if(idx<30) begin//写if (r_recv_buffer[0] == 8'h01) beginr_mem[idx] <= {r_recv_buffer[5], r_recv_buffer[4], r_recv_buffer[3], r_recv_buffer[2]};r_state <= S_RESP;end//读else if(r_recv_buffer[0] == 8'h00) beginr_resp_data <= r_mem[idx];r_state <= S_RESP;end//rpc调用else if(r_recv_buffer[0] == 8'h02) beginr_resp_data <= 32'b0;r_rpc_start<= 1'b1;r_state <= S_RPC_PROCESSING;endendelse beginr_state <= S_IDLE;endend else beginr_state <= S_IDLE;endendS_RPC_PROCESSING: begin//上个状态也是处理RPC,且RPC处理完成if (r_pre_state==S_RPC_PROCESSING && w_rpc_busy==0 && w_rpc_done) beginr_mem[6] <= w_res_reg_0;r_mem[7] <= w_res_reg_1;r_mem[8] <= w_res_reg_2;r_mem[9] <= w_res_reg_3;r_rpc_start<= 1'b0;r_state <= S_RESP;endendS_RESP: beginr_tx_cnt<=0;if(r_recv_buffer[0] == 8'h00 || r_recv_buffer[0] == 8'h01) beginr_resp_data <= r_mem[idx];r_tx_buffer[0] <= r_cmd_type;r_tx_buffer[1] <= r_cmd_addr;r_tx_buffer[2] <= r_mem[idx][7:0];r_tx_buffer[3] <= r_mem[idx][15:8];r_tx_buffer[4] <= r_mem[idx][23:16];r_tx_buffer[5] <= r_mem[idx][31:24];r_state <= S_SEND;endelse beginr_resp_data<= w_res_reg_0;r_tx_buffer[0] <= r_cmd_type;r_tx_buffer[1] <= r_cmd_addr;r_tx_buffer[2] <= w_res_reg_0[7:0];r_tx_buffer[3] <= w_res_reg_0[15:8];r_tx_buffer[4] <= w_res_reg_0[23:16];r_tx_buffer[5] <= w_res_reg_0[31:24];r_state <= S_SEND;endendS_SEND: beginif (!w_tx_busy && !r_wait_busy) beginr_tx_data   <= r_tx_buffer[r_tx_cnt];r_tx_en     <= 1'b1;r_tx_cnt    <= r_tx_cnt + 1;r_wait_busy <= 1'b1;end else if (w_tx_busy) beginr_wait_busy <= 1'b0;if (r_tx_cnt == 6) beginr_state <= S_IDLE;o_done <= 1'b1;endendendendcaseend
end// 实例化 RPC 处理器模块,连接输入参数和输出结果寄存器rpc_processor u_rpc (.i_clk        (i_clk),.i_rst_n      (i_rst_n),.i_method_reg ({24'b0,r_recv_buffer[1]}),        // 功能号寄存器.i_req_reg_0  ({r_recv_buffer[5],r_recv_buffer[4],r_recv_buffer[3],r_recv_buffer[2]}),        // 参数0.i_req_reg_1  (r_mem[3]),        // 参数1.i_req_reg_2  (r_mem[4]),        // 参数2.i_req_reg_3  (r_mem[5]),        // 参数3.o_res_reg_0  (w_res_reg_0),    // 返回值0.o_res_reg_1  (w_res_reg_1),    // 返回值1.o_res_reg_2  (w_res_reg_2),     // 返回值2.o_res_reg_3  (w_res_reg_3),     // 返回值3.i_rpc_start  (r_rpc_start),     // 启动标志.i_rpc_valid  (1),               //RPC主机方法和参数准备好了.o_rpc_done   (w_rpc_done),    // RPC处理完成(1=结果有效).o_rpc_busy  (w_rpc_busy),   // RPC正忙(处理中保持高),.o_scl         (o_scl   ),  //I2C的SCL时钟信号.i_sda_i         (i_sda_i   ),.o_sda_o         (o_sda_o   ),.o_sda_t         (o_sda_t   ));
endmodule

uart_rx.v

module uart_rx #(parameter P_CLK_FREQ = 50_000_000,parameter P_UART_BPS = 115200
) (input           i_clk       ,input           i_rst_n   ,input           i_uart_rxd      ,output  reg     o_uart_rx_done ,output  reg [7:0] o_uart_rx_data
);//parameter define
localparam   L_BAUD_CNT_MAX=   P_CLK_FREQ/P_UART_BPS   ;//reg define
reg             r_uart_rxd0  ;
reg             r_uart_rxd1  ;
reg             r_uart_rxd2  ;
reg             r_rx_flag    ; //正在接收中的标志
reg     [3:0]   r_bit_cnt     ;
reg     [15:0]  r_baud_cnt   ;
reg     [7:0]   r_rx_data_t  ;//wire define
wire            w_start_en;
////////////////////////////////////////////////////////////////////
//*************************main code******************************
//////////////////////////////////////////////////////////////////////i_uart_rxd negedge
assign w_start_en = r_uart_rxd2 & (~r_uart_rxd1) & (~r_rx_flag);//async signal input delay
always @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n) beginr_uart_rxd0 <= 1'b0 ;r_uart_rxd1 <= 1'b0 ;r_uart_rxd2 <= 1'b0 ;endelse beginr_uart_rxd0 <= i_uart_rxd ;r_uart_rxd1 <= r_uart_rxd0 ;r_uart_rxd2 <= r_uart_rxd1 ;end
end//generate r_baud_cnt
always @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n)r_baud_cnt <= 16'd0;else if(r_rx_flag) beginif(r_baud_cnt == L_BAUD_CNT_MAX - 1'b1)r_baud_cnt <= 16'd0;elser_baud_cnt <= r_baud_cnt + 16'b1;endelser_baud_cnt <= 16'd0;
end//generate r_bit_cnt
always @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n) beginr_bit_cnt <= 4'd0;endelse if(r_rx_flag) beginif(r_baud_cnt == L_BAUD_CNT_MAX - 1'b1)r_bit_cnt <= r_bit_cnt + 1'b1;elser_bit_cnt <= r_bit_cnt;endelser_bit_cnt <= 4'd0;
end//generate r_rx_flag
always @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n)r_rx_flag <= 1'b0;else if(w_start_en)r_rx_flag <= 1'b1;else if((r_bit_cnt == 4'd9) && (r_baud_cnt == L_BAUD_CNT_MAX/2 - 1'b1))r_rx_flag <= 1'b0;elser_rx_flag <= r_rx_flag;
endalways @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n)r_rx_data_t <= 8'b0;else if(r_rx_flag) beginif(r_baud_cnt == L_BAUD_CNT_MAX/2 - 1'b1) begincase(r_bit_cnt)4'd1 : r_rx_data_t[0] <= r_uart_rxd2;4'd2 : r_rx_data_t[1] <= r_uart_rxd2;4'd3 : r_rx_data_t[2] <= r_uart_rxd2;4'd4 : r_rx_data_t[3] <= r_uart_rxd2;4'd5 : r_rx_data_t[4] <= r_uart_rxd2;4'd6 : r_rx_data_t[5] <= r_uart_rxd2;4'd7 : r_rx_data_t[6] <= r_uart_rxd2;4'd8 : r_rx_data_t[7] <= r_uart_rxd2;default : ;endcaseendelser_rx_data_t <= r_rx_data_t;endelser_rx_data_t <= 8'b0;
endalways @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n) begino_uart_rx_done <= 1'b0;o_uart_rx_data <= 8'b0;endelse if(r_bit_cnt == 4'd9 && r_baud_cnt == L_BAUD_CNT_MAX/2 - 1'b1) begino_uart_rx_done <= 1'b1;o_uart_rx_data <= r_rx_data_t;endelse begino_uart_rx_done <= 1'b0;o_uart_rx_data <= o_uart_rx_data;end
end
endmodule

uart_tx.v

module uart_tx #(parameter P_CLK_FREQ = 50_000_000,parameter P_UART_BPS = 115200
) (// from systeminput                   i_clk       ,input                   i_rst_n   ,input                   i_uart_tx_en    ,input           [7 : 0] i_uart_tx_data  ,output  reg             o_uart_tx_busy , // 发送中标志// outputoutput  reg             o_uart_txd
);// parameter define
localparam  L_BAUD_CNT_MAX = P_CLK_FREQ / P_UART_BPS;// reg define
reg [3:0]   r_bit_cnt;
reg [15:0]  r_baud_cnt;
reg [7 :0]  r_tx_data_t;
reg         r_uart_tx_en_d;//i_uart_tx_en的上升沿
wire        w_uart_tx_en_posedge;// detect i_uart_tx_en rising edge
always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)r_uart_tx_en_d <= 1'b0;elser_uart_tx_en_d <= i_uart_tx_en;
endassign w_uart_tx_en_posedge = i_uart_tx_en && !r_uart_tx_en_d;// baud rate counter
always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)r_baud_cnt <= 16'd0;else if (o_uart_tx_busy) beginif (r_baud_cnt == L_BAUD_CNT_MAX - 1)r_baud_cnt <= 16'd0;elser_baud_cnt <= r_baud_cnt + 1'b1;end else beginr_baud_cnt <= 16'd0;end
end// tx bit counter
always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)r_bit_cnt <= 4'd0;else if (o_uart_tx_busy && (r_baud_cnt == L_BAUD_CNT_MAX - 1))r_bit_cnt <= r_bit_cnt + 1'b1;else if (!o_uart_tx_busy)r_bit_cnt <= 4'd0;
end// control busy and latch data
always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) beginr_tx_data_t     <= 8'd0;o_uart_tx_busy <= 1'b0;endelse if (w_uart_tx_en_posedge && !o_uart_tx_busy) beginr_tx_data_t     <= i_uart_tx_data;o_uart_tx_busy <= 1'b1;endelse if (o_uart_tx_busy && r_bit_cnt == 4'd9 && r_baud_cnt == L_BAUD_CNT_MAX - 1) begino_uart_tx_busy <= 1'b0;end
end// generate txd signal
always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)o_uart_txd <= 1'b1;else if (o_uart_tx_busy) begincase(r_bit_cnt)4'd0 : o_uart_txd <= 1'b0;               // start bit4'd1 : o_uart_txd <= r_tx_data_t[0];4'd2 : o_uart_txd <= r_tx_data_t[1];4'd3 : o_uart_txd <= r_tx_data_t[2];4'd4 : o_uart_txd <= r_tx_data_t[3];4'd5 : o_uart_txd <= r_tx_data_t[4];4'd6 : o_uart_txd <= r_tx_data_t[5];4'd7 : o_uart_txd <= r_tx_data_t[6];4'd8 : o_uart_txd <= r_tx_data_t[7];4'd9 : o_uart_txd <= 1'b1;               // stop bitdefault : o_uart_txd <= 1'b1;endcaseendelseo_uart_txd <= 1'b1;
endendmodule

rpc_processor.v

`timescale 1ns/1ps// 宏定义:RPC方法(32位功能码)
`define RPC_FUNC_ECHO          32'h00000000  // 回显功能(返回输入参数)
`define RPC_FUNC_ADD           32'h00000001  // 加法功能(参数相加)
`define RPC_FUNC_IIC_READ      32'h00000002  //  读IIC
`define RPC_FUNC_IIC_WRITE     32'h00000003  // 写IICmodule rpc_processor (input  wire        i_clk,         // 时钟信号input  wire        i_rst_n,       // 复位信号(低有效)// 寄存器接口(直接暴露)input  wire [31:0] i_method_reg,  // 方法选择寄存器input  wire [31:0] i_req_reg_0,   // 请求参数0input  wire [31:0] i_req_reg_1,   // 请求参数1input  wire [31:0] i_req_reg_2,   // 请求参数2input  wire [31:0] i_req_reg_3,   // 请求参数3output reg  [31:0] o_res_reg_0,   // 响应结果0output reg  [31:0] o_res_reg_1,   // 响应结果1output reg  [31:0] o_res_reg_2,   // 响应结果2output reg  [31:0] o_res_reg_3,   // 响应结果3// RPC控制信号(含启动信号)input  wire        i_rpc_start,   // RPC启动信号(1=触发处理,上升沿有效)output reg         o_rpc_busy,   //  RPC处理中(处理中保持高)input  wire        i_rpc_valid,   // 外部数据有效output reg         o_rpc_done,    // RPC处理完成(1=结果有效)// iic 接口output               o_scl    ,      //eeprom的时钟线sclinput                i_sda_i,      // 从引脚读回来的 SDA (IOBUF.O)output               o_sda_o,      // 要驱动到引脚的 SDA 值 (IOBUF.I)output               o_sda_t     // 三态控制 (IOBUF.T) 1=高阻, 0=驱动
);//parameter defineparameter    P_SLAVE_ADDR = 7'b1010000     ; //器件地址(P_SLAVE_ADDR)parameter    P_BIT_CTRL   = 1'b1           ; //字地址位控制参数(16b/8b)parameter    P_CLK_FREQ   = 26'd50_000_000 ; //i2c_dri模块的驱动时钟频率(P_CLK_FREQ)parameter    P_I2C_FREQ   = 18'd250_000    ; //I2C的SCL时钟频率parameter    P_L_TIME     = 17'd125_000    ; //led闪烁时间参数parameter    P_MAX_BYTE   = 16'd256        ; //读写测试的字节个数//wire definewire           w_dri_clk   ; //I2C操作时钟wire           w_i2c_exec  ; //I2C触发控制wire   [15:0]  w_i2c_addr  ; //I2C操作地址wire   [ 7:0]  w_i2c_data_w; //I2C写入的数据wire           w_i2c_done  ; //I2C操作结束标志wire           w_i2c_ack   ; //I2C应答标志 0:应答 1:未应答wire           w_i2c_rh_wl ; //I2C读写控制wire   [ 7:0]  w_i2c_data_r; //I2C读出的数据// reg  definereg [15:0] r_i2c_addr;reg [7:0] r_i2c_data_w;reg  r_i2c_exec;reg  r_i2c_rh_wl;reg  r_i2c_ack;// connectassign w_i2c_addr = r_i2c_addr;assign w_i2c_data_w = r_i2c_data_w;assign w_i2c_exec = r_i2c_exec;assign w_i2c_rh_wl = r_i2c_rh_wl;assign w_i2c_ack = r_i2c_ack;// --------------------------// 启动信号边沿检测(防止持续触发)// --------------------------reg r_rpc_start_dly;wire w_rpc_start_posedge;  // 启动信号上升沿(真正的触发点)always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) beginr_rpc_start_dly <= 1'b0;end else beginr_rpc_start_dly <= i_rpc_start;  // 延迟一拍用于边沿检测endendassign w_rpc_start_posedge = i_rpc_start && !r_rpc_start_dly;  // 上升沿检测// --------------------------// 内部锁存寄存器(处理期间保持参数稳定)// --------------------------reg [31:0] r_method_latch;reg [31:0] r_req_latch_0, r_req_latch_1, r_req_latch_2, r_req_latch_3;wire  w_iic_method= r_method_latch==`RPC_FUNC_IIC_READ||r_method_latch==`RPC_FUNC_IIC_WRITE;// --------------------------// RPC处理状态机// --------------------------localparam S_IDLE      = 2'b00;localparam S_INIT= 2'b01;localparam S_PROCESSING = 2'b10;localparam S_DONE      = 2'b11;reg [1:0] r_state;reg [15:0] r_proc_cnt;  // 模拟处理延迟(0~15周期)always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) beginr_state <= S_IDLE;r_proc_cnt <= 16'h0;o_rpc_busy <= 1'b0;o_rpc_done <= 1'b0;r_method_latch <= 32'h0;r_req_latch_0 <= 32'h0;r_req_latch_1 <= 32'h0;r_req_latch_2 <= 32'h0;r_req_latch_3 <= 32'h0;o_res_reg_0 <= 32'h0;o_res_reg_1 <= 32'h0;o_res_reg_2 <= 32'h0;o_res_reg_3 <= 32'h0;end else begincase (r_state)S_IDLE: begin// 检测到启动信号上升沿,且外部数据有效,启动处理if (w_rpc_start_posedge && i_rpc_valid) begino_rpc_done <= 1'b0;  // 完成标志清0// 锁存当前寄存器值(处理期间参数不变)r_method_latch <= i_method_reg;r_req_latch_0 <= i_req_reg_0;r_req_latch_1 <= i_req_reg_1;r_req_latch_2 <= i_req_reg_2;r_req_latch_3 <= i_req_reg_3;o_rpc_busy <= 1'b1;      // 置位请求有效r_state <= S_INIT;    // 进入初始状态r_proc_cnt <= 16'h0;       // 重置延迟计数器r_i2c_exec <= 1'b0;end else begino_rpc_busy <= 1'b0;r_state <= S_IDLE;endendS_INIT: beginif(r_proc_cnt==16'h0) beginif(r_method_latch==`RPC_FUNC_IIC_READ) beginr_i2c_addr<={8'h00, r_req_latch_0[7:0]};  // 高8位补0,使用低8位作为地址r_i2c_rh_wl<=1;r_i2c_data_w<=8'b0;r_i2c_exec<=1;endelse if(r_method_latch==`RPC_FUNC_IIC_WRITE) beginr_i2c_addr<={8'h00, r_req_latch_0[7:0]};  // 高8位补0,使用低8位作为地址r_i2c_rh_wl<=0;r_i2c_data_w<=r_req_latch_0[15:8];r_i2c_exec<=1;endendr_proc_cnt<=r_proc_cnt+1;//让r_i2c_exec拉高久一些if(r_proc_cnt==16'd52) beginr_proc_cnt <= 16'h0;r_i2c_exec <= 1'b0;r_state <= S_PROCESSING;endendS_PROCESSING: begin// 模拟处理延迟(例如10个时钟周期,可修改)if ((r_proc_cnt >= 16'd9 && !w_iic_method)||(r_proc_cnt >= 16'd4 &&  w_i2c_done && w_iic_method)) begin// 根据方法号执行不同处理(示例逻辑)case (r_method_latch)`RPC_FUNC_ECHO: begin  // 方法0:返回请求参数o_res_reg_0 <= r_req_latch_0;o_res_reg_1 <= r_req_latch_1;o_res_reg_2 <= r_req_latch_2;o_res_reg_3 <= r_req_latch_3;end`RPC_FUNC_ADD: begin  // 方法1:参数相加o_res_reg_0[7:0] <=    r_req_latch_0[7:0]+1;o_res_reg_0[15:8] <=   r_req_latch_0[15:8]+2;o_res_reg_0[23:16] <=  r_req_latch_0[23:16]+3;o_res_reg_0[31:24] <=  r_req_latch_0[31:24]+4;end`RPC_FUNC_IIC_READ: begino_res_reg_0[7:0] <=    w_i2c_data_r;o_res_reg_0[15:8] <=   8'd0;o_res_reg_0[23:16] <=  8'd0;o_res_reg_0[31:24] <=  8'd0;end`RPC_FUNC_IIC_WRITE: begino_res_reg_0[7:0] <=     r_req_latch_0[7:0];o_res_reg_0[15:8] <=    8'd0;o_res_reg_0[23:16] <=   8'd0;o_res_reg_0[31:24] <=   8'd0;enddefault: begino_res_reg_0 <= 32'h0;o_res_reg_1 <= 32'h0;o_res_reg_2 <= 32'h0;o_res_reg_3 <= 32'h0;endendcaser_state <= S_DONE;end else beginr_proc_cnt <= r_proc_cnt + 1'b1;r_state <= S_PROCESSING;endendS_DONE: begino_rpc_busy <= 1'b0;      // 清除请求有效o_rpc_done <= 1'b1;       // 置位完成标志(通知结果就绪)r_state <= S_IDLE;          // 返回空闲状态,等待下一次启动enddefault: r_state <= S_IDLE;endcaseendend//i2c驱动模块i2c_master_dri #(.P_SLAVE_ADDR  (P_SLAVE_ADDR),  //EEPROM从机地址.P_CLK_FREQ    (P_CLK_FREQ  ),  //模块输入的时钟频率.P_I2C_FREQ    (P_I2C_FREQ  )   //IIC_SCL的时钟频率) u_i2c_master_dri(.i_clk         (i_clk   ),.i_rst_n       (i_rst_n ),//i2c interface.i_i2c_exec    (w_i2c_exec  ),  //I2C触发执行信号.i_bit_ctrl    (P_BIT_CTRL  ),  //器件地址位控制(16b/8b).i_i2c_rh_wl   (w_i2c_rh_wl ),  //I2C读写控制信号.i_i2c_addr    (w_i2c_addr  ),  //I2C器件内地址.i_i2c_data_w  (w_i2c_data_w),  //I2C要写的数据.o_i2c_data_r  (w_i2c_data_r),  //I2C读出的数据.o_i2c_done    (w_i2c_done  ),  //I2C一次操作完成.o_i2c_ack     (w_i2c_ack   ),  //I2C应答标志.o_scl         (o_scl   ),  //I2C的SCL时钟信号.i_sda_i         (i_sda_i   ),.o_sda_o         (o_sda_o   ),.o_sda_t         (o_sda_t   ));endmodule

i2c_master_dri.v


module i2c_master_dri#(parameter   P_SLAVE_ADDR = 7'b1010000   ,  //EEPROM从机地址parameter   P_CLK_FREQ   = 26'd50_000_000, //模块输入的时钟频率parameter   P_I2C_FREQ   = 18'd250_000     //IIC_SCL的时钟频率250K)(input                i_clk        ,input                i_rst_n      ,// i2c interface (bus control)input                i_i2c_exec   ,  //I2C触发执行信号input                i_bit_ctrl   ,  //字地址位控制(16b/8b)input                i_i2c_rh_wl  ,  //I2C读写控制信号 (1=read 0=write) 原名 i2c_rh_wl 保持input        [15:0]  i_i2c_addr   ,  //I2C器件内地址input        [ 7:0]  i_i2c_data_w ,  //I2C要写的数据output  reg  [ 7:0]  o_i2c_data_r ,  //I2C读出的数据output  reg          o_i2c_done   ,  //I2C一次操作完成output  reg          o_i2c_ack    ,  //I2C应答标志 0:应答 1:未应答output  reg          o_scl        ,  //I2C的SCL时钟信号// SDA 三端口替换: 外部通过 IOBUF 连接到 top IOinput                i_sda_i,      // 从引脚读回来的 SDA (IOBUF.O)output               o_sda_o,      // 要驱动到引脚的 SDA 值 (IOBUF.I)output               o_sda_t,      // 三态控制 (IOBUF.T) 1=高阻, 0=驱动// user interfaceoutput  reg          o_dri_clk     //驱动I2C操作的驱动时钟);//localparam define
localparam  S_IDLE     = 8'b0000_0001; //空闲状态
localparam  S_SLADDR   = 8'b0000_0010; //发送器件地址(slave address)
localparam  S_ADDR16   = 8'b0000_0100; //发送16位字地址
localparam  S_ADDR8    = 8'b0000_1000; //发送8位字地址
localparam  S_DATA_WR  = 8'b0001_0000; //写数据(8 bit)
localparam  S_ADDR_RD  = 8'b0010_0000; //发送器件地址读
localparam  S_DATA_RD  = 8'b0100_0000; //读数据(8 bit)
localparam  S_STOP     = 8'b1000_0000; //结束I2C操作//reg define
reg            r_sda_dir   ; //I2C数据(SDA)方向控制 (1=drive, 0=release)
reg            r_sda_out   ; //SDA输出信号 (内部驱动值)
reg            r_st_done   ; //状态结束
reg            r_wr_flag   ; //写标志
reg    [ 6:0]  r_cnt       ; //计数
reg    [ 7:0]  r_cur_state ; //状态机当前状态
reg    [ 7:0]  r_next_state; //状态机下一状态
reg    [15:0]  r_addr_t    ; //地址
reg    [ 7:0]  r_data_r    ; //读取的数据 (临时)
reg    [ 7:0]  r_data_wr_t ; //I2C需写的数据的临时寄存
reg    [ 9:0]  r_clk_cnt   ; //分频时钟计数//wire define
wire          w_sda_in     ; //SDA输入信号 (来自外部 IO via IOBUF.O)
wire   [8:0]  w_clk_divide ; //模块驱动时钟的分频系数//*****************************************************
//**                    main code
//*****************************************************// ---- SDA 信号映射:把内部 r_sda_out/r_sda_dir 暴露为模块输出 o_sda_o/o_sda_t;w_sda_in 从外部输入
assign o_sda_o      = r_sda_out;        // 内部想输出到总线的值
assign o_sda_t      = ~r_sda_dir;       // r_sda_dir==1 表示驱动 -> T = 0; r_sda_dir==0 表示释放 -> T = 1
assign w_sda_in     = i_sda_i;          // 从外部引脚读回的值 (IOBUF.O)// ---- 分频计算 (保持原逻辑)
assign  w_clk_divide = (P_CLK_FREQ/P_I2C_FREQ) >> 2'd2 ;  //模块驱动时钟的分频系数//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作
always @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n) begino_dri_clk <=  1'b0;r_clk_cnt <= 10'd0;endelse if(r_clk_cnt == (w_clk_divide[8:1] - 9'd1)) beginr_clk_cnt <= 10'd0;o_dri_clk <= ~o_dri_clk;endelser_clk_cnt <= r_clk_cnt + 10'b1;
end// 生成时钟使能信号,用于统一时钟域
reg r_dri_clk_en;
always @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n) beginr_dri_clk_en <= 1'b0;endelse if(r_clk_cnt == (w_clk_divide[8:1] - 9'd1)) beginr_dri_clk_en <= 1'b1;endelser_dri_clk_en <= 1'b0;
end//(三段式状态机)同步时序描述状态转移
always @(posedge i_clk or negedge i_rst_n) beginif(!i_rst_n)r_cur_state <= S_IDLE;else if(r_dri_clk_en)r_cur_state <= r_next_state;
end//组合逻辑判断状态转移条件
always @(*) beginr_next_state = S_IDLE;case(r_cur_state)S_IDLE: begin                          //空闲状态if(i_i2c_exec) beginr_next_state = S_SLADDR;endelser_next_state = S_IDLE;endS_SLADDR: beginif(r_st_done) beginif(i_bit_ctrl)                    //判断是16位还是8位字地址r_next_state = S_ADDR16;elser_next_state = S_ADDR8 ;endelser_next_state = S_SLADDR;endS_ADDR16: begin                        //写16位字地址if(r_st_done) beginr_next_state = S_ADDR8;endelse beginr_next_state = S_ADDR16;endendS_ADDR8: begin                         //8位字地址if(r_st_done) beginif(r_wr_flag==1'b0)               //读写判断 (注意原 r_wr_flag 用法)r_next_state = S_DATA_WR;elser_next_state = S_ADDR_RD;endelse beginr_next_state = S_ADDR8;endendS_DATA_WR: begin                       //写数据(8 bit)if(r_st_done)r_next_state = S_STOP;elser_next_state = S_DATA_WR;endS_ADDR_RD: begin                       //写地址以进行读数据if(r_st_done) beginr_next_state = S_DATA_RD;endelse beginr_next_state = S_ADDR_RD;endendS_DATA_RD: begin                       //读取数据(8 bit)if(r_st_done)r_next_state = S_STOP;elser_next_state = S_DATA_RD;endS_STOP: begin                          //结束I2C操作if(r_st_done)r_next_state = S_IDLE;elser_next_state = S_STOP ;enddefault: r_next_state= S_IDLE;endcase
end//时序电路描述状态输出
always @(posedge i_clk or negedge i_rst_n) begin//复位初始化if(!i_rst_n) begino_scl       <= 1'b1;r_sda_out   <= 1'b1;r_sda_dir   <= 1'b1;o_i2c_done  <= 1'b0;o_i2c_ack   <= 1'b0;r_cnt       <= 7'b0;r_st_done   <= 1'b0;r_data_r    <= 8'b0;o_i2c_data_r<= 8'b0;r_wr_flag   <= 1'b0;r_addr_t    <= 16'b0;r_data_wr_t <= 8'b0;endelse if(r_dri_clk_en) beginr_st_done <= 1'b0 ;r_cnt     <= r_cnt +7'b1 ;case(r_cur_state)S_IDLE: begin                          //空闲状态o_scl     <= 1'b1;r_sda_out <= 1'b1;r_sda_dir <= 1'b1;o_i2c_done<= 1'b0;r_cnt     <= 7'b0;if(i_i2c_exec) beginr_wr_flag   <= i_i2c_rh_wl ;r_addr_t    <= i_i2c_addr  ;r_data_wr_t <= i_i2c_data_w;o_i2c_ack   <= 1'b0;endendS_SLADDR: begin                         //写地址(器件地址和字地址)case(r_cnt)7'd1 : r_sda_out <= 1'b0;          //开始I2C7'd3 : o_scl <= 1'b0;7'd4 : r_sda_out <= P_SLAVE_ADDR[6]; //传送器件地址7'd5 : o_scl <= 1'b1;7'd7 : o_scl <= 1'b0;7'd8 : r_sda_out <= P_SLAVE_ADDR[5];7'd9 : o_scl <= 1'b1;7'd11: o_scl <= 1'b0;7'd12: r_sda_out <= P_SLAVE_ADDR[4];7'd13: o_scl <= 1'b1;7'd15: o_scl <= 1'b0;7'd16: r_sda_out <= P_SLAVE_ADDR[3];7'd17: o_scl <= 1'b1;7'd19: o_scl <= 1'b0;7'd20: r_sda_out <= P_SLAVE_ADDR[2];7'd21: o_scl <= 1'b1;7'd23: o_scl <= 1'b0;7'd24: r_sda_out <= P_SLAVE_ADDR[1];7'd25: o_scl <= 1'b1;7'd27: o_scl <= 1'b0;7'd28: r_sda_out <= P_SLAVE_ADDR[0];7'd29: o_scl <= 1'b1;7'd31: o_scl <= 1'b0;7'd32: r_sda_out <= 1'b0;          //0:写7'd33: o_scl <= 1'b1;7'd35: o_scl <= 1'b0;7'd36: beginr_sda_dir <= 1'b0;r_sda_out <= 1'b1;end7'd37: o_scl     <= 1'b1;7'd38: begin                     //从机应答r_st_done <= 1'b1;if(w_sda_in == 1'b1)           //高电平表示未应答o_i2c_ack <= 1'b1;         //拉高应答标志位end7'd39: begino_scl <= 1'b0;r_cnt <= 7'b0;enddefault :  ;endcaseendS_ADDR16: begincase(r_cnt)7'd0 : beginr_sda_dir <= 1'b1 ;r_sda_out <= r_addr_t[15];       //传送字地址end7'd1 : o_scl <= 1'b1;7'd3 : o_scl <= 1'b0;7'd4 : r_sda_out <= r_addr_t[14];7'd5 : o_scl <= 1'b1;7'd7 : o_scl <= 1'b0;7'd8 : r_sda_out <= r_addr_t[13];7'd9 : o_scl <= 1'b1;7'd11: o_scl <= 1'b0;7'd12: r_sda_out <= r_addr_t[12];7'd13: o_scl <= 1'b1;7'd15: o_scl <= 1'b0;7'd16: r_sda_out <= r_addr_t[11];7'd17: o_scl <= 1'b1;7'd19: o_scl <= 1'b0;7'd20: r_sda_out <= r_addr_t[10];7'd21: o_scl <= 1'b1;7'd23: o_scl <= 1'b0;7'd24: r_sda_out <= r_addr_t[9];7'd25: o_scl <= 1'b1;7'd27: o_scl <= 1'b0;7'd28: r_sda_out <= r_addr_t[8];7'd29: o_scl <= 1'b1;7'd31: o_scl <= 1'b0;7'd32: beginr_sda_dir <= 1'b0;r_sda_out <= 1'b1;end7'd33: o_scl  <= 1'b1;7'd34: begin                     //从机应答r_st_done <= 1'b1;if(w_sda_in == 1'b1)           //高电平表示未应答o_i2c_ack <= 1'b1;         //拉高应答标志位end7'd35: begino_scl <= 1'b0;r_cnt <= 7'b0;enddefault :  ;endcaseendS_ADDR8: begincase(r_cnt)7'd0: beginr_sda_dir <= 1'b1 ;r_sda_out <= r_addr_t[7];         //字地址end7'd1 : o_scl <= 1'b1;7'd3 : o_scl <= 1'b0;7'd4 : r_sda_out <= r_addr_t[6];7'd5 : o_scl <= 1'b1;7'd7 : o_scl <= 1'b0;7'd8 : r_sda_out <= r_addr_t[5];7'd9 : o_scl <= 1'b1;7'd11: o_scl <= 1'b0;7'd12: r_sda_out <= r_addr_t[4];7'd13: o_scl <= 1'b1;7'd15: o_scl <= 1'b0;7'd16: r_sda_out <= r_addr_t[3];7'd17: o_scl <= 1'b1;7'd19: o_scl <= 1'b0;7'd20: r_sda_out <= r_addr_t[2];7'd21: o_scl <= 1'b1;7'd23: o_scl <= 1'b0;7'd24: r_sda_out <= r_addr_t[1];7'd25: o_scl <= 1'b1;7'd27: o_scl <= 1'b0;7'd28: r_sda_out <= r_addr_t[0];7'd29: o_scl <= 1'b1;7'd31: o_scl <= 1'b0;7'd32: beginr_sda_dir <= 1'b0;r_sda_out <= 1'b1;end7'd33: o_scl     <= 1'b1;7'd34: begin                     //从机应答r_st_done <= 1'b1;if(w_sda_in == 1'b1)           //高电平表示未应答o_i2c_ack <= 1'b1;         //拉高应答标志位end7'd35: begino_scl <= 1'b0;r_cnt <= 7'b0;enddefault :  ;endcaseendS_DATA_WR: begin                        //写数据(8 bit)case(r_cnt)7'd0: beginr_sda_dir <= 1'b1;r_sda_out <= r_data_wr_t[7];     //I2C写8位数据end7'd1 : o_scl <= 1'b1;7'd3 : o_scl <= 1'b0;7'd4 : r_sda_out <= r_data_wr_t[6];7'd5 : o_scl <= 1'b1;7'd7 : o_scl <= 1'b0;7'd8 : r_sda_out <= r_data_wr_t[5];7'd9 : o_scl <= 1'b1;7'd11: o_scl <= 1'b0;7'd12: r_sda_out <= r_data_wr_t[4];7'd13: o_scl <= 1'b1;7'd15: o_scl <= 1'b0;7'd16: r_sda_out <= r_data_wr_t[3];7'd17: o_scl <= 1'b1;7'd19: o_scl <= 1'b0;7'd20: r_sda_out <= r_data_wr_t[2];7'd21: o_scl <= 1'b1;7'd23: o_scl <= 1'b0;7'd24: r_sda_out <= r_data_wr_t[1];7'd25: o_scl <= 1'b1;7'd27: o_scl <= 1'b0;7'd28: r_sda_out <= r_data_wr_t[0];7'd29: o_scl <= 1'b1;7'd31: o_scl <= 1'b0;7'd32: beginr_sda_dir <= 1'b0;r_sda_out <= 1'b1;end7'd33: o_scl <= 1'b1;7'd34: begin                     //从机应答r_st_done <= 1'b1;if(w_sda_in == 1'b1)           //高电平表示未应答o_i2c_ack <= 1'b1;         //拉高应答标志位end7'd35: begino_scl  <= 1'b0;r_cnt  <= 7'b0;enddefault  :  ;endcaseendS_ADDR_RD: begin                        //写地址以进行读数据case(r_cnt)7'd0 : beginr_sda_dir <= 1'b1;r_sda_out <= 1'b1;end7'd1 : o_scl <= 1'b1;7'd2 : r_sda_out <= 1'b0;          //重新开始7'd3 : o_scl <= 1'b0;7'd4 : r_sda_out <= P_SLAVE_ADDR[6]; //传送器件地址7'd5 : o_scl <= 1'b1;7'd7 : o_scl <= 1'b0;7'd8 : r_sda_out <= P_SLAVE_ADDR[5];7'd9 : o_scl <= 1'b1;7'd11: o_scl <= 1'b0;7'd12: r_sda_out <= P_SLAVE_ADDR[4];7'd13: o_scl <= 1'b1;7'd15: o_scl <= 1'b0;7'd16: r_sda_out <= P_SLAVE_ADDR[3];7'd17: o_scl <= 1'b1;7'd19: o_scl <= 1'b0;7'd20: r_sda_out <= P_SLAVE_ADDR[2];7'd21: o_scl <= 1'b1;7'd23: o_scl <= 1'b0;7'd24: r_sda_out <= P_SLAVE_ADDR[1];7'd25: o_scl <= 1'b1;7'd27: o_scl <= 1'b0;7'd28: r_sda_out <= P_SLAVE_ADDR[0];7'd29: o_scl <= 1'b1;7'd31: o_scl <= 1'b0;7'd32: r_sda_out <= 1'b1;          //1:读7'd33: o_scl <= 1'b1;7'd35: o_scl <= 1'b0;7'd36: beginr_sda_dir <= 1'b0;r_sda_out <= 1'b1;end7'd37: o_scl     <= 1'b1;7'd38: begin                     //从机应答r_st_done <= 1'b1;if(w_sda_in == 1'b1)           //高电平表示未应答o_i2c_ack <= 1'b1;         //拉高应答标志位end7'd39: begino_scl <= 1'b0;r_cnt <= 7'b0;enddefault : ;endcaseendS_DATA_RD: begin                        //读取数据(8 bit)case(r_cnt)7'd0: r_sda_dir <= 1'b0;7'd1: beginr_data_r[7] <= w_sda_in;o_scl       <= 1'b1;end7'd3: o_scl  <= 1'b0;7'd5: beginr_data_r[6] <= w_sda_in ;o_scl       <= 1'b1   ;end7'd7: o_scl  <= 1'b0;7'd9: beginr_data_r[5] <= w_sda_in;o_scl       <= 1'b1  ;end7'd11: o_scl  <= 1'b0;7'd13: beginr_data_r[4] <= w_sda_in;o_scl       <= 1'b1  ;end7'd15: o_scl  <= 1'b0;7'd17: beginr_data_r[3] <= w_sda_in;o_scl       <= 1'b1  ;end7'd19: o_scl  <= 1'b0;7'd21: beginr_data_r[2] <= w_sda_in;o_scl       <= 1'b1  ;end7'd23: o_scl  <= 1'b0;7'd25: beginr_data_r[1] <= w_sda_in;o_scl       <= 1'b1  ;end7'd27: o_scl  <= 1'b0;7'd29: beginr_data_r[0] <= w_sda_in;o_scl       <= 1'b1  ;end7'd31: o_scl  <= 1'b0;7'd32: beginr_sda_dir <= 1'b1;r_sda_out <= 1'b1;end7'd33: o_scl     <= 1'b1;7'd34: r_st_done <= 1'b1;          //非应答7'd35: begino_scl <= 1'b0;r_cnt <= 7'b0;o_i2c_data_r <= r_data_r;enddefault  :  ;endcaseendS_STOP: begin                           //结束I2C操作case(r_cnt)7'd0: beginr_sda_dir <= 1'b1;             //结束I2Cr_sda_out <= 1'b0;end7'd1 : o_scl     <= 1'b1;7'd3 : r_sda_out <= 1'b1;7'd15: r_st_done <= 1'b1;7'd16: beginr_cnt      <= 7'b0;o_i2c_done <= 1'b1;            //向上层模块传递I2C结束信号enddefault  : ;endcaseendendcaseend
endendmodule

iobuf_wrapper.v

module iobuf_wrapper (input  wire I,output wire O,inout  wire IO,input  wire T
);IOBUF u_iobuf (.I(I), .O(O), .IO(IO), .T(T));
endmodule

readme.md

set rtl_dir "D:/workspace/gitee/ant_prj/ant/src/rtl/iic"
add_files $rtl_dir/rpc_processor.v
add_files $rtl_dir/uart_rx.v
add_files $rtl_dir/uart_tx.v
add_files $rtl_dir/vio_uart.v
add_files $rtl_dir/i2c_master_dri.v
add_files $rtl_dir/iobuf_wrapper.v

pin.xdc

#时序约束
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
#IO引脚约束
#----------------------系统时钟---------------------------
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
#----------------------系统复位---------------------------
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
set_property -dict {PACKAGE_PIN K14 IOSTANDARD LVCMOS33} [get_ports uart_rxd]
set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports uart_txd]
set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports iic_scl]
set_property -dict {PACKAGE_PIN F17 IOSTANDARD LVCMOS33} [get_ports iic_sda]
set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports led]
http://www.dtcms.com/a/399662.html

相关文章:

  • 杭州网站快速备案正规电商培训班
  • 台州做网站多少钱镇江佳鑫网络科技有限公司
  • APM v4.1.1 | 免费音乐听歌B站油管音乐播放器
  • 牛客算法基础noob51 杨辉三角
  • SVN忽略文件不生效
  • MyBatis开启自动下划线转驼峰
  • 自己做网站 搜索功能开发汽车商城网站模板免费下载
  • 加拿大住宅代理指南(2025年更新)
  • 专门建站的公司制作u盘启动盘
  • redis的set集合的常规使用
  • 【C++模板编程】从泛型思想到实战应用
  • auto 关键字
  • 工程项目建设自学网站哪家网站开发好
  • 企业网站建设文档微信开发应用平台
  • 大语言模型本身有记忆功能吗?
  • 解决Initializing Python failed: Failed to import encodings module错误
  • 上海做网站哪里有wordpress环境安装
  • 兖州市做网站wordpress电子商务视频教程
  • 优秀网站模板中国10大装修公司排名
  • python++springboot+nodejs微信小程序高校实验室管理系统 实验室预约登记 设备借用管理 实验记录审核系统
  • 外贸精品网站建设网站运营介绍
  • 构建神经网络的两大核心工具
  • 品牌高端网站制作金蝶软件多少钱
  • 基于STM32舞台彩灯控制器设计app控制系统
  • 2D激光定位与建图
  • shell编程:grep - 文本搜索利器(1)
  • 网站建设制作公司地址做照片书网站
  • 鸿蒙Next远端状态订阅开发实例:实现进程状态监控与资源管理
  • 济宁做网站的WordPress重新安装删除哪个
  • Deep Residual Learning for Image Recognition 阅读笔记