rtl:perips: rewrite gpio

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/4/head
liangkangnan 2021-08-13 09:33:15 +08:00
parent 9387f56a33
commit 5fa659a084
10 changed files with 794 additions and 142 deletions

View File

@ -33,7 +33,6 @@
../rtl/debug/jtag_top.sv
../rtl/debug/debug_rom.sv
../rtl/perips/gpio.sv
../rtl/perips/ram.sv
../rtl/perips/rom.sv
../rtl/perips/rvic.sv
@ -47,6 +46,10 @@
../rtl/perips/timer/timer_reg_top.sv
../rtl/perips/timer/timer_core.sv
../rtl/perips/timer/timer_top.sv
../rtl/perips/gpio/gpio_reg_pkg.sv
../rtl/perips/gpio/gpio_reg_top.sv
../rtl/perips/gpio/gpio_core.sv
../rtl/perips/gpio/gpio_top.sv
../rtl/sys_bus/obi_interconnect.sv
../rtl/sys_bus/obi_interconnect_master_sel.sv
@ -64,3 +67,4 @@
../rtl/utils/prim_subreg.sv
../rtl/utils/prim_subreg_arb.sv
../rtl/utils/prim_subreg_ext.sv
../rtl/utils/prim_filter.sv

View File

@ -1,120 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// GPIO模块
module gpio(
input wire clk,
input wire rst_n,
input wire[31:0] addr_i,
input wire[31:0] data_i,
input wire[3:0] sel_i,
input wire we_i,
output wire[31:0] data_o,
input wire[1:0] io_pin_i,
output wire[31:0] reg_ctrl,
output wire[31:0] reg_data
);
// GPIO寄存器(偏移)地址
localparam GPIO_CTRL = 4'h0;
localparam GPIO_DATA = 4'h4;
// GPIO控制寄存器
// 每2位控制1个IO的输入、输出模式最多支持16个IO
// 0: 高阻1输出2输入
reg[31:0] gpio_ctrl;
// GPIO输入输出数据寄存器
reg[31:0] gpio_data;
assign reg_ctrl = gpio_ctrl;
assign reg_data = gpio_data;
wire wen = we_i;
wire ren = (~we_i);
wire write_reg_ctrl_en = wen & (addr_i[3:0] == GPIO_CTRL);
wire write_reg_data_en = wen & (addr_i[3:0] == GPIO_DATA);
// 写gpio_ctrl
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
gpio_ctrl <= 32'h0;
end else begin
if (write_reg_ctrl_en) begin
if (sel_i[0]) begin
gpio_ctrl[7:0] <= data_i[7:0];
end
if (sel_i[1]) begin
gpio_ctrl[15:8] <= data_i[15:8];
end
if (sel_i[2]) begin
gpio_ctrl[23:16] <= data_i[23:16];
end
if (sel_i[3]) begin
gpio_ctrl[31:24] <= data_i[31:24];
end
end
end
end
// 写gpio_data
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
gpio_data <= 32'h0;
end else begin
if (write_reg_data_en) begin
if (sel_i[0]) begin
gpio_data[7:0] <= data_i[7:0];
end
if (sel_i[1]) begin
gpio_data[15:8] <= data_i[15:8];
end
end else begin
if (gpio_ctrl[1:0] == 2'b10) begin
gpio_data[0] <= io_pin_i[0];
end
if (gpio_ctrl[3:2] == 2'b10) begin
gpio_data[1] <= io_pin_i[1];
end
end
end
end
reg[31:0] data_r;
// 读寄存器
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_r <= 32'h0;
end else begin
if (ren) begin
case (addr_i[3:0])
GPIO_CTRL: data_r <= gpio_ctrl;
GPIO_DATA: data_r <= gpio_data;
default: data_r <= 32'h0;
endcase
end else begin
data_r <= 32'h0;
end
end
end
assign data_o = data_r;
endmodule

59
rtl/perips/gpio/gpio.h Normal file
View File

@ -0,0 +1,59 @@
// Generated register defines for gpio
// Copyright information found in source file:
// Copyright lowRISC contributors.
// Licensing information found in source file:
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef _GPIO_REG_DEFS_
#define _GPIO_REG_DEFS_
#ifdef __cplusplus
extern "C" {
#endif
// Register width
#define GPIO_PARAM_REG_WIDTH 32
// gpio mode register
#define GPIO_MODE_REG_OFFSET 0x0
#define GPIO_MODE_REG_RESVAL 0x0
#define GPIO_MODE_GPIO_MASK 0xffff
#define GPIO_MODE_GPIO_OFFSET 0
#define GPIO_MODE_GPIO_FIELD \
((bitfield_field32_t) { .mask = GPIO_MODE_GPIO_MASK, .index = GPIO_MODE_GPIO_OFFSET })
// gpio interrupt register
#define GPIO_INTR_REG_OFFSET 0x4
#define GPIO_INTR_REG_RESVAL 0x0
#define GPIO_INTR_GPIO_INT_MASK 0xffff
#define GPIO_INTR_GPIO_INT_OFFSET 0
#define GPIO_INTR_GPIO_INT_FIELD \
((bitfield_field32_t) { .mask = GPIO_INTR_GPIO_INT_MASK, .index = GPIO_INTR_GPIO_INT_OFFSET })
#define GPIO_INTR_GPIO_PENDING_MASK 0xff
#define GPIO_INTR_GPIO_PENDING_OFFSET 16
#define GPIO_INTR_GPIO_PENDING_FIELD \
((bitfield_field32_t) { .mask = GPIO_INTR_GPIO_PENDING_MASK, .index = GPIO_INTR_GPIO_PENDING_OFFSET })
// gpio data register
#define GPIO_DATA_REG_OFFSET 0x8
#define GPIO_DATA_REG_RESVAL 0x0
#define GPIO_DATA_GPIO_MASK 0xff
#define GPIO_DATA_GPIO_OFFSET 0
#define GPIO_DATA_GPIO_FIELD \
((bitfield_field32_t) { .mask = GPIO_DATA_GPIO_MASK, .index = GPIO_DATA_GPIO_OFFSET })
// gpio input filter enable register
#define GPIO_FILTER_REG_OFFSET 0xc
#define GPIO_FILTER_REG_RESVAL 0x0
#define GPIO_FILTER_GPIO_MASK 0xff
#define GPIO_FILTER_GPIO_OFFSET 0
#define GPIO_FILTER_GPIO_FIELD \
((bitfield_field32_t) { .mask = GPIO_FILTER_GPIO_MASK, .index = GPIO_FILTER_GPIO_OFFSET })
#ifdef __cplusplus
} // extern "C"
#endif
#endif // _GPIO_REG_DEFS_
// End generated register defines for gpio

View File

@ -0,0 +1,61 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "gpio",
clocking: [{clock: "clk_i", reset: "rst_ni"}],
bus_interfaces: [
{ protocol: "tlul", direction: "device" }
],
regwidth: "32",
registers: [
{ name: "MODE",
desc: "gpio mode register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "15:0",
name: "GPIO",
desc: "gpio input or output mode, 2 bits for each gpio",
}
]
}
{ name: "INTR",
desc: "gpio interrupt register",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "15:0",
name: "GPIO_INT",
desc: "gpio interrupt mode, 2 bits for each gpio",
}
{ bits: "23:16",
name: "GPIO_PENDING",
swaccess: "rw1c",
desc: "gpio interrupt pending, 1 bits for each gpio",
}
]
}
{ name: "DATA",
desc: "gpio data register",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "7:0",
name: "GPIO",
desc: "gpio input or output data, 1 bits for each gpio",
}
]
}
{ name: "FILTER",
desc: "gpio input filter enable register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "7:0",
name: "GPIO",
desc: "gpio input filter enable, 1 bits for each gpio",
}
]
}
]
}

