rtl:perips: rewrite gpio
Signed-off-by: liangkangnan <liangkangnan@163.com>pull/4/head
parent
9387f56a33
commit
5fa659a084
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue