rtl:perips: add i2c master
Signed-off-by: liangkangnan <liangkangnan@163.com>pull/4/head
parent
6143d9ee6a
commit
2afcba47ea
|
@ -53,6 +53,11 @@
|
|||
../rtl/perips/rvic/rvic_reg_top.sv
|
||||
../rtl/perips/rvic/rvic_core.sv
|
||||
../rtl/perips/rvic/rvic_top.sv
|
||||
../rtl/perips/i2c/i2c_reg_pkg.sv
|
||||
../rtl/perips/i2c/i2c_reg_top.sv
|
||||
../rtl/perips/i2c/i2c_core.sv
|
||||
../rtl/perips/i2c/i2c_top.sv
|
||||
../rtl/perips/i2c/i2c_master.sv
|
||||
|
||||
../rtl/sys_bus/obi_interconnect.sv
|
||||
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
// UART0
|
||||
`define UART0_ADDR_MASK ~32'hffff
|
||||
`define UART0_ADDR_BASE 32'h50000000
|
||||
// I2C0
|
||||
`define I2C0_ADDR_MASK ~32'hffff
|
||||
`define I2C0_ADDR_BASE 32'h60000000
|
||||
// Interrupt controller
|
||||
`define RVIC_ADDR_MASK ~32'hffff
|
||||
`define RVIC_ADDR_BASE 32'hD0000000
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{ name: "i2c",
|
||||
clocking: [{clock: "clk_i", reset: "rst_ni"}],
|
||||
bus_interfaces: [
|
||||
{ protocol: "tlul", direction: "device" }
|
||||
],
|
||||
regwidth: "32",
|
||||
registers: [
|
||||
{ name: "CTRL",
|
||||
desc: "I2C control register",
|
||||
swaccess: "rw",
|
||||
hwaccess: "hrw",
|
||||
hwqe: "true",
|
||||
fields: [
|
||||
{ bits: "0",
|
||||
name: "START",
|
||||
desc: "I2C start",
|
||||
}
|
||||
{ bits: "1",
|
||||
name: "INT_EN",
|
||||
desc: "I2C interrupt enable",
|
||||
}
|
||||
{ bits: "2",
|
||||
name: "INT_PENDING",
|
||||
swaccess: "rw1c",
|
||||
desc: "I2C interrupt pending",
|
||||
}
|
||||
{ bits: "3",
|
||||
name: "MODE",
|
||||
desc: "I2C mode, 0: master, 1: slave",
|
||||
}
|
||||
{ bits: "4",
|
||||
name: "WRITE",
|
||||
desc: "0: write, 1: read",
|
||||
}
|
||||
{ bits: "5",
|
||||
name: "ACK",
|
||||
swaccess: "ro",
|
||||
desc: "0: ack, 1: nack",
|
||||
}
|
||||
{ bits: "6",
|
||||
name: "ERROR",
|
||||
swaccess: "ro",
|
||||
desc: "0: no error, 1: error",
|
||||
}
|
||||
{ bits: "31:16",
|
||||
name: "CLK_DIV",
|
||||
desc: "I2C clock divider count",
|
||||
}
|
||||
]
|
||||
}
|
||||
{ name: "MASTER_DATA",
|
||||
desc: "I2C master transfer data register",
|
||||
swaccess: "rw",
|
||||
hwaccess: "hrw",
|
||||
fields: [
|
||||
{ bits: "7:0",
|
||||
name: "ADDRESS",
|
||||
desc: "I2C slave address",
|
||||
}
|
||||
{ bits: "15:8",
|
||||
name: "REGREG",
|
||||
desc: "I2C write or read reg",
|
||||
}
|
||||
{ bits: "23:16",
|
||||
name: "DATA",
|
||||
desc: "I2C write or read data",
|
||||
}
|
||||
]
|
||||
}
|
||||
{ name: "SLAVE_DATA",
|
||||
desc: "I2C slave received data register",
|
||||
swaccess: "ro",
|
||||
hwaccess: "hrw",
|
||||
hwext: "true",
|
||||
hwre: "true",
|
||||
fields: [
|
||||
{ bits: "7:0",
|
||||
desc: "I2C slave received data(fifo)",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
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_core (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
output logic scl_o,
|
||||
output logic scl_oe_o,
|
||||
input logic scl_i,
|
||||
output logic sda_o,
|
||||
output logic sda_oe_o,
|
||||
input logic sda_i,
|
||||
|
||||
output logic irq_o,
|
||||
|
||||
input logic reg_we_i,
|
||||
input logic reg_re_i,
|
||||
input logic [31:0] reg_wdata_i,
|
||||
input logic [ 3:0] reg_be_i,
|
||||
input logic [31:0] reg_addr_i,
|
||||
output logic [31:0] reg_rdata_o
|
||||
);
|
||||
|
||||
import i2c_reg_pkg::*;
|
||||
|
||||
i2c_reg_pkg::i2c_reg2hw_t reg2hw;
|
||||
i2c_reg_pkg::i2c_hw2reg_t hw2reg;
|
||||
|
||||
logic master_mode;
|
||||
logic slave_mode;
|
||||
logic op_write;
|
||||
logic op_read;
|
||||
logic start;
|
||||
logic [15:0] clk_div;
|
||||
logic int_enable;
|
||||
logic [7:0] master_address;
|
||||
logic [7:0] master_register;
|
||||
logic [7:0] master_data;
|
||||
logic master_ready, master_ready_q;
|
||||
logic master_start;
|
||||
logic master_error;
|
||||
logic [7:0] master_read_data;
|
||||
|
||||
assign master_mode = ~reg2hw.ctrl.mode.q;
|
||||
assign slave_mode = reg2hw.ctrl.mode.q;
|
||||
assign op_write = ~reg2hw.ctrl.write.q;
|
||||
assign op_read = reg2hw.ctrl.write.q;
|
||||
assign start = reg2hw.ctrl.start.q;
|
||||
assign clk_div = reg2hw.ctrl.clk_div.q;
|
||||
assign int_enable = reg2hw.ctrl.int_en.q;
|
||||
|
||||
assign master_address = reg2hw.master_data.address.q;
|
||||
assign master_register = reg2hw.master_data.regreg.q;
|
||||
assign master_data = reg2hw.master_data.data.q;
|
||||
|
||||
// 软件写1启动master传输
|
||||
assign master_start = reg2hw.ctrl.start.qe && reg2hw.ctrl.start.q && master_ready;
|
||||
|
||||
// master传输完成后,硬件清start位
|
||||
assign hw2reg.ctrl.start.d = 1'b0;
|
||||
// master传输完成上升沿脉冲
|
||||
assign hw2reg.ctrl.start.de = (~master_ready_q) && master_ready;
|
||||
|
||||
// 传输完成产生中断pending
|
||||
assign hw2reg.ctrl.int_pending.d = 1'b1;
|
||||
assign hw2reg.ctrl.int_pending.de = int_enable && (~master_ready_q) && master_ready;
|
||||
|
||||
// 传输完成并且是读操作,则更新master data
|
||||
assign hw2reg.master_data.data.d = master_read_data;
|
||||
assign hw2reg.master_data.data.de = op_read && (~master_ready_q) && master_ready;
|
||||
|
||||
// 传输完成更新error
|
||||
assign hw2reg.ctrl.error.d = master_error;
|
||||
assign hw2reg.ctrl.error.de = (~master_ready_q) && master_ready;
|
||||
|
||||
assign irq_o = reg2hw.ctrl.int_pending.q;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
master_ready_q <= 1'b1;
|
||||
end else begin
|
||||
master_ready_q <= master_ready;
|
||||
end
|
||||
end
|
||||
|
||||
i2c_master u_i2c_master (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.enable_i (master_mode),
|
||||
.div_ratio_i (clk_div),
|
||||
.read_i (op_read),
|
||||
.slave_addr_i (master_address),
|
||||
.slave_reg_i (master_register),
|
||||
.slave_data_i (master_data),
|
||||
.start_i (master_start),
|
||||
.ready_o (master_ready),
|
||||
.error_o (master_error),
|
||||
.data_o (master_read_data),
|
||||
.scl_i (scl_i),
|
||||
.scl_o (scl_o),
|
||||
.scl_oe_o (scl_oe_o),
|
||||
.sda_i (sda_i),
|
||||
.sda_o (sda_o),
|
||||
.sda_oe_o (sda_oe_o)
|
||||
);
|
||||
|
||||
i2c_reg_top u_i2c_reg_top (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.reg2hw (reg2hw),
|
||||
.hw2reg (hw2reg),
|
||||
.reg_we (reg_we_i),
|
||||
.reg_re (reg_re_i),
|
||||
.reg_wdata (reg_wdata_i),
|
||||
.reg_be (reg_be_i),
|
||||
.reg_addr (reg_addr_i),
|
||||
.reg_rdata (reg_rdata_o)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
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_master (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
input logic enable_i,
|
||||
input logic [15:0] div_ratio_i,
|
||||
input logic read_i,
|
||||
input logic [7:0] slave_addr_i,
|
||||
input logic [7:0] slave_reg_i,
|
||||
input logic [7:0] slave_data_i,
|
||||
input logic start_i,
|
||||
output logic ready_o,
|
||||
output logic error_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 tick;
|
||||
|
||||
logic error_d, error_q;
|
||||
logic [7:0] data_d, data_q;
|
||||
logic [4:0] edge_cnt_d, edge_cnt_q;
|
||||
logic [7:0] shift_reg_d, shift_reg_q;
|
||||
logic [5:0] state_d, state_q;
|
||||
logic sda_d, sda_q;
|
||||
logic scl_d, scl_q;
|
||||
logic sda_oe_d, sda_oe_q;
|
||||
logic scl_oe_d, scl_oe_q;
|
||||
logic op_read_d, op_read_q;
|
||||
|
||||
|
||||
always_comb begin
|
||||
state_d = state_q;
|
||||
shift_reg_d = shift_reg_q;
|
||||
scl_d = scl_q;
|
||||
sda_oe_d = sda_oe_q;
|
||||
scl_oe_d = scl_oe_q;
|
||||
sda_d = sda_q;
|
||||
edge_cnt_d = edge_cnt_q;
|
||||
data_d = data_q;
|
||||
error_d = error_q;
|
||||
op_read_d = op_read_q;
|
||||
|
||||
if (!enable_i) begin
|
||||
sda_d = 1'b0;
|
||||
sda_oe_d = 1'b0;
|
||||
scl_d = 1'b0;
|
||||
scl_oe_d = 1'b0;
|
||||
state_d = S_IDLE;
|
||||
end else begin
|
||||
case (state_q)
|
||||
S_IDLE: begin
|
||||
sda_d = 1'b1;
|
||||
sda_oe_d = 1'b1;
|
||||
scl_d = 1'b1;
|
||||
scl_oe_d = 1'b1;
|
||||
if (start_i) begin
|
||||
state_d = S_START;
|
||||
error_d = 1'b0;
|
||||
data_d = '0;
|
||||
op_read_d = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
S_START: begin
|
||||
if (tick) begin
|
||||
sda_d = 1'b0;
|
||||
edge_cnt_d = '0;
|
||||
state_d = S_ADDR;
|
||||
shift_reg_d = {slave_addr_i[7:1], op_read_q};
|
||||
end
|
||||
end
|
||||
|
||||
S_ADDR: begin
|
||||
if (tick) begin
|
||||
scl_d = ~scl_q;
|
||||
edge_cnt_d = edge_cnt_q + 1'b1;
|
||||
// 下降沿释放SDA,准备接收ACK
|
||||
if (edge_cnt_q == 5'd16) begin
|
||||
sda_oe_d = 1'b0;
|
||||
// 上升沿接收ACK
|
||||
end else if (edge_cnt_q == 5'd17) begin
|
||||
// NACK
|
||||
if (sda_i) begin
|
||||
error_d = 1'b1;
|
||||
// ACK
|
||||
end else begin
|
||||
if (op_read_q) begin
|
||||
state_d = S_DATA;
|
||||
end else begin
|
||||
state_d = S_REG;
|
||||
shift_reg_d = slave_reg_i;
|
||||
end
|
||||
edge_cnt_d = '0;
|
||||
end
|
||||
// 最后一个下降沿
|
||||
end else if (edge_cnt_q == 5'd18) begin
|
||||
sda_d = 1'b0;
|
||||
sda_oe_d = 1'b1;
|
||||
// 最后一个上升沿
|
||||
end else if (edge_cnt_q == 5'd19) begin
|
||||
state_d = S_STOP;
|
||||
end else begin
|
||||
// 发数据
|
||||
if (scl_q) begin
|
||||
// 左移一位(MSB first)
|
||||
shift_reg_d = {shift_reg_q[6:0], 1'b1};
|
||||
sda_d = shift_reg_q[7];
|
||||
sda_oe_d = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
S_REG: begin
|
||||
if (tick) begin
|
||||
scl_d = ~scl_q;
|
||||
edge_cnt_d = edge_cnt_q + 1'b1;
|
||||
// 下降沿释放SDA,准备接收ACK
|
||||
if (edge_cnt_q == 5'd16) begin
|
||||
sda_oe_d = 1'b0;
|
||||
// 上升沿接收ACK
|
||||
end else if (edge_cnt_q == 5'd17) begin
|
||||
// NACK
|
||||
if (sda_i) begin
|
||||
error_d = 1'b1;
|
||||
// ACK
|
||||
end else begin
|
||||
// 写操作,转去S_DATA状态
|
||||
if (!read_i) begin
|
||||
state_d = S_DATA;
|
||||
shift_reg_d = slave_data_i;
|
||||
edge_cnt_d = '0;
|
||||
// 读操作,发送STOP信号
|
||||
end else begin
|
||||
op_read_d = 1'b1;
|
||||
end
|
||||
end
|
||||
// 最后一个下降沿
|
||||
end else if (edge_cnt_q == 5'd18) begin
|
||||
sda_d = 1'b0;
|
||||
sda_oe_d = 1'b1;
|
||||
// 最后一个上升沿
|
||||
end else if (edge_cnt_q == 5'd19) begin
|
||||
state_d = S_STOP;
|
||||
end else begin
|
||||
// 发数据
|
||||
if (scl_q) begin
|
||||
// 左移一位(MSB first)
|
||||
shift_reg_d = {shift_reg_q[6:0], 1'b1};
|
||||
sda_d = shift_reg_q[7];
|
||||
sda_oe_d = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
S_DATA: begin
|
||||
if (tick) begin
|
||||
scl_d = ~scl_q;
|
||||
edge_cnt_d = edge_cnt_q + 1'b1;
|
||||
// 下降沿释放SDA,准备接收ACK
|
||||
if (edge_cnt_q == 5'd16) begin
|
||||
sda_oe_d = 1'b0;
|
||||
// 上升沿接收ACK
|
||||
end else if (edge_cnt_q == 5'd17) begin
|
||||
// NACK
|
||||
if (sda_i ^ op_read_q) begin
|
||||
error_d = 1'b1;
|
||||
// ACK
|
||||
end else begin
|
||||
error_d = 1'b0;
|
||||
end
|
||||
op_read_d = 1'b0;
|
||||
// 最后一个下降沿
|
||||
end else if (edge_cnt_q == 5'd18) begin
|
||||
sda_d = 1'b0;
|
||||
sda_oe_d = 1'b1;
|
||||
// 最后一个上升沿
|
||||
end else if (edge_cnt_q == 5'd19) begin
|
||||
state_d = S_STOP;
|
||||
end else begin
|
||||
// 读数据
|
||||
if (op_read_q && (~scl_q)) begin
|
||||
data_d = {data_q[6:0], sda_i};
|
||||
// 发数据
|
||||
end else if ((~op_read_q) && scl_q) begin
|
||||
// 左移一位(MSB first)
|
||||
shift_reg_d = {shift_reg_q[6:0], 1'b1};
|
||||
sda_d = shift_reg_q[7];
|
||||
sda_oe_d = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
S_STOP: begin
|
||||
if (tick) begin
|
||||
sda_d = 1'b1;
|
||||
if (op_read_q) begin
|
||||
state_d = S_START;
|
||||
end else begin
|
||||
state_d = S_IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
default: ;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign scl_o = scl_q;
|
||||
assign scl_oe_o = scl_oe_q;
|
||||
assign sda_o = sda_q;
|
||||
assign sda_oe_o = sda_oe_q;
|
||||
assign data_o = data_q;
|
||||
assign ready_o = (state_q == S_IDLE);
|
||||
assign error_o = error_q;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
state_q <= S_IDLE;
|
||||
shift_reg_q <= '0;
|
||||
scl_q <= 1'b0;
|
||||
sda_q <= 1'b0;
|
||||
sda_oe_q <= 1'b0;
|
||||
scl_oe_q <= 1'b0;
|
||||
edge_cnt_q <= '0;
|
||||
data_q <= '0;
|
||||
error_q <= 1'b0;
|
||||
op_read_q <= 1'b0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
shift_reg_q <= shift_reg_d;
|
||||
scl_q <= scl_d;
|
||||
sda_q <= sda_d;
|
||||
sda_oe_q <= sda_oe_d;
|
||||
scl_oe_q <= scl_oe_d;
|
||||
edge_cnt_q <= edge_cnt_d;
|
||||
data_q <= data_d;
|
||||
error_q <= error_d;
|
||||
op_read_q <= op_read_d;
|
||||
end
|
||||
end
|
||||
|
||||
logic [15:0] ratio = {1'b0, div_ratio_i[15:1]};
|
||||
|
||||
clk_div #(
|
||||
.RATIO_WIDTH(16)
|
||||
) u_clk_div (
|
||||
.clk_i(clk_i),
|
||||
.rst_ni(rst_ni || (~((state_q == S_IDLE) && start_i))),
|
||||
.en_i(state_q != S_IDLE),
|
||||
.ratio_i(ratio),
|
||||
.clk_o(tick)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Register Package auto-generated by `reggen` containing data structure
|
||||
|
||||
package i2c_reg_pkg;
|
||||
|
||||
// Address widths within the block
|
||||
parameter int BlockAw = 4;
|
||||
|
||||
////////////////////////////
|
||||
// Typedefs for registers //
|
||||
////////////////////////////
|
||||
|
||||
typedef struct packed {
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} start;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} int_en;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} int_pending;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} mode;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} write;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} ack;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} error;
|
||||
struct packed {
|
||||
logic [15:0] q;
|
||||
logic qe;
|
||||
} clk_div;
|
||||
} i2c_reg2hw_ctrl_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
struct packed {
|
||||
logic [7:0] q;
|
||||
} address;
|
||||
struct packed {
|
||||
logic [7:0] q;
|
||||
} regreg;
|
||||
struct packed {
|
||||
logic [7:0] q;
|
||||
} data;
|
||||
} i2c_reg2hw_master_data_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [7:0] q;
|
||||
logic re;
|
||||
} i2c_reg2hw_slave_data_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
struct packed {
|
||||
logic d;
|
||||
logic de;
|
||||
} start;
|
||||
struct packed {
|
||||
logic d;
|
||||
logic de;
|
||||
} int_en;
|
||||
struct packed {
|
||||
logic d;
|
||||
logic de;
|
||||
} int_pending;
|
||||
struct packed {
|
||||
logic d;
|
||||
logic de;
|
||||
} mode;
|
||||
struct packed {
|
||||
logic d;
|
||||
logic de;
|
||||
} write;
|
||||
struct packed {
|
||||
logic d;
|
||||
logic de;
|
||||
} ack;
|
||||
struct packed {
|
||||
logic d;
|
||||
logic de;
|
||||
} error;
|
||||
struct packed {
|
||||
logic [15:0] d;
|
||||
logic de;
|
||||
} clk_div;
|
||||
} i2c_hw2reg_ctrl_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
struct packed {
|
||||
logic [7:0] d;
|
||||
logic de;
|
||||
} address;
|
||||
struct packed {
|
||||
logic [7:0] d;
|
||||
logic de;
|
||||
} regreg;
|
||||
struct packed {
|
||||
logic [7:0] d;
|
||||
logic de;
|
||||
} data;
|
||||
} i2c_hw2reg_master_data_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [7:0] d;
|
||||
} i2c_hw2reg_slave_data_reg_t;
|
||||
|
||||
// Register -> HW type
|
||||
typedef struct packed {
|
||||
i2c_reg2hw_ctrl_reg_t ctrl; // [63:33]
|
||||
i2c_reg2hw_master_data_reg_t master_data; // [32:9]
|
||||
i2c_reg2hw_slave_data_reg_t slave_data; // [8:0]
|
||||
} i2c_reg2hw_t;
|
||||
|
||||
// HW -> register type
|
||||
typedef struct packed {
|
||||
i2c_hw2reg_ctrl_reg_t ctrl; // [65:35]
|
||||
i2c_hw2reg_master_data_reg_t master_data; // [34:8]
|
||||
i2c_hw2reg_slave_data_reg_t slave_data; // [7:0]
|
||||
} i2c_hw2reg_t;
|
||||
|
||||
// Register offsets
|
||||
parameter logic [BlockAw-1:0] I2C_CTRL_OFFSET = 4'h0;
|
||||
parameter logic [BlockAw-1:0] I2C_MASTER_DATA_OFFSET = 4'h4;
|
||||
parameter logic [BlockAw-1:0] I2C_SLAVE_DATA_OFFSET = 4'h8;
|
||||
|
||||
// Reset values for hwext registers and their fields
|
||||
parameter logic [7:0] I2C_SLAVE_DATA_RESVAL = 8'h0;
|
||||
|
||||
// Register index
|
||||
typedef enum int {
|
||||
I2C_CTRL,
|
||||
I2C_MASTER_DATA,
|
||||
I2C_SLAVE_DATA
|
||||
} i2c_id_e;
|
||||
|
||||
// Register width information to check illegal writes
|
||||
parameter logic [3:0] I2C_PERMIT [3] = '{
|
||||
4'b1111, // index[0] I2C_CTRL
|
||||
4'b0111, // index[1] I2C_MASTER_DATA
|
||||
4'b0001 // index[2] I2C_SLAVE_DATA
|
||||
};
|
||||
|
||||
endpackage
|
||||
|
|
@ -0,0 +1,453 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Register Top module auto-generated by `reggen`
|
||||
|
||||
|
||||
module i2c_reg_top (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
// To HW
|
||||
output i2c_reg_pkg::i2c_reg2hw_t reg2hw, // Write
|
||||
input i2c_reg_pkg::i2c_hw2reg_t hw2reg, // Read
|
||||
|
||||
input logic reg_we,
|
||||
input logic reg_re,
|
||||
input logic [31:0] reg_wdata,
|
||||
input logic [ 3:0] reg_be,
|
||||
input logic [31:0] reg_addr,
|
||||
output logic [31:0] reg_rdata
|
||||
);
|
||||
|
||||
import i2c_reg_pkg::* ;
|
||||
|
||||
localparam int AW = 4;
|
||||
localparam int DW = 32;
|
||||
localparam int DBW = DW/8; // Byte Width
|
||||
|
||||
logic reg_error;
|
||||
logic addrmiss, wr_err;
|
||||
|
||||
logic [DW-1:0] reg_rdata_next;
|
||||
|
||||
assign reg_rdata = reg_rdata_next;
|
||||
assign reg_error = wr_err;
|
||||
|
||||
// Define SW related signals
|
||||
// Format: <reg>_<field>_{wd|we|qs}
|
||||
// or <reg>_{wd|we|qs} if field == 1 or 0
|
||||
logic ctrl_we;
|
||||
logic ctrl_start_qs;
|
||||
logic ctrl_start_wd;
|
||||
logic ctrl_int_en_qs;
|
||||
logic ctrl_int_en_wd;
|
||||
logic ctrl_int_pending_qs;
|
||||
logic ctrl_int_pending_wd;
|
||||
logic ctrl_mode_qs;
|
||||
logic ctrl_mode_wd;
|
||||
logic ctrl_write_qs;
|
||||
logic ctrl_write_wd;
|
||||
logic ctrl_ack_qs;
|
||||
logic ctrl_error_qs;
|
||||
logic [15:0] ctrl_clk_div_qs;
|
||||
logic [15:0] ctrl_clk_div_wd;
|
||||
logic master_data_we;
|
||||
logic [7:0] master_data_address_qs;
|
||||
logic [7:0] master_data_address_wd;
|
||||
logic [7:0] master_data_regreg_qs;
|
||||
logic [7:0] master_data_regreg_wd;
|
||||
logic [7:0] master_data_data_qs;
|
||||
logic [7:0] master_data_data_wd;
|
||||
logic slave_data_re;
|
||||
logic [7:0] slave_data_qs;
|
||||
|
||||
// Register instances
|
||||
// R[ctrl]: V(False)
|
||||
|
||||
// F[start]: 0:0
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_start (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_start_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.ctrl.start.de),
|
||||
.d (hw2reg.ctrl.start.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.start.qe),
|
||||
.q (reg2hw.ctrl.start.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_start_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[int_en]: 1:1
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_int_en (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_int_en_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.ctrl.int_en.de),
|
||||
.d (hw2reg.ctrl.int_en.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.int_en.qe),
|
||||
.q (reg2hw.ctrl.int_en.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_int_en_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[int_pending]: 2:2
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("W1C"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_int_pending (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_int_pending_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.ctrl.int_pending.de),
|
||||
.d (hw2reg.ctrl.int_pending.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.int_pending.qe),
|
||||
.q (reg2hw.ctrl.int_pending.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_int_pending_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[mode]: 3:3
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_mode (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_mode_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.ctrl.mode.de),
|
||||
.d (hw2reg.ctrl.mode.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.mode.qe),
|
||||
.q (reg2hw.ctrl.mode.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_mode_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[write]: 4:4
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_write (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_write_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.ctrl.write.de),
|
||||
.d (hw2reg.ctrl.write.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.write.qe),
|
||||
.q (reg2hw.ctrl.write.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_write_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[ack]: 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 #(
|
||||
.DW (1),
|
||||
.SWACCESS("RO"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_error (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.ctrl.error.de),
|
||||
.d (hw2reg.ctrl.error.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.error.qe),
|
||||
.q (reg2hw.ctrl.error.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_error_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[clk_div]: 31:16
|
||||
prim_subreg #(
|
||||
.DW (16),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (16'h0)
|
||||
) u_ctrl_clk_div (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_clk_div_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.ctrl.clk_div.de),
|
||||
.d (hw2reg.ctrl.clk_div.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.clk_div.qe),
|
||||
.q (reg2hw.ctrl.clk_div.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_clk_div_qs)
|
||||
);
|
||||
|
||||
|
||||
// R[master_data]: V(False)
|
||||
|
||||
// F[address]: 7:0
|
||||
prim_subreg #(
|
||||
.DW (8),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (8'h0)
|
||||
) u_master_data_address (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (master_data_we),
|
||||
.wd (master_data_address_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.master_data.address.de),
|
||||
.d (hw2reg.master_data.address.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (),
|
||||
.q (reg2hw.master_data.address.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (master_data_address_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[regreg]: 15:8
|
||||
prim_subreg #(
|
||||
.DW (8),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (8'h0)
|
||||
) u_master_data_regreg (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (master_data_we),
|
||||
.wd (master_data_regreg_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.master_data.regreg.de),
|
||||
.d (hw2reg.master_data.regreg.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (),
|
||||
.q (reg2hw.master_data.regreg.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (master_data_regreg_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[data]: 23:16
|
||||
prim_subreg #(
|
||||
.DW (8),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (8'h0)
|
||||
) u_master_data_data (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (master_data_we),
|
||||
.wd (master_data_data_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (hw2reg.master_data.data.de),
|
||||
.d (hw2reg.master_data.data.d),
|
||||
|
||||
// to internal hardware
|
||||
.qe (),
|
||||
.q (reg2hw.master_data.data.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (master_data_data_qs)
|
||||
);
|
||||
|
||||
|
||||
// R[slave_data]: V(True)
|
||||
|
||||
prim_subreg_ext #(
|
||||
.DW (8)
|
||||
) u_slave_data (
|
||||
.re (slave_data_re),
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
.d (hw2reg.slave_data.d),
|
||||
.qre (reg2hw.slave_data.re),
|
||||
.qe (),
|
||||
.q (reg2hw.slave_data.q),
|
||||
.qs (slave_data_qs)
|
||||
);
|
||||
|
||||
|
||||
logic [2:0] addr_hit;
|
||||
always_comb begin
|
||||
addr_hit = '0;
|
||||
addr_hit[0] = (reg_addr == I2C_CTRL_OFFSET);
|
||||
addr_hit[1] = (reg_addr == I2C_MASTER_DATA_OFFSET);
|
||||
addr_hit[2] = (reg_addr == I2C_SLAVE_DATA_OFFSET);
|
||||
end
|
||||
|
||||
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
|
||||
|
||||
// Check sub-word write is permitted
|
||||
always_comb begin
|
||||
wr_err = (reg_we &
|
||||
((addr_hit[0] & (|(I2C_PERMIT[0] & ~reg_be))) |
|
||||
(addr_hit[1] & (|(I2C_PERMIT[1] & ~reg_be))) |
|
||||
(addr_hit[2] & (|(I2C_PERMIT[2] & ~reg_be)))));
|
||||
end
|
||||
|
||||
assign ctrl_we = addr_hit[0] & reg_we & !reg_error;
|
||||
|
||||
assign ctrl_start_wd = reg_wdata[0];
|
||||
|
||||
assign ctrl_int_en_wd = reg_wdata[1];
|
||||
|
||||
assign ctrl_int_pending_wd = reg_wdata[2];
|
||||
|
||||
assign ctrl_mode_wd = reg_wdata[3];
|
||||
|
||||
assign ctrl_write_wd = reg_wdata[4];
|
||||
|
||||
assign ctrl_clk_div_wd = reg_wdata[31:16];
|
||||
assign master_data_we = addr_hit[1] & reg_we & !reg_error;
|
||||
|
||||
assign master_data_address_wd = reg_wdata[7:0];
|
||||
|
||||
assign master_data_regreg_wd = reg_wdata[15:8];
|
||||
|
||||
assign master_data_data_wd = reg_wdata[23:16];
|
||||
assign slave_data_re = addr_hit[2] & reg_re & !reg_error;
|
||||
|
||||
// Read data return
|
||||
always_comb begin
|
||||
reg_rdata_next = '0;
|
||||
unique case (1'b1)
|
||||
addr_hit[0]: begin
|
||||
reg_rdata_next[0] = ctrl_start_qs;
|
||||
reg_rdata_next[1] = ctrl_int_en_qs;
|
||||
reg_rdata_next[2] = ctrl_int_pending_qs;
|
||||
reg_rdata_next[3] = ctrl_mode_qs;
|
||||
reg_rdata_next[4] = ctrl_write_qs;
|
||||
reg_rdata_next[5] = ctrl_ack_qs;
|
||||
reg_rdata_next[6] = ctrl_error_qs;
|
||||
reg_rdata_next[31:16] = ctrl_clk_div_qs;
|
||||
end
|
||||
|
||||
addr_hit[1]: begin
|
||||
reg_rdata_next[7:0] = master_data_address_qs;
|
||||
reg_rdata_next[15:8] = master_data_regreg_qs;
|
||||
reg_rdata_next[23:16] = master_data_data_qs;
|
||||
end
|
||||
|
||||
addr_hit[2]: begin
|
||||
reg_rdata_next[7:0] = slave_data_qs;
|
||||
end
|
||||
|
||||
default: begin
|
||||
reg_rdata_next = '1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// Unused signal tieoff
|
||||
|
||||
// wdata / byte enable are not always fully used
|
||||
// add a blanket unused statement to handle lint waivers
|
||||
logic unused_wdata;
|
||||
logic unused_be;
|
||||
assign unused_wdata = ^reg_wdata;
|
||||
assign unused_be = ^reg_be;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
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_top (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
output logic scl_o,
|
||||
output logic scl_oe_o,
|
||||
input logic scl_i,
|
||||
output logic sda_o,
|
||||
output logic sda_oe_o,
|
||||
input logic sda_i,
|
||||
|
||||
output logic irq_o,
|
||||
|
||||
// OBI总线接口信号
|
||||
input logic req_i,
|
||||
input logic we_i,
|
||||
input logic [ 3:0] be_i,
|
||||
input logic [31:0] addr_i,
|
||||
input logic [31:0] data_i,
|
||||
output logic [31:0] data_o
|
||||
);
|
||||
|
||||
logic re;
|
||||
logic we;
|
||||
logic [31:0] addr;
|
||||
logic [31:0] reg_rdata;
|
||||
|
||||
// 读信号
|
||||
assign re = req_i & (!we_i);
|
||||
// 写信号
|
||||
assign we = req_i & we_i;
|
||||
// 去掉基地址
|
||||
assign addr = {16'h0, addr_i[15:0]};
|
||||
|
||||
i2c_core u_i2c_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.scl_o (scl_o),
|
||||
.scl_oe_o (scl_oe_o),
|
||||
.scl_i (scl_i),
|
||||
.sda_o (sda_o),
|
||||
.sda_oe_o (sda_oe_o),
|
||||
.sda_i (sda_i),
|
||||
.irq_o (irq_o),
|
||||
.reg_we_i (we),
|
||||
.reg_re_i (re),
|
||||
.reg_wdata_i(data_i),
|
||||
.reg_be_i (be_i),
|
||||
.reg_addr_i (addr),
|
||||
.reg_rdata_o(reg_rdata)
|
||||
);
|
||||
|
||||
always_ff @(posedge clk_i) begin
|
||||
data_o <= reg_rdata;
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -31,6 +31,9 @@ module tinyriscv_soc_top #(
|
|||
output wire uart_tx_pin, // UART发送引脚
|
||||
input wire uart_rx_pin, // UART接收引脚
|
||||
|
||||
inout wire i2c_scl_pin, // I2C SCL引脚
|
||||
inout wire i2c_sda_pin, // I2C SDA引脚
|
||||
|
||||
inout wire[1:0] gpio_pins, // GPIO引脚,1bit代表一个GPIO
|
||||
|
||||
input wire jtag_TCK_pin, // JTAG TCK引脚
|
||||
|
@ -42,9 +45,9 @@ module tinyriscv_soc_top #(
|
|||
|
||||
localparam int MASTERS = 3; // Number of master ports
|
||||
`ifdef VERILATOR
|
||||
localparam int SLAVES = 8; // Number of slave ports
|
||||
localparam int SLAVES = 9; // Number of slave ports
|
||||
`else
|
||||
localparam int SLAVES = 7; // Number of slave ports
|
||||
localparam int SLAVES = 8; // Number of slave ports
|
||||
`endif
|
||||
|
||||
// masters
|
||||
|
@ -60,8 +63,9 @@ module tinyriscv_soc_top #(
|
|||
localparam int Gpio = 4;
|
||||
localparam int Uart0 = 5;
|
||||
localparam int Rvic = 6;
|
||||
localparam int I2c = 7;
|
||||
`ifdef VERILATOR
|
||||
localparam int SimCtrl = 7;
|
||||
localparam int SimCtrl = 8;
|
||||
`endif
|
||||
|
||||
|
||||
|
@ -110,17 +114,26 @@ module tinyriscv_soc_top #(
|
|||
wire uart0_irq;
|
||||
wire gpio0_irq;
|
||||
wire gpio1_irq;
|
||||
wire i2c0_irq;
|
||||
|
||||
wire[GPIO_NUM-1:0] gpio_data_in;
|
||||
wire[GPIO_NUM-1:0] gpio_oe;
|
||||
wire[GPIO_NUM-1:0] gpio_data_out;
|
||||
|
||||
wire i2c_scl_in;
|
||||
wire i2c_scl_oe;
|
||||
wire i2c_scl_out;
|
||||
wire i2c_sda_in;
|
||||
wire i2c_sda_oe;
|
||||
wire i2c_sda_out;
|
||||
|
||||
always @ (*) begin
|
||||
irq_src = 32'h0;
|
||||
irq_src[0] = timer0_irq;
|
||||
irq_src[1] = uart0_irq;
|
||||
irq_src[2] = gpio0_irq;
|
||||
irq_src[3] = gpio1_irq;
|
||||
irq_src[4] = i2c0_irq;
|
||||
end
|
||||
|
||||
`ifdef VERILATOR
|
||||
|
@ -269,6 +282,32 @@ module tinyriscv_soc_top #(
|
|||
.data_o (slave_rdata[Rvic])
|
||||
);
|
||||
|
||||
assign i2c_scl_pin = i2c_scl_oe ? i2c_scl_out : 1'bz;
|
||||
assign i2c_scl_in = i2c_scl_pin;
|
||||
assign i2c_sda_pin = i2c_sda_oe ? i2c_sda_out : 1'bz;
|
||||
assign i2c_sda_in = i2c_sda_pin;
|
||||
|
||||
assign slave_addr_mask[I2c] = `I2C0_ADDR_MASK;
|
||||
assign slave_addr_base[I2c] = `I2C0_ADDR_BASE;
|
||||
// 7.I2C0模块
|
||||
i2c_top i2c0(
|
||||
.clk_i (clk),
|
||||
.rst_ni (ndmreset_n),
|
||||
.scl_o (i2c_scl_out),
|
||||
.scl_oe_o (i2c_scl_oe),
|
||||
.scl_i (i2c_scl_in),
|
||||
.sda_o (i2c_sda_out),
|
||||
.sda_oe_o (i2c_sda_oe),
|
||||
.sda_i (i2c_sda_in),
|
||||
.irq_o (i2c0_irq),
|
||||
.req_i (slave_req[I2c]),
|
||||
.we_i (slave_we[I2c]),
|
||||
.be_i (slave_be[I2c]),
|
||||
.addr_i (slave_addr[I2c]),
|
||||
.data_i (slave_wdata[I2c]),
|
||||
.data_o (slave_rdata[I2c])
|
||||
);
|
||||
|
||||
`ifdef VERILATOR
|
||||
assign slave_addr_mask[SimCtrl] = `SIM_CTRL_ADDR_MASK;
|
||||
assign slave_addr_base[SimCtrl] = `SIM_CTRL_ADDR_BASE;
|
||||
|
|
Loading…
Reference in New Issue