View File

@ -0,0 +1,158 @@
/*
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.
*/
// 目前最多支持8个GPIO
module gpio_core #(
parameter int GPIO_NUM = 2
)(
input logic clk_i,
input logic rst_ni,
output logic [GPIO_NUM-1:0] gpio_oe_o,
output logic [GPIO_NUM-1:0] gpio_data_o,
input logic [GPIO_NUM-1:0] gpio_data_i,
output logic irq_gpio0_o,
output logic irq_gpio1_o,
output logic irq_gpio2_4_o,
output logic irq_gpio5_7_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
);
localparam logic [1:0] INTR_MODE_RAISE_EDGE = 2'd1;
localparam logic [1:0] INTR_MODE_FALL_EDGE = 2'd2;
localparam logic [1:0] INTR_MODE_DOUBLE_EDGE = 2'd3;
localparam logic [1:0] GPIO_MODE_INPUT = 2'd1;
localparam logic [1:0] GPIO_MODE_OUTPUT = 2'd2;
import gpio_reg_pkg::*;
gpio_reg_pkg::gpio_reg2hw_t reg2hw;
gpio_reg_pkg::gpio_hw2reg_t hw2reg;
logic [GPIO_NUM-1:0] gpio_oe;
logic [GPIO_NUM-1:0] gpio_ie;
logic [GPIO_NUM-1:0] gpio_data;
logic [GPIO_NUM-1:0] gpio_filter_enable;
logic [GPIO_NUM-1:0] gpio_filter_data;
logic [GPIO_NUM-1:0] gpio_raise_detect;
logic [GPIO_NUM-1:0] gpio_fall_detect;
logic [GPIO_NUM-1:0] gpio_intr_trigge;
// 输入滤波使能
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_filter_enable
assign gpio_filter_enable[i] = reg2hw.filter.q[i];
end
// 输出使能
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_oe
assign gpio_oe[i] = reg2hw.mode.q[i*2+1:i*2] == GPIO_MODE_OUTPUT;
end
assign gpio_oe_o = gpio_oe;
// 输出数据
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_data
assign gpio_data[i] = reg2hw.data.q[i];
end
assign gpio_data_o = gpio_data;
// 输入使能
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_ie
assign gpio_ie[i] = reg2hw.mode.q[i*2+1:i*2] == GPIO_MODE_INPUT;
end
// 硬件写data数据
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_h2r_data
assign hw2reg.data.d[i] = gpio_ie[i] ? gpio_filter_data[i] : reg2hw.data.q[i];
end
// 硬件写data使能
assign hw2reg.data.de = |gpio_ie;
// 中断有效
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_intr_trigge
assign gpio_intr_trigge[i] = ((reg2hw.intr.gpio_int[i*2+1:i*2] == INTR_MODE_RAISE_EDGE) & gpio_raise_detect[i]) |
((reg2hw.intr.gpio_int[i*2+1:i*2] == INTR_MODE_FALL_EDGE) & gpio_fall_detect[i]) |
((reg2hw.intr.gpio_int[i*2+1:i*2] == INTR_MODE_DOUBLE_EDGE) & (gpio_raise_detect[i] | gpio_fall_detect[i]));
end
// 硬件写中断pending数据
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_intr_pending
assign hw2reg.intr.gpio_pending.d[i] = gpio_intr_trigge[i] ? 1'b1 : reg2hw.intr.gpio_pending.q[i];
end
// 硬件写中断pending使能
assign hw2reg.intr.gpio_pending.de = |gpio_intr_trigge;
// 中断输出信号
if (GPIO_NUM >= 1) begin : g_num_ge_1
assign irq_gpio0_o = reg2hw.intr.gpio_pending.q[0];
end
if (GPIO_NUM >= 2) begin : g_num_ge_2
assign irq_gpio1_o = reg2hw.intr.gpio_pending.q[1];
end
if (GPIO_NUM >= 5) begin : g_num_ge_5
assign irq_gpio2_4_o = reg2hw.intr.gpio_pending.q[2] | reg2hw.intr.gpio_pending.q[3] | reg2hw.intr.gpio_pending.q[4];
end
if (GPIO_NUM >= 8) begin : g_num_ge_8
assign irq_gpio5_7_o = reg2hw.intr.gpio_pending.q[5] | reg2hw.intr.gpio_pending.q[6] | reg2hw.intr.gpio_pending.q[7];
end
// 沿检测
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_edge_detect
edge_detect u_edge_detect(
.clk_i (clk_i),
.rst_ni (rst_ni),
.sig_i (gpio_filter_data[i]),
.sig_o (),
.re_o (gpio_raise_detect[i]),
.fe_o (gpio_fall_detect[i])
);
end
// 输入信号滤波
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_filter
prim_filter #(
.Cycles(8)
) gpio_filter (
.clk_i (clk_i),
.rst_ni (rst_ni),
.enable_i (gpio_filter_enable[i]),
.filter_i (gpio_data_i[i]),
.filter_o (gpio_filter_data[i])
);
end
gpio_reg_top u_gpio_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

