rtl:perips:i2c: add i2c slave
Signed-off-by: liangkangnan <liangkangnan@163.com>pull/4/head
parent
7e57d8db17
commit
e708eb6d4d
|
@ -58,6 +58,7 @@
|
||||||
../rtl/perips/i2c/i2c_core.sv
|
../rtl/perips/i2c/i2c_core.sv
|
||||||
../rtl/perips/i2c/i2c_top.sv
|
../rtl/perips/i2c/i2c_top.sv
|
||||||
../rtl/perips/i2c/i2c_master.sv
|
../rtl/perips/i2c/i2c_master.sv
|
||||||
|
../rtl/perips/i2c/i2c_slave.sv
|
||||||
|
|
||||||
../rtl/sys_bus/obi_interconnect.sv
|
../rtl/sys_bus/obi_interconnect.sv
|
||||||
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
||||||
|
|
|
@ -36,15 +36,23 @@
|
||||||
desc: "0: write, 1: read",
|
desc: "0: write, 1: read",
|
||||||
}
|
}
|
||||||
{ bits: "5",
|
{ bits: "5",
|
||||||
name: "ACK",
|
|
||||||
swaccess: "ro",
|
|
||||||
desc: "0: ack, 1: nack",
|
|
||||||
}
|
|
||||||
{ bits: "6",
|
|
||||||
name: "ERROR",
|
name: "ERROR",
|
||||||
swaccess: "ro",
|
swaccess: "ro",
|
||||||
desc: "0: no error, 1: error",
|
desc: "0: no error, 1: error",
|
||||||
}
|
}
|
||||||
|
{ bits: "6",
|
||||||
|
name: "SLAVE_WR",
|
||||||
|
swaccess: "ro",
|
||||||
|
desc: "0: write, 1: read",
|
||||||
|
}
|
||||||
|
{ bits: "7",
|
||||||
|
name: "SLAVE_RDY",
|
||||||
|
desc: "0: not ready, 1: ready",
|
||||||
|
}
|
||||||
|
{ bits: "15:8",
|
||||||
|
name: "SLAVE_ADDR",
|
||||||
|
desc: "I2C slave address",
|
||||||
|
}
|
||||||
{ bits: "31:16",
|
{ bits: "31:16",
|
||||||
name: "CLK_DIV",
|
name: "CLK_DIV",
|
||||||
desc: "I2C clock divider count",
|
desc: "I2C clock divider count",
|
||||||
|
@ -70,15 +78,59 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
{ name: "SLAVE_DATA",
|
{ name: "SLAVE_ADDR",
|
||||||
desc: "I2C slave received data register",
|
desc: "I2C slave read or write address register",
|
||||||
swaccess: "ro",
|
swaccess: "ro",
|
||||||
hwaccess: "hrw",
|
hwaccess: "hrw",
|
||||||
hwext: "true",
|
|
||||||
hwre: "true",
|
|
||||||
fields: [
|
fields: [
|
||||||
{ bits: "7:0",
|
{ bits: "7:0",
|
||||||
desc: "I2C slave received data(fifo)",
|
name: "ADDR0",
|
||||||
|
desc: "I2C slave read or write address[7:0]",
|
||||||
|
}
|
||||||
|
{ bits: "15:8",
|
||||||
|
name: "ADDR1",
|
||||||
|
desc: "I2C slave read or write address[15:8]",
|
||||||
|
}
|
||||||
|
{ bits: "23:16",
|
||||||
|
name: "ADDR2",
|
||||||
|
desc: "I2C slave read or write address[23:16]",
|
||||||
|
}
|
||||||
|
{ bits: "31:24",
|
||||||
|
name: "ADDR3",
|
||||||
|
desc: "I2C slave read or write address[31:24]",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "SLAVE_WDATA",
|
||||||
|
desc: "I2C slave write data register",
|
||||||
|
swaccess: "ro",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
fields: [
|
||||||
|
{ bits: "7:0",
|
||||||
|
name: "WDATA0",
|
||||||
|
desc: "I2C slave write data[7:0]",
|
||||||
|
}
|
||||||
|
{ bits: "15:8",
|
||||||
|
name: "WDATA1",
|
||||||
|
desc: "I2C slave write data[15:8]",
|
||||||
|
}
|
||||||
|
{ bits: "23:16",
|
||||||
|
name: "WDATA2",
|
||||||
|
desc: "I2C slave write data[23:16]",
|
||||||
|
}
|
||||||
|
{ bits: "31:24",
|
||||||
|
name: "WDATA3",
|
||||||
|
desc: "I2C slave write data[31:24]",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "SLAVE_RDATA",
|
||||||
|
desc: "I2C slave read data register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hro",
|
||||||
|
fields: [
|
||||||
|
{ bits: "31:0",
|
||||||
|
desc: "I2C slave read data",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ module i2c_core (
|
||||||
i2c_reg_pkg::i2c_hw2reg_t hw2reg;
|
i2c_reg_pkg::i2c_hw2reg_t hw2reg;
|
||||||
|
|
||||||
logic master_mode;
|
logic master_mode;
|
||||||
logic slave_mode;
|
|
||||||
logic op_write;
|
logic op_write;
|
||||||
logic op_read;
|
logic op_read;
|
||||||
logic start;
|
logic start;
|
||||||
|
@ -50,13 +49,36 @@ module i2c_core (
|
||||||
logic [7:0] master_address;
|
logic [7:0] master_address;
|
||||||
logic [7:0] master_register;
|
logic [7:0] master_register;
|
||||||
logic [7:0] master_data;
|
logic [7:0] master_data;
|
||||||
logic master_ready, master_ready_q;
|
logic master_ready, master_ready_re;
|
||||||
logic master_start;
|
logic master_start;
|
||||||
logic master_error;
|
logic master_error;
|
||||||
logic [7:0] master_read_data;
|
logic [7:0] master_read_data;
|
||||||
|
logic master_scl;
|
||||||
|
logic master_scl_oe;
|
||||||
|
logic master_sda;
|
||||||
|
logic master_sda_oe;
|
||||||
|
logic slave_mode;
|
||||||
|
logic slave_start;
|
||||||
|
logic [7:0] slave_address;
|
||||||
|
logic [7:0] slave_recv_address;
|
||||||
|
logic [7:0] slave_send_data;
|
||||||
|
logic [7:0] slave_recv_data;
|
||||||
|
logic slave_recv_read;
|
||||||
|
logic slave_recv_valid, slave_recv_valid_re;
|
||||||
|
logic slave_op_req, slave_op_req_re;
|
||||||
|
logic slave_scl;
|
||||||
|
logic slave_scl_oe;
|
||||||
|
logic slave_sda;
|
||||||
|
logic slave_sda_oe;
|
||||||
|
|
||||||
|
assign scl_o = master_scl | slave_scl;
|
||||||
|
assign scl_oe_o = master_scl_oe | slave_scl_oe;
|
||||||
|
assign sda_o = master_sda | slave_sda;
|
||||||
|
assign sda_oe_o = master_sda_oe | slave_sda_oe;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////// master //////////////////////////////////////////////////////////
|
||||||
|
|
||||||
assign master_mode = ~reg2hw.ctrl.mode.q;
|
assign master_mode = ~reg2hw.ctrl.mode.q;
|
||||||
assign slave_mode = reg2hw.ctrl.mode.q;
|
|
||||||
assign op_write = ~reg2hw.ctrl.write.q;
|
assign op_write = ~reg2hw.ctrl.write.q;
|
||||||
assign op_read = reg2hw.ctrl.write.q;
|
assign op_read = reg2hw.ctrl.write.q;
|
||||||
assign start = reg2hw.ctrl.start.q;
|
assign start = reg2hw.ctrl.start.q;
|
||||||
|
@ -68,35 +90,152 @@ module i2c_core (
|
||||||
assign master_data = reg2hw.master_data.data.q;
|
assign master_data = reg2hw.master_data.data.q;
|
||||||
|
|
||||||
// 软件写1启动master传输
|
// 软件写1启动master传输
|
||||||
assign master_start = reg2hw.ctrl.start.qe && reg2hw.ctrl.start.q && master_ready;
|
assign master_start = reg2hw.ctrl.start.qe && reg2hw.ctrl.start.q && master_ready && master_mode;
|
||||||
|
|
||||||
// master传输完成后,硬件清start位
|
// master传输完成,硬件清start位
|
||||||
assign hw2reg.ctrl.start.d = 1'b0;
|
assign hw2reg.ctrl.start.d = 1'b0;
|
||||||
// master传输完成上升沿脉冲
|
assign hw2reg.ctrl.start.de = master_ready_re;
|
||||||
assign hw2reg.ctrl.start.de = (~master_ready_q) && master_ready;
|
|
||||||
|
|
||||||
// 传输完成产生中断pending
|
// 传输完成产生中断pending
|
||||||
assign hw2reg.ctrl.int_pending.d = 1'b1;
|
assign hw2reg.ctrl.int_pending.d = 1'b1;
|
||||||
assign hw2reg.ctrl.int_pending.de = int_enable && (~master_ready_q) && master_ready;
|
assign hw2reg.ctrl.int_pending.de = int_enable && (master_ready_re || slave_op_req_re);
|
||||||
|
|
||||||
// 传输完成并且是读操作,则更新master data
|
// 传输完成并且是读操作,则更新master data
|
||||||
assign hw2reg.master_data.data.d = master_read_data;
|
assign hw2reg.master_data.data.d = master_read_data;
|
||||||
assign hw2reg.master_data.data.de = op_read && (~master_ready_q) && master_ready;
|
assign hw2reg.master_data.data.de = op_read && master_ready_re;
|
||||||
|
|
||||||
// 传输完成更新error
|
// 传输完成更新error
|
||||||
assign hw2reg.ctrl.error.d = master_error;
|
assign hw2reg.ctrl.error.d = master_error;
|
||||||
assign hw2reg.ctrl.error.de = (~master_ready_q) && master_ready;
|
assign hw2reg.ctrl.error.de = master_ready_re;
|
||||||
|
|
||||||
assign irq_o = reg2hw.ctrl.int_pending.q;
|
assign irq_o = reg2hw.ctrl.int_pending.q;
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
edge_detect master_ready_edge_detect (
|
||||||
if (~rst_ni) begin
|
.clk_i (clk_i),
|
||||||
master_ready_q <= 1'b1;
|
.rst_ni (rst_ni),
|
||||||
end else begin
|
.sig_i (master_ready),
|
||||||
master_ready_q <= master_ready;
|
.sig_o (),
|
||||||
|
.re_o (master_ready_re),
|
||||||
|
.fe_o ()
|
||||||
|
);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////// slave //////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
assign slave_start = reg2hw.ctrl.start.q;
|
||||||
|
assign slave_mode = reg2hw.ctrl.mode.q;
|
||||||
|
assign slave_address = reg2hw.ctrl.slave_addr.q;
|
||||||
|
|
||||||
|
// 收到请求后清ready状态
|
||||||
|
assign hw2reg.ctrl.slave_rdy.d = 1'b0;
|
||||||
|
assign hw2reg.ctrl.slave_rdy.de = slave_op_req_re;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
slave_send_data = '0;
|
||||||
|
hw2reg.slave_addr.addr0.de = 1'b0;
|
||||||
|
hw2reg.slave_addr.addr0.d = '0;
|
||||||
|
hw2reg.slave_addr.addr1.de = 1'b0;
|
||||||
|
hw2reg.slave_addr.addr1.d = '0;
|
||||||
|
hw2reg.slave_addr.addr2.de = 1'b0;
|
||||||
|
hw2reg.slave_addr.addr2.d = '0;
|
||||||
|
hw2reg.slave_addr.addr3.de = 1'b0;
|
||||||
|
hw2reg.slave_addr.addr3.d = '0;
|
||||||
|
hw2reg.slave_wdata.wdata0.de = 1'b0;
|
||||||
|
hw2reg.slave_wdata.wdata0.d = '0;
|
||||||
|
hw2reg.slave_wdata.wdata1.de = 1'b0;
|
||||||
|
hw2reg.slave_wdata.wdata1.d = '0;
|
||||||
|
hw2reg.slave_wdata.wdata2.de = 1'b0;
|
||||||
|
hw2reg.slave_wdata.wdata2.d = '0;
|
||||||
|
hw2reg.slave_wdata.wdata3.de = 1'b0;
|
||||||
|
hw2reg.slave_wdata.wdata3.d = '0;
|
||||||
|
hw2reg.ctrl.slave_wr.de = 1'b0;
|
||||||
|
hw2reg.ctrl.slave_wr.d = '0;
|
||||||
|
|
||||||
|
case (slave_recv_address)
|
||||||
|
8'h0: begin
|
||||||
|
slave_send_data = {6'h0, reg2hw.ctrl.slave_rdy.q, 1'b0};
|
||||||
|
end
|
||||||
|
8'hc: begin
|
||||||
|
slave_send_data = reg2hw.slave_rdata.q[7:0];
|
||||||
|
end
|
||||||
|
8'hd: begin
|
||||||
|
slave_send_data = reg2hw.slave_rdata.q[15:8];
|
||||||
|
end
|
||||||
|
8'he: begin
|
||||||
|
slave_send_data = reg2hw.slave_rdata.q[23:16];
|
||||||
|
end
|
||||||
|
8'hf: begin
|
||||||
|
slave_send_data = reg2hw.slave_rdata.q[31:24];
|
||||||
|
end
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
|
||||||
|
// 收到写请求
|
||||||
|
if (slave_recv_valid_re && (!slave_recv_read)) begin
|
||||||
|
case (slave_recv_address)
|
||||||
|
8'h0: begin
|
||||||
|
hw2reg.ctrl.slave_wr.de = 1'b1;
|
||||||
|
hw2reg.ctrl.slave_wr.d = slave_recv_data[0];
|
||||||
|
end
|
||||||
|
8'h4: begin
|
||||||
|
hw2reg.slave_addr.addr0.de = 1'b1;
|
||||||
|
hw2reg.slave_addr.addr0.d = slave_recv_data;
|
||||||
|
end
|
||||||
|
8'h5: begin
|
||||||
|
hw2reg.slave_addr.addr1.de = 1'b1;
|
||||||
|
hw2reg.slave_addr.addr1.d = slave_recv_data;
|
||||||
|
end
|
||||||
|
8'h6: begin
|
||||||
|
hw2reg.slave_addr.addr2.de = 1'b1;
|
||||||
|
hw2reg.slave_addr.addr2.d = slave_recv_data;
|
||||||
|
end
|
||||||
|
8'h7: begin
|
||||||
|
hw2reg.slave_addr.addr3.de = 1'b1;
|
||||||
|
hw2reg.slave_addr.addr3.d = slave_recv_data;
|
||||||
|
end
|
||||||
|
8'h8: begin
|
||||||
|
hw2reg.slave_wdata.wdata0.de = 1'b1;
|
||||||
|
hw2reg.slave_wdata.wdata0.d = slave_recv_data;
|
||||||
|
end
|
||||||
|
8'h9: begin
|
||||||
|
hw2reg.slave_wdata.wdata1.de = 1'b1;
|
||||||
|
hw2reg.slave_wdata.wdata1.d = slave_recv_data;
|
||||||
|
end
|
||||||
|
8'ha: begin
|
||||||
|
hw2reg.slave_wdata.wdata2.de = 1'b1;
|
||||||
|
hw2reg.slave_wdata.wdata2.d = slave_recv_data;
|
||||||
|
end
|
||||||
|
8'hb: begin
|
||||||
|
hw2reg.slave_wdata.wdata3.de = 1'b1;
|
||||||
|
hw2reg.slave_wdata.wdata3.d = slave_recv_data;
|
||||||
|
end
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// master写0x00地址,发出中断(通知软件)
|
||||||
|
assign slave_op_req = slave_recv_valid_re && (!slave_recv_read) && (slave_recv_address == 8'h0);
|
||||||
|
|
||||||
|
// 软件收到请求上升沿检测
|
||||||
|
edge_detect slave_op_req_edge_detect (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.sig_i (slave_op_req),
|
||||||
|
.sig_o (),
|
||||||
|
.re_o (slave_op_req_re),
|
||||||
|
.fe_o ()
|
||||||
|
);
|
||||||
|
|
||||||
|
// slave收到请求上升沿检测
|
||||||
|
edge_detect slave_recv_valid_edge_detect (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.sig_i (slave_recv_valid),
|
||||||
|
.sig_o (),
|
||||||
|
.re_o (slave_recv_valid_re),
|
||||||
|
.fe_o ()
|
||||||
|
);
|
||||||
|
|
||||||
i2c_master u_i2c_master (
|
i2c_master u_i2c_master (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
.rst_ni (rst_ni),
|
.rst_ni (rst_ni),
|
||||||
|
@ -111,11 +250,29 @@ module i2c_core (
|
||||||
.error_o (master_error),
|
.error_o (master_error),
|
||||||
.data_o (master_read_data),
|
.data_o (master_read_data),
|
||||||
.scl_i (scl_i),
|
.scl_i (scl_i),
|
||||||
.scl_o (scl_o),
|
.scl_o (master_scl),
|
||||||
.scl_oe_o (scl_oe_o),
|
.scl_oe_o (master_scl_oe),
|
||||||
.sda_i (sda_i),
|
.sda_i (sda_i),
|
||||||
.sda_o (sda_o),
|
.sda_o (master_sda),
|
||||||
.sda_oe_o (sda_oe_o)
|
.sda_oe_o (master_sda_oe)
|
||||||
|
);
|
||||||
|
|
||||||
|
i2c_slave u_i2c_slave (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.enable_i (slave_mode & slave_start),
|
||||||
|
.slave_addr_i (slave_address),
|
||||||
|
.data_i (slave_send_data),
|
||||||
|
.addr_o (slave_recv_address),
|
||||||
|
.read_o (slave_recv_read),
|
||||||
|
.valid_o (slave_recv_valid),
|
||||||
|
.data_o (slave_recv_data),
|
||||||
|
.scl_i (scl_i),
|
||||||
|
.scl_o (slave_scl),
|
||||||
|
.scl_oe_o (slave_scl_oe),
|
||||||
|
.sda_i (sda_i),
|
||||||
|
.sda_o (slave_sda),
|
||||||
|
.sda_oe_o (slave_sda_oe)
|
||||||
);
|
);
|
||||||
|
|
||||||
i2c_reg_top u_i2c_reg_top (
|
i2c_reg_top u_i2c_reg_top (
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
package i2c_reg_pkg;
|
package i2c_reg_pkg;
|
||||||
|
|
||||||
// Address widths within the block
|
// Address widths within the block
|
||||||
parameter int BlockAw = 4;
|
parameter int BlockAw = 5;
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
// Typedefs for registers //
|
// Typedefs for registers //
|
||||||
|
@ -37,11 +37,19 @@ package i2c_reg_pkg;
|
||||||
struct packed {
|
struct packed {
|
||||||
logic q;
|
logic q;
|
||||||
logic qe;
|
logic qe;
|
||||||
} ack;
|
} error;
|
||||||
struct packed {
|
struct packed {
|
||||||
logic q;
|
logic q;
|
||||||
logic qe;
|
logic qe;
|
||||||
} error;
|
} slave_wr;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} slave_rdy;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
logic qe;
|
||||||
|
} slave_addr;
|
||||||
struct packed {
|
struct packed {
|
||||||
logic [15:0] q;
|
logic [15:0] q;
|
||||||
logic qe;
|
logic qe;
|
||||||
|
@ -61,9 +69,38 @@ package i2c_reg_pkg;
|
||||||
} i2c_reg2hw_master_data_reg_t;
|
} i2c_reg2hw_master_data_reg_t;
|
||||||
|
|
||||||
typedef struct packed {
|
typedef struct packed {
|
||||||
|
struct packed {
|
||||||
logic [7:0] q;
|
logic [7:0] q;
|
||||||
logic re;
|
} addr0;
|
||||||
} i2c_reg2hw_slave_data_reg_t;
|
struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
} addr1;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
} addr2;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
} addr3;
|
||||||
|
} i2c_reg2hw_slave_addr_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
} wdata0;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
} wdata1;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
} wdata2;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
} wdata3;
|
||||||
|
} i2c_reg2hw_slave_wdata_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [31:0] q;
|
||||||
|
} i2c_reg2hw_slave_rdata_reg_t;
|
||||||
|
|
||||||
typedef struct packed {
|
typedef struct packed {
|
||||||
struct packed {
|
struct packed {
|
||||||
|
@ -89,11 +126,19 @@ package i2c_reg_pkg;
|
||||||
struct packed {
|
struct packed {
|
||||||
logic d;
|
logic d;
|
||||||
logic de;
|
logic de;
|
||||||
} ack;
|
} error;
|
||||||
struct packed {
|
struct packed {
|
||||||
logic d;
|
logic d;
|
||||||
logic de;
|
logic de;
|
||||||
} error;
|
} slave_wr;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} slave_rdy;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
logic de;
|
||||||
|
} slave_addr;
|
||||||
struct packed {
|
struct packed {
|
||||||
logic [15:0] d;
|
logic [15:0] d;
|
||||||
logic de;
|
logic de;
|
||||||
|
@ -116,43 +161,83 @@ package i2c_reg_pkg;
|
||||||
} i2c_hw2reg_master_data_reg_t;
|
} i2c_hw2reg_master_data_reg_t;
|
||||||
|
|
||||||
typedef struct packed {
|
typedef struct packed {
|
||||||
|
struct packed {
|
||||||
logic [7:0] d;
|
logic [7:0] d;
|
||||||
} i2c_hw2reg_slave_data_reg_t;
|
logic de;
|
||||||
|
} addr0;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
logic de;
|
||||||
|
} addr1;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
logic de;
|
||||||
|
} addr2;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
logic de;
|
||||||
|
} addr3;
|
||||||
|
} i2c_hw2reg_slave_addr_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
logic de;
|
||||||
|
} wdata0;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
logic de;
|
||||||
|
} wdata1;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
logic de;
|
||||||
|
} wdata2;
|
||||||
|
struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
logic de;
|
||||||
|
} wdata3;
|
||||||
|
} i2c_hw2reg_slave_wdata_reg_t;
|
||||||
|
|
||||||
// Register -> HW type
|
// Register -> HW type
|
||||||
typedef struct packed {
|
typedef struct packed {
|
||||||
i2c_reg2hw_ctrl_reg_t ctrl; // [63:33]
|
i2c_reg2hw_ctrl_reg_t ctrl; // [161:120]
|
||||||
i2c_reg2hw_master_data_reg_t master_data; // [32:9]
|
i2c_reg2hw_master_data_reg_t master_data; // [119:96]
|
||||||
i2c_reg2hw_slave_data_reg_t slave_data; // [8:0]
|
i2c_reg2hw_slave_addr_reg_t slave_addr; // [95:64]
|
||||||
|
i2c_reg2hw_slave_wdata_reg_t slave_wdata; // [63:32]
|
||||||
|
i2c_reg2hw_slave_rdata_reg_t slave_rdata; // [31:0]
|
||||||
} i2c_reg2hw_t;
|
} i2c_reg2hw_t;
|
||||||
|
|
||||||
// HW -> register type
|
// HW -> register type
|
||||||
typedef struct packed {
|
typedef struct packed {
|
||||||
i2c_hw2reg_ctrl_reg_t ctrl; // [65:35]
|
i2c_hw2reg_ctrl_reg_t ctrl; // [140:99]
|
||||||
i2c_hw2reg_master_data_reg_t master_data; // [34:8]
|
i2c_hw2reg_master_data_reg_t master_data; // [98:72]
|
||||||
i2c_hw2reg_slave_data_reg_t slave_data; // [7:0]
|
i2c_hw2reg_slave_addr_reg_t slave_addr; // [71:36]
|
||||||
|
i2c_hw2reg_slave_wdata_reg_t slave_wdata; // [35:0]
|
||||||
} i2c_hw2reg_t;
|
} i2c_hw2reg_t;
|
||||||
|
|
||||||
// Register offsets
|
// Register offsets
|
||||||
parameter logic [BlockAw-1:0] I2C_CTRL_OFFSET = 4'h0;
|
parameter logic [BlockAw-1:0] I2C_CTRL_OFFSET = 5'h0;
|
||||||
parameter logic [BlockAw-1:0] I2C_MASTER_DATA_OFFSET = 4'h4;
|
parameter logic [BlockAw-1:0] I2C_MASTER_DATA_OFFSET = 5'h4;
|
||||||
parameter logic [BlockAw-1:0] I2C_SLAVE_DATA_OFFSET = 4'h8;
|
parameter logic [BlockAw-1:0] I2C_SLAVE_ADDR_OFFSET = 5'h8;
|
||||||
|
parameter logic [BlockAw-1:0] I2C_SLAVE_WDATA_OFFSET = 5'hc;
|
||||||
// Reset values for hwext registers and their fields
|
parameter logic [BlockAw-1:0] I2C_SLAVE_RDATA_OFFSET = 5'h10;
|
||||||
parameter logic [7:0] I2C_SLAVE_DATA_RESVAL = 8'h0;
|
|
||||||
|
|
||||||
// Register index
|
// Register index
|
||||||
typedef enum int {
|
typedef enum int {
|
||||||
I2C_CTRL,
|
I2C_CTRL,
|
||||||
I2C_MASTER_DATA,
|
I2C_MASTER_DATA,
|
||||||
I2C_SLAVE_DATA
|
I2C_SLAVE_ADDR,
|
||||||
|
I2C_SLAVE_WDATA,
|
||||||
|
I2C_SLAVE_RDATA
|
||||||
} i2c_id_e;
|
} i2c_id_e;
|
||||||
|
|
||||||
// Register width information to check illegal writes
|
// Register width information to check illegal writes
|
||||||
parameter logic [3:0] I2C_PERMIT [3] = '{
|
parameter logic [3:0] I2C_PERMIT [5] = '{
|
||||||
4'b1111, // index[0] I2C_CTRL
|
4'b1111, // index[0] I2C_CTRL
|
||||||
4'b0111, // index[1] I2C_MASTER_DATA
|
4'b0111, // index[1] I2C_MASTER_DATA
|
||||||
4'b0001 // index[2] I2C_SLAVE_DATA
|
4'b1111, // index[2] I2C_SLAVE_ADDR
|
||||||
|
4'b1111, // index[3] I2C_SLAVE_WDATA
|
||||||
|
4'b1111 // index[4] I2C_SLAVE_RDATA
|
||||||
};
|
};
|
||||||
|
|
||||||
endpackage
|
endpackage
|
||||||
|
|
|
@ -23,7 +23,7 @@ module i2c_reg_top (
|
||||||
|
|
||||||
import i2c_reg_pkg::* ;
|
import i2c_reg_pkg::* ;
|
||||||
|
|
||||||
localparam int AW = 4;
|
localparam int AW = 5;
|
||||||
localparam int DW = 32;
|
localparam int DW = 32;
|
||||||
localparam int DBW = DW/8; // Byte Width
|
localparam int DBW = DW/8; // Byte Width
|
||||||
|
|
||||||
|
@ -49,8 +49,12 @@ module i2c_reg_top (
|
||||||
logic ctrl_mode_wd;
|
logic ctrl_mode_wd;
|
||||||
logic ctrl_write_qs;
|
logic ctrl_write_qs;
|
||||||
logic ctrl_write_wd;
|
logic ctrl_write_wd;
|
||||||
logic ctrl_ack_qs;
|
|
||||||
logic ctrl_error_qs;
|
logic ctrl_error_qs;
|
||||||
|
logic ctrl_slave_wr_qs;
|
||||||
|
logic ctrl_slave_rdy_qs;
|
||||||
|
logic ctrl_slave_rdy_wd;
|
||||||
|
logic [7:0] ctrl_slave_addr_qs;
|
||||||
|
logic [7:0] ctrl_slave_addr_wd;
|
||||||
logic [15:0] ctrl_clk_div_qs;
|
logic [15:0] ctrl_clk_div_qs;
|
||||||
logic [15:0] ctrl_clk_div_wd;
|
logic [15:0] ctrl_clk_div_wd;
|
||||||
logic master_data_we;
|
logic master_data_we;
|
||||||
|
@ -60,8 +64,17 @@ module i2c_reg_top (
|
||||||
logic [7:0] master_data_regreg_wd;
|
logic [7:0] master_data_regreg_wd;
|
||||||
logic [7:0] master_data_data_qs;
|
logic [7:0] master_data_data_qs;
|
||||||
logic [7:0] master_data_data_wd;
|
logic [7:0] master_data_data_wd;
|
||||||
logic slave_data_re;
|
logic [7:0] slave_addr_addr0_qs;
|
||||||
logic [7:0] slave_data_qs;
|
logic [7:0] slave_addr_addr1_qs;
|
||||||
|
logic [7:0] slave_addr_addr2_qs;
|
||||||
|
logic [7:0] slave_addr_addr3_qs;
|
||||||
|
logic [7:0] slave_wdata_wdata0_qs;
|
||||||
|
logic [7:0] slave_wdata_wdata1_qs;
|
||||||
|
logic [7:0] slave_wdata_wdata2_qs;
|
||||||
|
logic [7:0] slave_wdata_wdata3_qs;
|
||||||
|
logic slave_rdata_we;
|
||||||
|
logic [31:0] slave_rdata_qs;
|
||||||
|
logic [31:0] slave_rdata_wd;
|
||||||
|
|
||||||
// Register instances
|
// Register instances
|
||||||
// R[ctrl]: V(False)
|
// R[ctrl]: V(False)
|
||||||
|
@ -196,33 +209,7 @@ module i2c_reg_top (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// F[ack]: 5:5
|
// F[error]: 5:5
|
||||||
prim_subreg #(
|
|
||||||
.DW (1),
|
|
||||||
.SWACCESS("RO"),
|
|
||||||
.RESVAL (1'h0)
|
|
||||||
) u_ctrl_ack (
|
|
||||||
.clk_i (clk_i),
|
|
||||||
.rst_ni (rst_ni),
|
|
||||||
|
|
||||||
// from register interface
|
|
||||||
.we (1'b0),
|
|
||||||
.wd ('0),
|
|
||||||
|
|
||||||
// from internal hardware
|
|
||||||
.de (hw2reg.ctrl.ack.de),
|
|
||||||
.d (hw2reg.ctrl.ack.d),
|
|
||||||
|
|
||||||
// to internal hardware
|
|
||||||
.qe (reg2hw.ctrl.ack.qe),
|
|
||||||
.q (reg2hw.ctrl.ack.q),
|
|
||||||
|
|
||||||
// to register interface (read)
|
|
||||||
.qs (ctrl_ack_qs)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// F[error]: 6:6
|
|
||||||
prim_subreg #(
|
prim_subreg #(
|
||||||
.DW (1),
|
.DW (1),
|
||||||
.SWACCESS("RO"),
|
.SWACCESS("RO"),
|
||||||
|
@ -248,6 +235,84 @@ module i2c_reg_top (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[slave_wr]: 6:6
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl_slave_wr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl.slave_wr.de),
|
||||||
|
.d (hw2reg.ctrl.slave_wr.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl.slave_wr.qe),
|
||||||
|
.q (reg2hw.ctrl.slave_wr.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl_slave_wr_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[slave_rdy]: 7:7
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl_slave_rdy (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl_we),
|
||||||
|
.wd (ctrl_slave_rdy_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl.slave_rdy.de),
|
||||||
|
.d (hw2reg.ctrl.slave_rdy.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl.slave_rdy.qe),
|
||||||
|
.q (reg2hw.ctrl.slave_rdy.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl_slave_rdy_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[slave_addr]: 15:8
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_ctrl_slave_addr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl_we),
|
||||||
|
.wd (ctrl_slave_addr_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl.slave_addr.de),
|
||||||
|
.d (hw2reg.ctrl.slave_addr.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl.slave_addr.qe),
|
||||||
|
.q (reg2hw.ctrl.slave_addr.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl_slave_addr_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// F[clk_div]: 31:16
|
// F[clk_div]: 31:16
|
||||||
prim_subreg #(
|
prim_subreg #(
|
||||||
.DW (16),
|
.DW (16),
|
||||||
|
@ -354,28 +419,253 @@ module i2c_reg_top (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// R[slave_data]: V(True)
|
// R[slave_addr]: V(False)
|
||||||
|
|
||||||
prim_subreg_ext #(
|
// F[addr0]: 7:0
|
||||||
.DW (8)
|
prim_subreg #(
|
||||||
) u_slave_data (
|
.DW (8),
|
||||||
.re (slave_data_re),
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_slave_addr_addr0 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
.we (1'b0),
|
.we (1'b0),
|
||||||
.wd ('0),
|
.wd ('0),
|
||||||
.d (hw2reg.slave_data.d),
|
|
||||||
.qre (reg2hw.slave_data.re),
|
// from internal hardware
|
||||||
|
.de (hw2reg.slave_addr.addr0.de),
|
||||||
|
.d (hw2reg.slave_addr.addr0.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
.qe (),
|
.qe (),
|
||||||
.q (reg2hw.slave_data.q),
|
.q (reg2hw.slave_addr.addr0.q),
|
||||||
.qs (slave_data_qs)
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_addr_addr0_qs)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
logic [2:0] addr_hit;
|
// F[addr1]: 15:8
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_slave_addr_addr1 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.slave_addr.addr1.de),
|
||||||
|
.d (hw2reg.slave_addr.addr1.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.slave_addr.addr1.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_addr_addr1_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[addr2]: 23:16
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_slave_addr_addr2 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.slave_addr.addr2.de),
|
||||||
|
.d (hw2reg.slave_addr.addr2.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.slave_addr.addr2.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_addr_addr2_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[addr3]: 31:24
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_slave_addr_addr3 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.slave_addr.addr3.de),
|
||||||
|
.d (hw2reg.slave_addr.addr3.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.slave_addr.addr3.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_addr_addr3_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[slave_wdata]: V(False)
|
||||||
|
|
||||||
|
// F[wdata0]: 7:0
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_slave_wdata_wdata0 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.slave_wdata.wdata0.de),
|
||||||
|
.d (hw2reg.slave_wdata.wdata0.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.slave_wdata.wdata0.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_wdata_wdata0_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[wdata1]: 15:8
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_slave_wdata_wdata1 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.slave_wdata.wdata1.de),
|
||||||
|
.d (hw2reg.slave_wdata.wdata1.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.slave_wdata.wdata1.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_wdata_wdata1_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[wdata2]: 23:16
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_slave_wdata_wdata2 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.slave_wdata.wdata2.de),
|
||||||
|
.d (hw2reg.slave_wdata.wdata2.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.slave_wdata.wdata2.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_wdata_wdata2_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[wdata3]: 31:24
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("RO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_slave_wdata_wdata3 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.slave_wdata.wdata3.de),
|
||||||
|
.d (hw2reg.slave_wdata.wdata3.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.slave_wdata.wdata3.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_wdata_wdata3_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[slave_rdata]: V(False)
|
||||||
|
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (32),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (32'h0)
|
||||||
|
) u_slave_rdata (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (slave_rdata_we),
|
||||||
|
.wd (slave_rdata_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (1'b0),
|
||||||
|
.d ('0),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.slave_rdata.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (slave_rdata_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
logic [4:0] addr_hit;
|
||||||
always_comb begin
|
always_comb begin
|
||||||
addr_hit = '0;
|
addr_hit = '0;
|
||||||
addr_hit[0] = (reg_addr == I2C_CTRL_OFFSET);
|
addr_hit[0] = (reg_addr == I2C_CTRL_OFFSET);
|
||||||
addr_hit[1] = (reg_addr == I2C_MASTER_DATA_OFFSET);
|
addr_hit[1] = (reg_addr == I2C_MASTER_DATA_OFFSET);
|
||||||
addr_hit[2] = (reg_addr == I2C_SLAVE_DATA_OFFSET);
|
addr_hit[2] = (reg_addr == I2C_SLAVE_ADDR_OFFSET);
|
||||||
|
addr_hit[3] = (reg_addr == I2C_SLAVE_WDATA_OFFSET);
|
||||||
|
addr_hit[4] = (reg_addr == I2C_SLAVE_RDATA_OFFSET);
|
||||||
end
|
end
|
||||||
|
|
||||||
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
|
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
|
||||||
|
@ -385,7 +675,9 @@ module i2c_reg_top (
|
||||||
wr_err = (reg_we &
|
wr_err = (reg_we &
|
||||||
((addr_hit[0] & (|(I2C_PERMIT[0] & ~reg_be))) |
|
((addr_hit[0] & (|(I2C_PERMIT[0] & ~reg_be))) |
|
||||||
(addr_hit[1] & (|(I2C_PERMIT[1] & ~reg_be))) |
|
(addr_hit[1] & (|(I2C_PERMIT[1] & ~reg_be))) |
|
||||||
(addr_hit[2] & (|(I2C_PERMIT[2] & ~reg_be)))));
|
(addr_hit[2] & (|(I2C_PERMIT[2] & ~reg_be))) |
|
||||||
|
(addr_hit[3] & (|(I2C_PERMIT[3] & ~reg_be))) |
|
||||||
|
(addr_hit[4] & (|(I2C_PERMIT[4] & ~reg_be)))));
|
||||||
end
|
end
|
||||||
|
|
||||||
assign ctrl_we = addr_hit[0] & reg_we & !reg_error;
|
assign ctrl_we = addr_hit[0] & reg_we & !reg_error;
|
||||||
|
@ -400,6 +692,10 @@ module i2c_reg_top (
|
||||||
|
|
||||||
assign ctrl_write_wd = reg_wdata[4];
|
assign ctrl_write_wd = reg_wdata[4];
|
||||||
|
|
||||||
|
assign ctrl_slave_rdy_wd = reg_wdata[7];
|
||||||
|
|
||||||
|
assign ctrl_slave_addr_wd = reg_wdata[15:8];
|
||||||
|
|
||||||
assign ctrl_clk_div_wd = reg_wdata[31:16];
|
assign ctrl_clk_div_wd = reg_wdata[31:16];
|
||||||
assign master_data_we = addr_hit[1] & reg_we & !reg_error;
|
assign master_data_we = addr_hit[1] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
@ -408,7 +704,9 @@ module i2c_reg_top (
|
||||||
assign master_data_regreg_wd = reg_wdata[15:8];
|
assign master_data_regreg_wd = reg_wdata[15:8];
|
||||||
|
|
||||||
assign master_data_data_wd = reg_wdata[23:16];
|
assign master_data_data_wd = reg_wdata[23:16];
|
||||||
assign slave_data_re = addr_hit[2] & reg_re & !reg_error;
|
assign slave_rdata_we = addr_hit[4] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
assign slave_rdata_wd = reg_wdata[31:0];
|
||||||
|
|
||||||
// Read data return
|
// Read data return
|
||||||
always_comb begin
|
always_comb begin
|
||||||
|
@ -420,8 +718,10 @@ module i2c_reg_top (
|
||||||
reg_rdata_next[2] = ctrl_int_pending_qs;
|
reg_rdata_next[2] = ctrl_int_pending_qs;
|
||||||
reg_rdata_next[3] = ctrl_mode_qs;
|
reg_rdata_next[3] = ctrl_mode_qs;
|
||||||
reg_rdata_next[4] = ctrl_write_qs;
|
reg_rdata_next[4] = ctrl_write_qs;
|
||||||
reg_rdata_next[5] = ctrl_ack_qs;
|
reg_rdata_next[5] = ctrl_error_qs;
|
||||||
reg_rdata_next[6] = ctrl_error_qs;
|
reg_rdata_next[6] = ctrl_slave_wr_qs;
|
||||||
|
reg_rdata_next[7] = ctrl_slave_rdy_qs;
|
||||||
|
reg_rdata_next[15:8] = ctrl_slave_addr_qs;
|
||||||
reg_rdata_next[31:16] = ctrl_clk_div_qs;
|
reg_rdata_next[31:16] = ctrl_clk_div_qs;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -432,7 +732,21 @@ module i2c_reg_top (
|
||||||
end
|
end
|
||||||
|
|
||||||
addr_hit[2]: begin
|
addr_hit[2]: begin
|
||||||
reg_rdata_next[7:0] = slave_data_qs;
|
reg_rdata_next[7:0] = slave_addr_addr0_qs;
|
||||||
|
reg_rdata_next[15:8] = slave_addr_addr1_qs;
|
||||||
|
reg_rdata_next[23:16] = slave_addr_addr2_qs;
|
||||||
|
reg_rdata_next[31:24] = slave_addr_addr3_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[3]: begin
|
||||||
|
reg_rdata_next[7:0] = slave_wdata_wdata0_qs;
|
||||||
|
reg_rdata_next[15:8] = slave_wdata_wdata1_qs;
|
||||||
|
reg_rdata_next[23:16] = slave_wdata_wdata2_qs;
|
||||||
|
reg_rdata_next[31:24] = slave_wdata_wdata3_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[4]: begin
|
||||||
|
reg_rdata_next[31:0] = slave_rdata_qs;
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
|
|
|
@ -0,0 +1,270 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module i2c_slave (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
input logic enable_i,
|
||||||
|
input logic [7:0] slave_addr_i,
|
||||||
|
input logic [7:0] data_i,
|
||||||
|
output logic [7:0] addr_o,
|
||||||
|
output logic read_o,
|
||||||
|
output logic valid_o,
|
||||||
|
output logic [7:0] data_o,
|
||||||
|
|
||||||
|
input logic scl_i,
|
||||||
|
output logic scl_o,
|
||||||
|
output logic scl_oe_o,
|
||||||
|
input logic sda_i,
|
||||||
|
output logic sda_o,
|
||||||
|
output logic sda_oe_o
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam S_IDLE = 6'b000001;
|
||||||
|
localparam S_START = 6'b000010;
|
||||||
|
localparam S_ADDR = 6'b000100;
|
||||||
|
localparam S_REG = 6'b001000;
|
||||||
|
localparam S_DATA = 6'b010000;
|
||||||
|
localparam S_STOP = 6'b100000;
|
||||||
|
|
||||||
|
logic scl_raise_edge, scl_fall_edge;
|
||||||
|
logic sda_raise_edge, sda_fall_edge;
|
||||||
|
logic sda, scl;
|
||||||
|
|
||||||
|
logic [5:0] state_d, state_q;
|
||||||
|
logic sda_oe_d, sda_oe_q;
|
||||||
|
logic scl_oe_d, scl_oe_q;
|
||||||
|
logic sda_d, sda_q;
|
||||||
|
logic scl_d, scl_q;
|
||||||
|
logic [7:0] data_d, data_q;
|
||||||
|
logic [7:0] addr_d, addr_q;
|
||||||
|
logic read_d, read_q;
|
||||||
|
logic send_ack_d, send_ack_q;
|
||||||
|
logic [3:0] scl_raise_edge_cnt_d, scl_raise_edge_cnt_q;
|
||||||
|
logic valid_d, valid_q;
|
||||||
|
logic op_read_d, op_read_q;
|
||||||
|
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
state_d = state_q;
|
||||||
|
sda_oe_d = sda_oe_q;
|
||||||
|
sda_d = sda_q;
|
||||||
|
scl_oe_d = scl_oe_q;
|
||||||
|
scl_d = scl_q;
|
||||||
|
data_d = data_q;
|
||||||
|
addr_d = addr_q;
|
||||||
|
read_d = read_q;
|
||||||
|
send_ack_d = send_ack_q;
|
||||||
|
scl_raise_edge_cnt_d = scl_raise_edge_cnt_q;
|
||||||
|
valid_d = valid_q;
|
||||||
|
op_read_d = op_read_q;
|
||||||
|
|
||||||
|
if (!enable_i) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
sda_oe_d = 1'b0;
|
||||||
|
sda_d = 1'b0;
|
||||||
|
scl_oe_d = 1'b0;
|
||||||
|
scl_d = 1'b0;
|
||||||
|
end else begin
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
sda_oe_d = 1'b0;
|
||||||
|
sda_d = 1'b0;
|
||||||
|
valid_d = 1'b0;
|
||||||
|
read_d = 1'b0;
|
||||||
|
// START信号
|
||||||
|
if (scl_i && sda_fall_edge) begin
|
||||||
|
state_d = S_ADDR;
|
||||||
|
send_ack_d = 1'b0;
|
||||||
|
scl_raise_edge_cnt_d = '0;
|
||||||
|
op_read_d = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_ADDR: begin
|
||||||
|
// SCL上升沿采数据
|
||||||
|
if (scl_raise_edge) begin
|
||||||
|
scl_raise_edge_cnt_d = scl_raise_edge_cnt_q + 1'b1;
|
||||||
|
if (scl_raise_edge_cnt_q < 4'd8) begin
|
||||||
|
data_d = {data_q[6:0], sda};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 下降沿发ACK信号
|
||||||
|
if ((scl_raise_edge_cnt_q == 4'd8) && scl_fall_edge) begin
|
||||||
|
// 地址对得上则回ACK信号
|
||||||
|
if (slave_addr_i[7:1] == data_q[7:1]) begin
|
||||||
|
sda_oe_d = 1'b1;
|
||||||
|
sda_d = 1'b0;
|
||||||
|
if (data_q[0]) begin
|
||||||
|
read_d = 1'b1;
|
||||||
|
end
|
||||||
|
// 否则回到S_IDLE状态
|
||||||
|
end else begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 释放SDA
|
||||||
|
if ((scl_raise_edge_cnt_q == 4'd9) && scl_fall_edge) begin
|
||||||
|
sda_oe_d = 1'b0;
|
||||||
|
scl_raise_edge_cnt_d = '0;
|
||||||
|
// 读
|
||||||
|
if (data_q[0]) begin
|
||||||
|
state_d = S_DATA;
|
||||||
|
op_read_d = 1'b1;
|
||||||
|
sda_oe_d = 1'b1;
|
||||||
|
data_d = {data_i[6:0], 1'b1};
|
||||||
|
sda_d = data_i[7];
|
||||||
|
// 写
|
||||||
|
end else begin
|
||||||
|
state_d = S_REG;
|
||||||
|
op_read_d = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 收到STOP信号
|
||||||
|
if (scl_i && sda_raise_edge) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_REG: begin
|
||||||
|
// SCL上升沿采数据
|
||||||
|
if (scl_raise_edge) begin
|
||||||
|
scl_raise_edge_cnt_d = scl_raise_edge_cnt_q + 1'b1;
|
||||||
|
if (scl_raise_edge_cnt_q < 4'd8) begin
|
||||||
|
data_d = {data_q[6:0], sda};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 下降沿发ACK信号
|
||||||
|
if ((scl_raise_edge_cnt_q == 4'd8) && scl_fall_edge) begin
|
||||||
|
sda_oe_d = 1'b1;
|
||||||
|
sda_d = 1'b0;
|
||||||
|
addr_d = data_q;
|
||||||
|
end
|
||||||
|
// 释放SDA
|
||||||
|
if ((scl_raise_edge_cnt_q == 4'd9) && scl_fall_edge) begin
|
||||||
|
sda_oe_d = 1'b0;
|
||||||
|
scl_raise_edge_cnt_d = '0;
|
||||||
|
state_d = S_DATA;
|
||||||
|
op_read_d = 1'b0;
|
||||||
|
end
|
||||||
|
// 收到STOP信号
|
||||||
|
if (scl_i && sda_raise_edge) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_DATA: begin
|
||||||
|
if (scl_raise_edge) begin
|
||||||
|
scl_raise_edge_cnt_d = scl_raise_edge_cnt_q + 1'b1;
|
||||||
|
if ((!op_read_q) && (scl_raise_edge_cnt_q < 4'd8)) begin
|
||||||
|
data_d = {data_q[6:0], sda};
|
||||||
|
end
|
||||||
|
end else if (scl_fall_edge) begin
|
||||||
|
if (op_read_q && (scl_raise_edge_cnt_q < 4'd7)) begin
|
||||||
|
sda_oe_d = 1'b1;
|
||||||
|
data_d = {data_q[6:0], 1'b1};
|
||||||
|
sda_d = data_q[7];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 下降沿发ACK信号
|
||||||
|
if ((scl_raise_edge_cnt_q == 4'd8) && scl_fall_edge) begin
|
||||||
|
sda_oe_d = 1'b1;
|
||||||
|
// 回NACK
|
||||||
|
if (op_read_q) begin
|
||||||
|
sda_d = 1'b1;
|
||||||
|
// 回ACK
|
||||||
|
end else begin
|
||||||
|
sda_d = 1'b0;
|
||||||
|
end
|
||||||
|
valid_d = 1'b1;
|
||||||
|
end
|
||||||
|
// 释放SDA
|
||||||
|
if ((scl_raise_edge_cnt_q == 4'd9) && scl_fall_edge) begin
|
||||||
|
sda_oe_d = 1'b0;
|
||||||
|
op_read_d = 1'b0;
|
||||||
|
end
|
||||||
|
// 收到STOP信号
|
||||||
|
if (scl_i && sda_raise_edge) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
sda_oe_q <= 1'b0;
|
||||||
|
sda_q <= 1'b0;
|
||||||
|
scl_oe_q <= 1'b0;
|
||||||
|
scl_q <= 1'b0;
|
||||||
|
data_q <= '0;
|
||||||
|
addr_q <= '0;
|
||||||
|
read_q <= 1'b0;
|
||||||
|
send_ack_q <= 1'b0;
|
||||||
|
scl_raise_edge_cnt_q <= '0;
|
||||||
|
valid_q <= 1'b0;
|
||||||
|
op_read_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
sda_oe_q <= sda_oe_d;
|
||||||
|
sda_q <= sda_d;
|
||||||
|
scl_oe_q <= scl_oe_d;
|
||||||
|
scl_q <= scl_d;
|
||||||
|
data_q <= data_d;
|
||||||
|
addr_q <= addr_d;
|
||||||
|
read_q <= read_d;
|
||||||
|
send_ack_q <= send_ack_d;
|
||||||
|
scl_raise_edge_cnt_q <= scl_raise_edge_cnt_d;
|
||||||
|
valid_q <= valid_d;
|
||||||
|
op_read_q <= op_read_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign scl_oe_o = scl_oe_q;
|
||||||
|
assign scl_o = scl_q;
|
||||||
|
assign sda_oe_o = sda_oe_q;
|
||||||
|
assign sda_o = sda_q;
|
||||||
|
assign data_o = data_q;
|
||||||
|
assign addr_o = addr_q;
|
||||||
|
assign read_o = read_q;
|
||||||
|
assign valid_o = valid_q;
|
||||||
|
|
||||||
|
// SCL信号沿检测
|
||||||
|
edge_detect scl_edge_detect (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.sig_i (scl_i),
|
||||||
|
.sig_o (scl),
|
||||||
|
.re_o (scl_raise_edge),
|
||||||
|
.fe_o (scl_fall_edge)
|
||||||
|
);
|
||||||
|
|
||||||
|
// SDA信号沿检测
|
||||||
|
edge_detect sda_edge_detect (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.sig_i (sda_i),
|
||||||
|
.sig_o (sda),
|
||||||
|
.re_o (sda_raise_edge),
|
||||||
|
.fe_o (sda_fall_edge)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
Loading…
Reference in New Issue