diff --git a/rtl.flist b/rtl.flist index 69c7122..2a627b5 100644 --- a/rtl.flist +++ b/rtl.flist @@ -65,6 +65,10 @@ ../rtl/perips/spi/spi_top.sv ../rtl/perips/spi/spi_master.sv ../rtl/perips/spi/spi_transmit_byte.sv +../rtl/perips/pinmux/pinmux_reg_pkg.sv +../rtl/perips/pinmux/pinmux_reg_top.sv +../rtl/perips/pinmux/pinmux_core.sv +../rtl/perips/pinmux/pinmux_top.sv ../rtl/sys_bus/obi_interconnect.sv ../rtl/sys_bus/obi_interconnect_master_sel.sv diff --git a/rtl/perips/pinmux/pinmux.hjson b/rtl/perips/pinmux/pinmux.hjson new file mode 100644 index 0000000..4bcafe3 --- /dev/null +++ b/rtl/perips/pinmux/pinmux.hjson @@ -0,0 +1,83 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ name: "pinmux", + clocking: [{clock: "clk_i", reset: "rst_ni"}], + bus_interfaces: [ + { protocol: "tlul", direction: "device" } + ], + regwidth: "32", + registers: [ + { name: "CTRL", + desc: "Pinmux control register", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "1:0", + name: "IO0_MUX", + desc: "IO0 mux", + } + { bits: "3:2", + name: "IO1_MUX", + desc: "IO1 mux", + } + { bits: "5:4", + name: "IO2_MUX", + desc: "IO2 mux", + } + { bits: "7:6", + name: "IO3_MUX", + desc: "IO3 mux", + } + { bits: "9:8", + name: "IO4_MUX", + desc: "IO4 mux", + } + { bits: "11:10", + name: "IO5_MUX", + desc: "IO5 mux", + } + { bits: "13:12", + name: "IO6_MUX", + desc: "IO6 mux", + } + { bits: "15:14", + name: "IO7_MUX", + desc: "IO7 mux", + } + { bits: "17:16", + name: "IO8_MUX", + desc: "IO8 mux", + } + { bits: "19:18", + name: "IO9_MUX", + desc: "IO9 mux", + } + { bits: "21:20", + name: "IO10_MUX", + desc: "IO10 mux", + } + { bits: "23:22", + name: "IO11_MUX", + desc: "IO11 mux", + } + { bits: "25:24", + name: "IO12_MUX", + desc: "IO12 mux", + } + { bits: "27:26", + name: "IO13_MUX", + desc: "IO13 mux", + } + { bits: "29:28", + name: "IO14_MUX", + desc: "IO14 mux", + } + { bits: "31:30", + name: "IO15_MUX", + desc: "IO15 mux", + } + ] + } + ] +} diff --git a/rtl/perips/pinmux/pinmux_core.sv b/rtl/perips/pinmux/pinmux_core.sv new file mode 100644 index 0000000..1934761 --- /dev/null +++ b/rtl/perips/pinmux/pinmux_core.sv @@ -0,0 +1,613 @@ + /* + 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 pinmux_core #( + parameter int GPIO_NUM = 16, + parameter int I2C_NUM = 2, + parameter int UART_NUM = 3, + parameter int SPI_NUM = 1 + )( + input logic clk_i, + input logic rst_ni, + + input logic [GPIO_NUM-1:0] gpio_oe_i, + input logic [GPIO_NUM-1:0] gpio_val_i, + output logic [GPIO_NUM-1:0] gpio_val_o, + + input logic [I2C_NUM-1:0] i2c_sda_oe_i, + input logic [I2C_NUM-1:0] i2c_sda_val_i, + output logic [I2C_NUM-1:0] i2c_sda_val_o, + input logic [I2C_NUM-1:0] i2c_scl_oe_i, + input logic [I2C_NUM-1:0] i2c_scl_val_i, + output logic [I2C_NUM-1:0] i2c_scl_val_o, + + input logic [UART_NUM-1:0] uart_tx_oe_i, + input logic [UART_NUM-1:0] uart_tx_val_i, + output logic [UART_NUM-1:0] uart_tx_val_o, + input logic [UART_NUM-1:0] uart_rx_oe_i, + input logic [UART_NUM-1:0] uart_rx_val_i, + output logic [UART_NUM-1:0] uart_rx_val_o, + + input logic [SPI_NUM-1:0] spi_clk_oe_i, + input logic [SPI_NUM-1:0] spi_clk_val_i, + output logic [SPI_NUM-1:0] spi_clk_val_o, + input logic [SPI_NUM-1:0] spi_ss_oe_i, + input logic [SPI_NUM-1:0] spi_ss_val_i, + output logic [SPI_NUM-1:0] spi_ss_val_o, + input logic [ 3:0] spi_dq_oe_i [SPI_NUM-1:0], + input logic [ 3:0] spi_dq_val_i[SPI_NUM-1:0], + output logic [ 3:0] spi_dq_val_o[SPI_NUM-1:0], + + input logic [GPIO_NUM-1:0] io_val_i, + output logic [GPIO_NUM-1:0] io_val_o, + output logic [GPIO_NUM-1:0] io_oe_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 pinmux_reg_pkg::*; + + pinmux_reg_pkg::pinmux_reg2hw_t reg2hw; + + logic [1:0] io0_mux; + logic [1:0] io1_mux; + logic [1:0] io2_mux; + logic [1:0] io3_mux; + logic [1:0] io4_mux; + logic [1:0] io5_mux; + logic [1:0] io6_mux; + logic [1:0] io7_mux; + logic [1:0] io8_mux; + logic [1:0] io9_mux; + logic [1:0] io10_mux; + logic [1:0] io11_mux; + logic [1:0] io12_mux; + logic [1:0] io13_mux; + logic [1:0] io14_mux; + logic [1:0] io15_mux; + + assign io0_mux = reg2hw.ctrl.io0_mux.q; + assign io1_mux = reg2hw.ctrl.io1_mux.q; + assign io2_mux = reg2hw.ctrl.io2_mux.q; + assign io3_mux = reg2hw.ctrl.io3_mux.q; + assign io4_mux = reg2hw.ctrl.io4_mux.q; + assign io5_mux = reg2hw.ctrl.io5_mux.q; + assign io6_mux = reg2hw.ctrl.io6_mux.q; + assign io7_mux = reg2hw.ctrl.io7_mux.q; + assign io8_mux = reg2hw.ctrl.io8_mux.q; + assign io9_mux = reg2hw.ctrl.io9_mux.q; + assign io10_mux = reg2hw.ctrl.io10_mux.q; + assign io11_mux = reg2hw.ctrl.io11_mux.q; + assign io12_mux = reg2hw.ctrl.io12_mux.q; + assign io13_mux = reg2hw.ctrl.io13_mux.q; + assign io14_mux = reg2hw.ctrl.io14_mux.q; + assign io15_mux = reg2hw.ctrl.io15_mux.q; + + // IO0 + always_comb begin + io_val_o[0] = 1'b0; + io_oe_o[0] = 1'b0; + + case (io0_mux) + // GPIO0 + 2'b00: begin + io_val_o[0] = gpio_val_i[0]; + io_oe_o[0] = gpio_oe_i[0]; + end + // UART0_TX + 2'b01: begin + io_val_o[0] = uart_tx_val_i[0]; + io_oe_o[0] = uart_tx_oe_i[0]; + end + // UART0_RX + 2'b10: begin + io_val_o[0] = uart_rx_val_i[0]; + io_oe_o[0] = uart_rx_oe_i[0]; + end + // GPIO0 + 2'b11: begin + io_val_o[0] = gpio_val_i[0]; + io_oe_o[0] = gpio_oe_i[0]; + end + default: ; + endcase + end + + // IO1 + always_comb begin + io_val_o[1] = 1'b0; + io_oe_o[1] = 1'b0; + + case (io1_mux) + // GPIO1 + 2'b00: begin + io_val_o[1] = gpio_val_i[1]; + io_oe_o[1] = gpio_oe_i[1]; + end + // UART1_TX + 2'b01: begin + io_val_o[1] = uart_tx_val_i[1]; + io_oe_o[1] = uart_tx_oe_i[1]; + end + // UART1_RX + 2'b10: begin + io_val_o[1] = uart_rx_val_i[1]; + io_oe_o[1] = uart_rx_oe_i[1]; + end + // GPIO1 + 2'b11: begin + io_val_o[1] = gpio_val_i[1]; + io_oe_o[1] = gpio_oe_i[1]; + end + default: ; + endcase + end + + // IO2 + always_comb begin + io_val_o[2] = 1'b0; + io_oe_o[2] = 1'b0; + + case (io2_mux) + // GPIO2 + 2'b00: begin + io_val_o[2] = gpio_val_i[2]; + io_oe_o[2] = gpio_oe_i[2]; + end + // UART2_TX + 2'b01: begin + io_val_o[2] = uart_tx_val_i[2]; + io_oe_o[2] = uart_tx_oe_i[2]; + end + // UART2_RX + 2'b10: begin + io_val_o[2] = uart_rx_val_i[2]; + io_oe_o[2] = uart_rx_oe_i[2]; + end + // GPIO2 + 2'b11: begin + io_val_o[2] = gpio_val_i[2]; + io_oe_o[2] = gpio_oe_i[2]; + end + default: ; + endcase + end + + // IO3 + always_comb begin + io_val_o[3] = 1'b0; + io_oe_o[3] = 1'b0; + + case (io3_mux) + // GPIO3 + 2'b00: begin + io_val_o[3] = gpio_val_i[3]; + io_oe_o[3] = gpio_oe_i[3]; + end + // UART0_TX + 2'b01: begin + io_val_o[3] = uart_tx_val_i[0]; + io_oe_o[3] = uart_tx_oe_i[0]; + end + // UART0_RX + 2'b10: begin + io_val_o[3] = uart_rx_val_i[0]; + io_oe_o[3] = uart_rx_oe_i[0]; + end + // GPIO3 + 2'b11: begin + io_val_o[3] = gpio_val_i[3]; + io_oe_o[3] = gpio_oe_i[3]; + end + default: ; + endcase + end + + // IO4 + always_comb begin + io_val_o[4] = 1'b0; + io_oe_o[4] = 1'b0; + + case (io4_mux) + // GPIO4 + 2'b00: begin + io_val_o[4] = gpio_val_i[4]; + io_oe_o[4] = gpio_oe_i[4]; + end + // UART1_TX + 2'b01: begin + io_val_o[4] = uart_tx_val_i[1]; + io_oe_o[4] = uart_tx_oe_i[1]; + end + // UART1_RX + 2'b10: begin + io_val_o[4] = uart_rx_val_i[1]; + io_oe_o[4] = uart_rx_oe_i[1]; + end + // GPIO4 + 2'b11: begin + io_val_o[4] = gpio_val_i[4]; + io_oe_o[4] = gpio_oe_i[4]; + end + default: ; + endcase + end + + // IO5 + always_comb begin + io_val_o[5] = 1'b0; + io_oe_o[5] = 1'b0; + + case (io5_mux) + // GPIO5 + 2'b00: begin + io_val_o[5] = gpio_val_i[5]; + io_oe_o[5] = gpio_oe_i[5]; + end + // UART2_TX + 2'b01: begin + io_val_o[5] = uart_tx_val_i[2]; + io_oe_o[5] = uart_tx_oe_i[2]; + end + // UART2_RX + 2'b10: begin + io_val_o[5] = uart_rx_val_i[2]; + io_oe_o[5] = uart_rx_oe_i[2]; + end + // GPIO5 + 2'b11: begin + io_val_o[5] = gpio_val_i[5]; + io_oe_o[5] = gpio_oe_i[5]; + end + default: ; + endcase + end + + // IO6 + always_comb begin + io_val_o[6] = 1'b0; + io_oe_o[6] = 1'b0; + + case (io6_mux) + // GPIO6 + 2'b00: begin + io_val_o[6] = gpio_val_i[6]; + io_oe_o[6] = gpio_oe_i[6]; + end + // I2C0_SCL + 2'b01: begin + io_val_o[6] = i2c_scl_val_i[0]; + io_oe_o[6] = i2c_scl_oe_i[0]; + end + // I2C0_SDA + 2'b10: begin + io_val_o[6] = i2c_sda_val_i[0]; + io_oe_o[6] = i2c_sda_oe_i[0]; + end + // GPIO6 + 2'b11: begin + io_val_o[6] = gpio_val_i[6]; + io_oe_o[6] = gpio_oe_i[6]; + end + default: ; + endcase + end + + // IO7 + always_comb begin + io_val_o[7] = 1'b0; + io_oe_o[7] = 1'b0; + + case (io7_mux) + // GPIO7 + 2'b00: begin + io_val_o[7] = gpio_val_i[7]; + io_oe_o[7] = gpio_oe_i[7]; + end + // I2C1_SCL + 2'b01: begin + io_val_o[7] = i2c_scl_val_i[1]; + io_oe_o[7] = i2c_scl_oe_i[1]; + end + // I2C1_SDA + 2'b10: begin + io_val_o[7] = i2c_sda_val_i[1]; + io_oe_o[7] = i2c_sda_oe_i[1]; + end + // GPIO7 + 2'b11: begin + io_val_o[7] = gpio_val_i[7]; + io_oe_o[7] = gpio_oe_i[7]; + end + default: ; + endcase + end + + // IO8 + always_comb begin + io_val_o[8] = 1'b0; + io_oe_o[8] = 1'b0; + + case (io8_mux) + // GPIO8 + 2'b00: begin + io_val_o[8] = gpio_val_i[8]; + io_oe_o[8] = gpio_oe_i[8]; + end + // I2C0_SCL + 2'b01: begin + io_val_o[8] = i2c_scl_val_i[0]; + io_oe_o[8] = i2c_scl_oe_i[0]; + end + // I2C0_SDA + 2'b10: begin + io_val_o[8] = i2c_sda_val_i[0]; + io_oe_o[8] = i2c_sda_oe_i[0]; + end + // GPIO8 + 2'b11: begin + io_val_o[8] = gpio_val_i[8]; + io_oe_o[8] = gpio_oe_i[8]; + end + default: ; + endcase + end + + // IO9 + always_comb begin + io_val_o[9] = 1'b0; + io_oe_o[9] = 1'b0; + + case (io9_mux) + // GPIO9 + 2'b00: begin + io_val_o[9] = gpio_val_i[9]; + io_oe_o[9] = gpio_oe_i[9]; + end + // I2C1_SCL + 2'b01: begin + io_val_o[9] = i2c_scl_val_i[1]; + io_oe_o[9] = i2c_scl_oe_i[1]; + end + // I2C1_SDA + 2'b10: begin + io_val_o[9] = i2c_sda_val_i[1]; + io_oe_o[9] = i2c_sda_oe_i[1]; + end + // GPIO9 + 2'b11: begin + io_val_o[9] = gpio_val_i[9]; + io_oe_o[9] = gpio_oe_i[9]; + end + default: ; + endcase + end + + // IO10 + always_comb begin + io_val_o[10] = 1'b0; + io_oe_o[10] = 1'b0; + + case (io10_mux) + // GPIO10 + 2'b00: begin + io_val_o[10] = gpio_val_i[10]; + io_oe_o[10] = gpio_oe_i[10]; + end + // SPI_CLK + 2'b01: begin + io_val_o[10] = spi_clk_val_i[0]; + io_oe_o[10] = spi_clk_oe_i[0]; + end + default: begin + io_val_o[10] = gpio_val_i[10]; + io_oe_o[10] = gpio_oe_i[10]; + end + endcase + end + + // IO11 + always_comb begin + io_val_o[11] = 1'b0; + io_oe_o[11] = 1'b0; + + case (io11_mux) + // GPIO11 + 2'b00: begin + io_val_o[11] = gpio_val_i[11]; + io_oe_o[11] = gpio_oe_i[11]; + end + // SPI_SS + 2'b01: begin + io_val_o[11] = spi_ss_val_i[0]; + io_oe_o[11] = spi_ss_oe_i[0]; + end + default: begin + io_val_o[11] = gpio_val_i[11]; + io_oe_o[11] = gpio_oe_i[11]; + end + endcase + end + + // IO12 + always_comb begin + io_val_o[12] = 1'b0; + io_oe_o[12] = 1'b0; + + case (io12_mux) + // GPIO12 + 2'b00: begin + io_val_o[12] = gpio_val_i[12]; + io_oe_o[12] = gpio_oe_i[12]; + end + // SPI_DQ0 + 2'b01: begin + io_val_o[12] = spi_dq_val_i[0][0]; + io_oe_o[12] = spi_dq_oe_i[0][0]; + end + default: begin + io_val_o[12] = gpio_val_i[12]; + io_oe_o[12] = gpio_oe_i[12]; + end + endcase + end + + // IO13 + always_comb begin + io_val_o[13] = 1'b0; + io_oe_o[13] = 1'b0; + + case (io13_mux) + // GPIO13 + 2'b00: begin + io_val_o[13] = gpio_val_i[13]; + io_oe_o[13] = gpio_oe_i[13]; + end + // SPI_DQ1 + 2'b01: begin + io_val_o[13] = spi_dq_val_i[0][1]; + io_oe_o[13] = spi_dq_oe_i[0][1]; + end + default: begin + io_val_o[13] = gpio_val_i[13]; + io_oe_o[13] = gpio_oe_i[13]; + end + endcase + end + + // IO14 + always_comb begin + io_val_o[14] = 1'b0; + io_oe_o[14] = 1'b0; + + case (io14_mux) + // GPIO14 + 2'b00: begin + io_val_o[14] = gpio_val_i[14]; + io_oe_o[14] = gpio_oe_i[14]; + end + // SPI_DQ2 + 2'b01: begin + io_val_o[14] = spi_dq_val_i[0][2]; + io_oe_o[14] = spi_dq_oe_i[0][2]; + end + default: begin + io_val_o[14] = gpio_val_i[14]; + io_oe_o[14] = gpio_oe_i[14]; + end + endcase + end + + // IO15 + always_comb begin + io_val_o[15] = 1'b0; + io_oe_o[15] = 1'b0; + + case (io15_mux) + // GPIO15 + 2'b00: begin + io_val_o[15] = gpio_val_i[15]; + io_oe_o[15] = gpio_oe_i[15]; + end + // SPI_DQ3 + 2'b01: begin + io_val_o[15] = spi_dq_val_i[0][3]; + io_oe_o[15] = spi_dq_oe_i[0][3]; + end + default: begin + io_val_o[15] = gpio_val_i[15]; + io_oe_o[15] = gpio_oe_i[15]; + end + endcase + end + +/////////////////////////////////////////////////////////////////////////////////////////// + + assign gpio_val_o[ 0] = ( io0_mux == 2'b00) ? io_val_i[ 0] : 1'b0; + assign gpio_val_o[ 1] = ( io1_mux == 2'b00) ? io_val_i[ 1] : 1'b0; + assign gpio_val_o[ 2] = ( io2_mux == 2'b00) ? io_val_i[ 2] : 1'b0; + assign gpio_val_o[ 3] = ( io3_mux == 2'b00) ? io_val_i[ 3] : 1'b0; + assign gpio_val_o[ 4] = ( io4_mux == 2'b00) ? io_val_i[ 4] : 1'b0; + assign gpio_val_o[ 5] = ( io5_mux == 2'b00) ? io_val_i[ 5] : 1'b0; + assign gpio_val_o[ 6] = ( io6_mux == 2'b00) ? io_val_i[ 6] : 1'b0; + assign gpio_val_o[ 7] = ( io7_mux == 2'b00) ? io_val_i[ 7] : 1'b0; + assign gpio_val_o[ 8] = ( io8_mux == 2'b00) ? io_val_i[ 8] : 1'b0; + assign gpio_val_o[ 9] = ( io9_mux == 2'b00) ? io_val_i[ 9] : 1'b0; + assign gpio_val_o[10] = (io10_mux == 2'b00) ? io_val_i[10] : 1'b0; + assign gpio_val_o[11] = (io11_mux == 2'b00) ? io_val_i[11] : 1'b0; + assign gpio_val_o[12] = (io12_mux == 2'b00) ? io_val_i[12] : 1'b0; + assign gpio_val_o[13] = (io13_mux == 2'b00) ? io_val_i[13] : 1'b0; + assign gpio_val_o[14] = (io14_mux == 2'b00) ? io_val_i[14] : 1'b0; + assign gpio_val_o[15] = (io15_mux == 2'b00) ? io_val_i[15] : 1'b0; + + assign uart_tx_val_o[0] = (io0_mux == 2'b01) ? io_val_i[0] : + (io3_mux == 2'b01) ? io_val_i[3] : + 1'b0; + assign uart_rx_val_o[0] = (io0_mux == 2'b10) ? io_val_i[0] : + (io3_mux == 2'b10) ? io_val_i[3] : + 1'b0; + assign uart_tx_val_o[1] = (io1_mux == 2'b01) ? io_val_i[1] : + (io4_mux == 2'b01) ? io_val_i[4] : + 1'b0; + assign uart_rx_val_o[1] = (io1_mux == 2'b10) ? io_val_i[1] : + (io4_mux == 2'b10) ? io_val_i[4] : + 1'b0; + assign uart_tx_val_o[2] = (io2_mux == 2'b01) ? io_val_i[2] : + (io5_mux == 2'b01) ? io_val_i[5] : + 1'b0; + assign uart_rx_val_o[2] = (io2_mux == 2'b10) ? io_val_i[2] : + (io5_mux == 2'b10) ? io_val_i[5] : + 1'b0; + + assign i2c_scl_val_o[0] = (io6_mux == 2'b01) ? io_val_i[6] : + (io8_mux == 2'b01) ? io_val_i[8] : + 1'b0; + assign i2c_sda_val_o[0] = (io6_mux == 2'b10) ? io_val_i[6] : + (io8_mux == 2'b10) ? io_val_i[8] : + 1'b0; + assign i2c_scl_val_o[1] = (io7_mux == 2'b01) ? io_val_i[7] : + (io9_mux == 2'b01) ? io_val_i[9] : + 1'b0; + assign i2c_sda_val_o[1] = (io7_mux == 2'b10) ? io_val_i[7] : + (io9_mux == 2'b10) ? io_val_i[9] : + 1'b0; + + assign spi_clk_val_o[0] = (io10_mux == 2'b01) ? io_val_i[10] : 1'b0; + assign spi_ss_val_o[0] = (io11_mux == 2'b01) ? io_val_i[11] : 1'b0; + assign spi_dq_val_o[0][0] = (io12_mux == 2'b01) ? io_val_i[12] : 1'b0; + assign spi_dq_val_o[0][1] = (io13_mux == 2'b01) ? io_val_i[13] : 1'b0; + assign spi_dq_val_o[0][2] = (io14_mux == 2'b01) ? io_val_i[14] : 1'b0; + assign spi_dq_val_o[0][3] = (io15_mux == 2'b01) ? io_val_i[15] : 1'b0; + + pinmux_reg_top u_pinmux_reg_top ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .reg2hw (reg2hw), + .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 diff --git a/rtl/perips/pinmux/pinmux_reg_pkg.sv b/rtl/perips/pinmux/pinmux_reg_pkg.sv new file mode 100644 index 0000000..94b6851 --- /dev/null +++ b/rtl/perips/pinmux/pinmux_reg_pkg.sv @@ -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 +// +// Register Package auto-generated by `reggen` containing data structure + +package pinmux_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 2; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + struct packed { + logic [1:0] q; + } io0_mux; + struct packed { + logic [1:0] q; + } io1_mux; + struct packed { + logic [1:0] q; + } io2_mux; + struct packed { + logic [1:0] q; + } io3_mux; + struct packed { + logic [1:0] q; + } io4_mux; + struct packed { + logic [1:0] q; + } io5_mux; + struct packed { + logic [1:0] q; + } io6_mux; + struct packed { + logic [1:0] q; + } io7_mux; + struct packed { + logic [1:0] q; + } io8_mux; + struct packed { + logic [1:0] q; + } io9_mux; + struct packed { + logic [1:0] q; + } io10_mux; + struct packed { + logic [1:0] q; + } io11_mux; + struct packed { + logic [1:0] q; + } io12_mux; + struct packed { + logic [1:0] q; + } io13_mux; + struct packed { + logic [1:0] q; + } io14_mux; + struct packed { + logic [1:0] q; + } io15_mux; + } pinmux_reg2hw_ctrl_reg_t; + + // Register -> HW type + typedef struct packed { + pinmux_reg2hw_ctrl_reg_t ctrl; // [31:0] + } pinmux_reg2hw_t; + + // Register offsets + parameter logic [BlockAw-1:0] PINMUX_CTRL_OFFSET = 2'h0; + + // Register index + typedef enum int { + PINMUX_CTRL + } pinmux_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] PINMUX_PERMIT [1] = '{ + 4'b1111 // index[0] PINMUX_CTRL + }; + +endpackage + diff --git a/rtl/perips/pinmux/pinmux_reg_top.sv b/rtl/perips/pinmux/pinmux_reg_top.sv new file mode 100644 index 0000000..dae69b0 --- /dev/null +++ b/rtl/perips/pinmux/pinmux_reg_top.sv @@ -0,0 +1,579 @@ +// 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 pinmux_reg_top ( + input logic clk_i, + input logic rst_ni, + + // To HW + output pinmux_reg_pkg::pinmux_reg2hw_t reg2hw, // Write + + 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 pinmux_reg_pkg::* ; + + localparam int AW = 2; + 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: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic ctrl_we; + logic [1:0] ctrl_io0_mux_qs; + logic [1:0] ctrl_io0_mux_wd; + logic [1:0] ctrl_io1_mux_qs; + logic [1:0] ctrl_io1_mux_wd; + logic [1:0] ctrl_io2_mux_qs; + logic [1:0] ctrl_io2_mux_wd; + logic [1:0] ctrl_io3_mux_qs; + logic [1:0] ctrl_io3_mux_wd; + logic [1:0] ctrl_io4_mux_qs; + logic [1:0] ctrl_io4_mux_wd; + logic [1:0] ctrl_io5_mux_qs; + logic [1:0] ctrl_io5_mux_wd; + logic [1:0] ctrl_io6_mux_qs; + logic [1:0] ctrl_io6_mux_wd; + logic [1:0] ctrl_io7_mux_qs; + logic [1:0] ctrl_io7_mux_wd; + logic [1:0] ctrl_io8_mux_qs; + logic [1:0] ctrl_io8_mux_wd; + logic [1:0] ctrl_io9_mux_qs; + logic [1:0] ctrl_io9_mux_wd; + logic [1:0] ctrl_io10_mux_qs; + logic [1:0] ctrl_io10_mux_wd; + logic [1:0] ctrl_io11_mux_qs; + logic [1:0] ctrl_io11_mux_wd; + logic [1:0] ctrl_io12_mux_qs; + logic [1:0] ctrl_io12_mux_wd; + logic [1:0] ctrl_io13_mux_qs; + logic [1:0] ctrl_io13_mux_wd; + logic [1:0] ctrl_io14_mux_qs; + logic [1:0] ctrl_io14_mux_wd; + logic [1:0] ctrl_io15_mux_qs; + logic [1:0] ctrl_io15_mux_wd; + + // Register instances + // R[ctrl]: V(False) + + // F[io0_mux]: 1:0 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io0_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io0_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io0_mux.q), + + // to register interface (read) + .qs (ctrl_io0_mux_qs) + ); + + + // F[io1_mux]: 3:2 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io1_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io1_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io1_mux.q), + + // to register interface (read) + .qs (ctrl_io1_mux_qs) + ); + + + // F[io2_mux]: 5:4 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io2_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io2_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io2_mux.q), + + // to register interface (read) + .qs (ctrl_io2_mux_qs) + ); + + + // F[io3_mux]: 7:6 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io3_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io3_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io3_mux.q), + + // to register interface (read) + .qs (ctrl_io3_mux_qs) + ); + + + // F[io4_mux]: 9:8 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io4_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io4_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io4_mux.q), + + // to register interface (read) + .qs (ctrl_io4_mux_qs) + ); + + + // F[io5_mux]: 11:10 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io5_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io5_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io5_mux.q), + + // to register interface (read) + .qs (ctrl_io5_mux_qs) + ); + + + // F[io6_mux]: 13:12 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io6_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io6_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io6_mux.q), + + // to register interface (read) + .qs (ctrl_io6_mux_qs) + ); + + + // F[io7_mux]: 15:14 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io7_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io7_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io7_mux.q), + + // to register interface (read) + .qs (ctrl_io7_mux_qs) + ); + + + // F[io8_mux]: 17:16 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io8_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io8_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io8_mux.q), + + // to register interface (read) + .qs (ctrl_io8_mux_qs) + ); + + + // F[io9_mux]: 19:18 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io9_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io9_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io9_mux.q), + + // to register interface (read) + .qs (ctrl_io9_mux_qs) + ); + + + // F[io10_mux]: 21:20 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io10_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io10_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io10_mux.q), + + // to register interface (read) + .qs (ctrl_io10_mux_qs) + ); + + + // F[io11_mux]: 23:22 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io11_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io11_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io11_mux.q), + + // to register interface (read) + .qs (ctrl_io11_mux_qs) + ); + + + // F[io12_mux]: 25:24 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io12_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io12_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io12_mux.q), + + // to register interface (read) + .qs (ctrl_io12_mux_qs) + ); + + + // F[io13_mux]: 27:26 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io13_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io13_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io13_mux.q), + + // to register interface (read) + .qs (ctrl_io13_mux_qs) + ); + + + // F[io14_mux]: 29:28 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io14_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io14_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io14_mux.q), + + // to register interface (read) + .qs (ctrl_io14_mux_qs) + ); + + + // F[io15_mux]: 31:30 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_ctrl_io15_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_io15_mux_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ctrl.io15_mux.q), + + // to register interface (read) + .qs (ctrl_io15_mux_qs) + ); + + + logic [0:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == PINMUX_CTRL_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] & (|(PINMUX_PERMIT[0] & ~reg_be))))); + end + + assign ctrl_we = addr_hit[0] & reg_we & !reg_error; + + assign ctrl_io0_mux_wd = reg_wdata[1:0]; + + assign ctrl_io1_mux_wd = reg_wdata[3:2]; + + assign ctrl_io2_mux_wd = reg_wdata[5:4]; + + assign ctrl_io3_mux_wd = reg_wdata[7:6]; + + assign ctrl_io4_mux_wd = reg_wdata[9:8]; + + assign ctrl_io5_mux_wd = reg_wdata[11:10]; + + assign ctrl_io6_mux_wd = reg_wdata[13:12]; + + assign ctrl_io7_mux_wd = reg_wdata[15:14]; + + assign ctrl_io8_mux_wd = reg_wdata[17:16]; + + assign ctrl_io9_mux_wd = reg_wdata[19:18]; + + assign ctrl_io10_mux_wd = reg_wdata[21:20]; + + assign ctrl_io11_mux_wd = reg_wdata[23:22]; + + assign ctrl_io12_mux_wd = reg_wdata[25:24]; + + assign ctrl_io13_mux_wd = reg_wdata[27:26]; + + assign ctrl_io14_mux_wd = reg_wdata[29:28]; + + assign ctrl_io15_mux_wd = reg_wdata[31:30]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[1:0] = ctrl_io0_mux_qs; + reg_rdata_next[3:2] = ctrl_io1_mux_qs; + reg_rdata_next[5:4] = ctrl_io2_mux_qs; + reg_rdata_next[7:6] = ctrl_io3_mux_qs; + reg_rdata_next[9:8] = ctrl_io4_mux_qs; + reg_rdata_next[11:10] = ctrl_io5_mux_qs; + reg_rdata_next[13:12] = ctrl_io6_mux_qs; + reg_rdata_next[15:14] = ctrl_io7_mux_qs; + reg_rdata_next[17:16] = ctrl_io8_mux_qs; + reg_rdata_next[19:18] = ctrl_io9_mux_qs; + reg_rdata_next[21:20] = ctrl_io10_mux_qs; + reg_rdata_next[23:22] = ctrl_io11_mux_qs; + reg_rdata_next[25:24] = ctrl_io12_mux_qs; + reg_rdata_next[27:26] = ctrl_io13_mux_qs; + reg_rdata_next[29:28] = ctrl_io14_mux_qs; + reg_rdata_next[31:30] = ctrl_io15_mux_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 diff --git a/rtl/perips/pinmux/pinmux_top.sv b/rtl/perips/pinmux/pinmux_top.sv new file mode 100644 index 0000000..bec99c2 --- /dev/null +++ b/rtl/perips/pinmux/pinmux_top.sv @@ -0,0 +1,136 @@ + /* + 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 pinmux_top #( + parameter int GPIO_NUM = 16, + parameter int I2C_NUM = 2, + parameter int UART_NUM = 3, + parameter int SPI_NUM = 1 + )( + input logic clk_i, + input logic rst_ni, + // 16路GPIO + input logic [GPIO_NUM-1:0] gpio_oe_i, + input logic [GPIO_NUM-1:0] gpio_val_i, + output logic [GPIO_NUM-1:0] gpio_val_o, + // 2路I2C + input logic [I2C_NUM-1:0] i2c_sda_oe_i, + input logic [I2C_NUM-1:0] i2c_sda_val_i, + output logic [I2C_NUM-1:0] i2c_sda_val_o, + input logic [I2C_NUM-1:0] i2c_scl_oe_i, + input logic [I2C_NUM-1:0] i2c_scl_val_i, + output logic [I2C_NUM-1:0] i2c_scl_val_o, + // 3路UART + input logic [UART_NUM-1:0] uart_tx_oe_i, + input logic [UART_NUM-1:0] uart_tx_val_i, + output logic [UART_NUM-1:0] uart_tx_val_o, + input logic [UART_NUM-1:0] uart_rx_oe_i, + input logic [UART_NUM-1:0] uart_rx_val_i, + output logic [UART_NUM-1:0] uart_rx_val_o, + // 1路SPI + input logic [SPI_NUM-1:0] spi_clk_oe_i, + input logic [SPI_NUM-1:0] spi_clk_val_i, + output logic [SPI_NUM-1:0] spi_clk_val_o, + input logic [SPI_NUM-1:0] spi_ss_oe_i, + input logic [SPI_NUM-1:0] spi_ss_val_i, + output logic [SPI_NUM-1:0] spi_ss_val_o, + input logic [ 3:0] spi_dq_oe_i [SPI_NUM-1:0], + input logic [ 3:0] spi_dq_val_i[SPI_NUM-1:0], + output logic [ 3:0] spi_dq_val_o[SPI_NUM-1:0], + + input logic [GPIO_NUM-1:0] io_val_i, + output logic [GPIO_NUM-1:0] io_val_o, + output logic [GPIO_NUM-1:0] io_oe_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 gnt_o, + output logic rvalid_o, + output logic [31:0] data_o + ); + + logic re; + logic we; + logic [31:0] addr; + logic [31:0] reg_rdata; + + assign gnt_o = req_i; + + // 读信号 + assign re = req_i & (!we_i); + // 写信号 + assign we = req_i & we_i; + // 去掉基地址 + assign addr = {16'h0, addr_i[15:0]}; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rvalid_o <= '0; + data_o <= '0; + end else begin + rvalid_o <= req_i; + data_o <= reg_rdata; + end + end + + pinmux_core #( + .GPIO_NUM(GPIO_NUM), + .I2C_NUM(I2C_NUM), + .UART_NUM(UART_NUM), + .SPI_NUM(SPI_NUM) + ) u_pinmux_core ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .gpio_oe_i, + .gpio_val_i, + .gpio_val_o, + .i2c_sda_oe_i, + .i2c_sda_val_i, + .i2c_sda_val_o, + .i2c_scl_oe_i, + .i2c_scl_val_i, + .i2c_scl_val_o, + .uart_tx_oe_i, + .uart_tx_val_i, + .uart_tx_val_o, + .uart_rx_oe_i, + .uart_rx_val_i, + .uart_rx_val_o, + .spi_clk_oe_i, + .spi_clk_val_i, + .spi_clk_val_o, + .spi_ss_oe_i, + .spi_ss_val_i, + .spi_ss_val_o, + .spi_dq_oe_i, + .spi_dq_val_i, + .spi_dq_val_o, + .io_val_i, + .io_val_o, + .io_oe_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) + ); + +endmodule