View File

@ -0,0 +1,90 @@
// 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 gpio_reg_pkg;
// Address widths within the block
parameter int BlockAw = 4;
////////////////////////////
// Typedefs for registers //
////////////////////////////
typedef struct packed {
logic [15:0] q;
} gpio_reg2hw_mode_reg_t;
typedef struct packed {
struct packed {
logic [15:0] q;
} gpio_int;
struct packed {
logic [7:0] q;
} gpio_pending;
} gpio_reg2hw_intr_reg_t;
typedef struct packed {
logic [7:0] q;
} gpio_reg2hw_data_reg_t;
typedef struct packed {
logic [7:0] q;
} gpio_reg2hw_filter_reg_t;
typedef struct packed {
struct packed {
logic [15:0] d;
logic de;
} gpio_int;
struct packed {
logic [7:0] d;
logic de;
} gpio_pending;
} gpio_hw2reg_intr_reg_t;
typedef struct packed {
logic [7:0] d;
logic de;
} gpio_hw2reg_data_reg_t;
// Register -> HW type
typedef struct packed {
gpio_reg2hw_mode_reg_t mode; // [55:40]
gpio_reg2hw_intr_reg_t intr; // [39:16]
gpio_reg2hw_data_reg_t data; // [15:8]
gpio_reg2hw_filter_reg_t filter; // [7:0]
} gpio_reg2hw_t;
// HW -> register type
typedef struct packed {
gpio_hw2reg_intr_reg_t intr; // [34:9]
gpio_hw2reg_data_reg_t data; // [8:0]
} gpio_hw2reg_t;
// Register offsets
parameter logic [BlockAw-1:0] GPIO_MODE_OFFSET = 4'h0;
parameter logic [BlockAw-1:0] GPIO_INTR_OFFSET = 4'h4;
parameter logic [BlockAw-1:0] GPIO_DATA_OFFSET = 4'h8;
parameter logic [BlockAw-1:0] GPIO_FILTER_OFFSET = 4'hc;
// Register index
typedef enum int {
GPIO_MODE,
GPIO_INTR,
GPIO_DATA,
GPIO_FILTER
} gpio_id_e;
// Register width information to check illegal writes
parameter logic [3:0] GPIO_PERMIT [4] = '{
4'b0011, // index[0] GPIO_MODE
4'b0111, // index[1] GPIO_INTR
4'b0001, // index[2] GPIO_DATA
4'b0001 // index[3] GPIO_FILTER
};
endpackage

View File

@ -0,0 +1,263 @@
// 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 gpio_reg_top (
input logic clk_i,
input logic rst_ni,
// To HW
output gpio_reg_pkg::gpio_reg2hw_t reg2hw, // Write
input gpio_reg_pkg::gpio_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 gpio_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 mode_we;
logic [15:0] mode_qs;
logic [15:0] mode_wd;
logic intr_we;
logic [15:0] intr_gpio_int_qs;
logic [15:0] intr_gpio_int_wd;
logic [7:0] intr_gpio_pending_qs;
logic [7:0] intr_gpio_pending_wd;
logic data_we;
logic [7:0] data_qs;
logic [7:0] data_wd;
logic filter_we;
logic [7:0] filter_qs;
logic [7:0] filter_wd;
// Register instances
// R[mode]: V(False)
prim_subreg #(
.DW (16),
.SWACCESS("RW"),
.RESVAL (16'h0)
) u_mode (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (mode_we),
.wd (mode_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.mode.q),
// to register interface (read)
.qs (mode_qs)
);
// R[intr]: V(False)
// F[gpio_int]: 15:0
prim_subreg #(
.DW (16),
.SWACCESS("RW"),
.RESVAL (16'h0)
) u_intr_gpio_int (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (intr_we),
.wd (intr_gpio_int_wd),
// from internal hardware
.de (hw2reg.intr.gpio_int.de),
.d (hw2reg.intr.gpio_int.d),
// to internal hardware
.qe (),
.q (reg2hw.intr.gpio_int.q),
// to register interface (read)
.qs (intr_gpio_int_qs)
);
// F[gpio_pending]: 23:16
prim_subreg #(
.DW (8),
.SWACCESS("W1C"),
.RESVAL (8'h0)
) u_intr_gpio_pending (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (intr_we),
.wd (intr_gpio_pending_wd),
// from internal hardware
.de (hw2reg.intr.gpio_pending.de),
.d (hw2reg.intr.gpio_pending.d),
// to internal hardware
.qe (),
.q (reg2hw.intr.gpio_pending.q),
// to register interface (read)
.qs (intr_gpio_pending_qs)
);
// R[data]: V(False)
prim_subreg #(
.DW (8),
.SWACCESS("RW"),
.RESVAL (8'h0)
) u_data (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (data_we),
.wd (data_wd),
// from internal hardware
.de (hw2reg.data.de),
.d (hw2reg.data.d),
// to internal hardware
.qe (),
.q (reg2hw.data.q),
// to register interface (read)
.qs (data_qs)
);
// R[filter]: V(False)
prim_subreg #(
.DW (8),
.SWACCESS("RW"),
.RESVAL (8'h0)
) u_filter (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (filter_we),
.wd (filter_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.filter.q),
// to register interface (read)
.qs (filter_qs)
);
logic [3:0] addr_hit;
always_comb begin
addr_hit = '0;
addr_hit[0] = (reg_addr == GPIO_MODE_OFFSET);
addr_hit[1] = (reg_addr == GPIO_INTR_OFFSET);
addr_hit[2] = (reg_addr == GPIO_DATA_OFFSET);
addr_hit[3] = (reg_addr == GPIO_FILTER_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] & (|(GPIO_PERMIT[0] & ~reg_be))) |
(addr_hit[1] & (|(GPIO_PERMIT[1] & ~reg_be))) |
(addr_hit[2] & (|(GPIO_PERMIT[2] & ~reg_be))) |
(addr_hit[3] & (|(GPIO_PERMIT[3] & ~reg_be)))));
end
assign mode_we = addr_hit[0] & reg_we & !reg_error;
assign mode_wd = reg_wdata[15:0];
assign intr_we = addr_hit[1] & reg_we & !reg_error;
assign intr_gpio_int_wd = reg_wdata[15:0];
assign intr_gpio_pending_wd = reg_wdata[23:16];
assign data_we = addr_hit[2] & reg_we & !reg_error;
assign data_wd = reg_wdata[7:0];
assign filter_we = addr_hit[3] & reg_we & !reg_error;
assign filter_wd = reg_wdata[7:0];
// Read data return
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
addr_hit[0]: begin
reg_rdata_next[15:0] = mode_qs;
end
addr_hit[1]: begin
reg_rdata_next[15:0] = intr_gpio_int_qs;
reg_rdata_next[23:16] = intr_gpio_pending_qs;
end
addr_hit[2]: begin
reg_rdata_next[7:0] = data_qs;
end
addr_hit[3]: begin
reg_rdata_next[7:0] = filter_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

View File

@ -0,0 +1,76 @@
/*
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 gpio_top #(
parameter int GPIO_NUM = 2
)(
input logic clk_i,
input logic rst_ni,
output logic [GPIO_NUM-1:0] gpio_oe_o,
output logic [GPIO_NUM-1:0] gpio_data_o,
input logic [GPIO_NUM-1:0] gpio_data_i,
output logic irq_gpio0_o,
output logic irq_gpio1_o,
output logic irq_gpio2_4_o,
output logic irq_gpio5_7_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]};
gpio_core #(
.GPIO_NUM(GPIO_NUM)
) u_gpio_core (
.clk_i (clk_i),
.rst_ni (rst_ni),
.gpio_oe_o (gpio_oe_o),
.gpio_data_o(gpio_data_o),
.gpio_data_i(gpio_data_i),
.irq_gpio0_o(irq_gpio0_o),
.irq_gpio1_o(irq_gpio1_o),
.irq_gpio2_4_o(irq_gpio2_4_o),
.irq_gpio5_7_o(irq_gpio5_7_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

View File

@ -19,7 +19,8 @@
// tinyriscv soc顶层模块
module tinyriscv_soc_top #(
parameter bit TRACE_ENABLE = 1'b0
parameter bit TRACE_ENABLE = 1'b0,
parameter int GPIO_NUM = 2
)(
input wire clk_50m_i, // 时钟引脚
@ -107,15 +108,19 @@ module tinyriscv_soc_top #(
wire timer0_irq;
wire uart0_irq;
wire gpio0_irq;
wire gpio1_irq;
wire[1:0] io_in;
wire[31:0] gpio_ctrl;
wire[31:0] gpio_data;
wire[GPIO_NUM-1:0] gpio_data_in;
wire[GPIO_NUM-1:0] gpio_oe;
wire[GPIO_NUM-1:0] gpio_data_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;
end
`ifdef VERILATOR
@ -202,27 +207,32 @@ module tinyriscv_soc_top #(
.data_o (slave_rdata[Timer0])
);
// IO0
assign gpio_pins[0] = (gpio_ctrl[1:0] == 2'b01)? gpio_data[0]: 1'bz;
assign io_in[0] = gpio_pins[0];
// IO1
assign gpio_pins[1] = (gpio_ctrl[3:2] == 2'b01)? gpio_data[1]: 1'bz;
assign io_in[1] = gpio_pins[1];
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_data
assign gpio_pins[i] = gpio_oe[i] ? gpio_data_out[i] : 1'bz;
assign gpio_data_in[i] = gpio_pins[i];
end
assign slave_addr_mask[Gpio] = `GPIO_ADDR_MASK;
assign slave_addr_base[Gpio] = `GPIO_ADDR_BASE;
// 4.GPIO模块
gpio u_gpio(
.clk (clk),
.rst_n (ndmreset_n),
.addr_i (slave_addr[Gpio]),
.data_i (slave_wdata[Gpio]),
.sel_i (slave_be[Gpio]),
.we_i (slave_we[Gpio]),
.data_o (slave_rdata[Gpio]),
.io_pin_i(io_in),
.reg_ctrl(gpio_ctrl),
.reg_data(gpio_data)
gpio_top #(
.GPIO_NUM(GPIO_NUM)
) u_gpio (
.clk_i (clk),
.rst_ni (ndmreset_n),
.gpio_oe_o (gpio_oe),
.gpio_data_o (gpio_data_out),
.gpio_data_i (gpio_data_in),
.irq_gpio0_o (gpio0_irq),
.irq_gpio1_o (gpio1_irq),
.irq_gpio2_4_o (),
.irq_gpio5_7_o (),
.req_i (slave_req[Gpio]),
.we_i (slave_we[Gpio]),
.be_i (slave_be[Gpio]),
.addr_i (slave_addr[Gpio]),
.data_i (slave_wdata[Gpio]),
.data_o (slave_rdata[Gpio])
);
assign slave_addr_mask[Uart0] = `UART0_ADDR_MASK;

51
rtl/utils/prim_filter.sv Normal file
View File

@ -0,0 +1,51 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Primitive input filter, with enable. Configurable number of cycles.
//
// when in reset, stored vector is zero
// when enable is false, output is input
// when enable is true, output is stored value,
// new input must be opposite value from stored value for
// #Cycles before switching to new value.
module prim_filter #(parameter int Cycles = 4) (
input clk_i,
input rst_ni,
input enable_i,
input filter_i,
output filter_o
);
logic [Cycles-1:0] stored_vector_q, stored_vector_d;
logic stored_value_q, update_stored_value;
logic unused_stored_vector_q_msb;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
stored_value_q <= 1'b0;
end else if (update_stored_value) begin
stored_value_q <= filter_i;
end
end
assign stored_vector_d = {stored_vector_q[Cycles-2:0],filter_i};
assign unused_stored_vector_q_msb = stored_vector_q[Cycles-1];
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
stored_vector_q <= {Cycles{1'b0}};
end else begin
stored_vector_q <= stored_vector_d;
end
end
assign update_stored_value =
(stored_vector_d == {Cycles{1'b0}}) |
(stored_vector_d == {Cycles{1'b1}});
assign filter_o = enable_i ? stored_value_q : filter_i;
endmodule