From f3a9d8ac703e49b1fa32333cf961275432efcb40 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Wed, 1 Apr 2015 01:22:19 +0100 Subject: [PATCH] rtl/keynsham: initial support for GPIO. The Keynsham SoC on the DE0-CV has GPIO pins connected to the 7-segment displays, push buttons and switches. The DE0-nano does not currently have any GPIO pins connected. --- README.md | 5 +- config/de0-cv.yaml | 20 ++++++ config/regmaps/gpio.yaml | 14 +++++ fpga/.gitignore | 1 + fpga/de0-cv/keynsham-soc.qsf | 72 ++++++++++++++++++++++ fpga/de0-cv/keynsham-soc.sdc | 4 ++ rtl/fpga/de0cv/toplevel.v | 6 +- rtl/keynsham/keynsham_gpio.v | 92 ++++++++++++++++++++++++++++ rtl/keynsham/keynsham_soc.v | 41 +++++++++++-- verif/CMakeLists.txt | 2 +- verif/icarus/oldland.cf | 1 + verif/verilator/CMakeLists.txt | 1 + verif/verilator/verilator_toplevel.v | 11 ++++ 13 files changed, 261 insertions(+), 9 deletions(-) create mode 100644 config/regmaps/gpio.yaml create mode 100644 rtl/keynsham/keynsham_gpio.v diff --git a/README.md b/README.md index 5ffaa80..ac74ad4 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,10 @@ Keynsham is a SoC using Oldland as the core and has a number of peripherals: - Interrupt controller. - UART. - SPI master. + - GPIO. There is a C model along with Icarus and Verilator RTL simulations. The -Keynsham SoC can be synthesized to run on a Terasic DE0 Nano. There are ports -of binutils, gcc and u-boot available. +Keynsham SoC can be synthesized to run on a Terasic DE0 Nano or DE0-CV. There +are ports of binutils, gcc and u-boot available. For documentation see the [Oldland CPU site](http://jamieiles.github.io/oldland-cpu/) diff --git a/config/de0-cv.yaml b/config/de0-cv.yaml index 9aa3e99..85f94b9 100644 --- a/config/de0-cv.yaml +++ b/config/de0-cv.yaml @@ -66,6 +66,26 @@ address: "0x80004000", size: "0x00004000", regmap: spimaster + }, + # Two banks of GPIO: + # - bank 1 at offset 16 + # - [31:28]: push buttons + # - [27:26]: no connection + # - [25:16]: switches + # - [15:15]: no connection + # - [14:8]: 7-seg 5 + # - [7:7]: no connection + # - [7:0]: 7-seg 4 + # - bank 0 at offset 0 + # - [30:24]: 7-seg 3 + # - [22:16]: 7-seg 2 + # - [14:8]: 7-seg 1 + # - [6:0]: 7-seg 0 + { + name: gpio, + address: "0x80008000", + size: "0x00001000", + regmap: gpio } ] } diff --git a/config/regmaps/gpio.yaml b/config/regmaps/gpio.yaml new file mode 100644 index 0000000..a6bed78 --- /dev/null +++ b/config/regmaps/gpio.yaml @@ -0,0 +1,14 @@ +{ + gpio_value: { + offset: 0 + }, + gpio_output_enable: { + offset: 4 + }, + gpio_set: { + offset: 8 + }, + gpio_clear: { + offset: 12 + }, +} diff --git a/fpga/.gitignore b/fpga/.gitignore index ad8b43f..cb31def 100644 --- a/fpga/.gitignore +++ b/fpga/.gitignore @@ -7,3 +7,4 @@ */spimaster_defines.v */timer_defines.v */uart_defines.v +*/gpio_defines.v diff --git a/fpga/de0-cv/keynsham-soc.qsf b/fpga/de0-cv/keynsham-soc.qsf index 272155d..d14282e 100644 --- a/fpga/de0-cv/keynsham-soc.qsf +++ b/fpga/de0-cv/keynsham-soc.qsf @@ -105,6 +105,73 @@ set_location_assignment PIN_R22 -to spi_clk2 set_location_assignment PIN_T22 -to spi_mosi2 set_location_assignment PIN_P22 -to rst_in_n +# Hex 0 +set_location_assignment PIN_U21 -to gpio[0] +set_location_assignment PIN_V21 -to gpio[1] +set_location_assignment PIN_W22 -to gpio[2] +set_location_assignment PIN_W21 -to gpio[3] +set_location_assignment PIN_Y22 -to gpio[4] +set_location_assignment PIN_Y21 -to gpio[5] +set_location_assignment PIN_AA22 -to gpio[6] +# Hex 1 +set_location_assignment PIN_AA20 -to gpio[8] +set_location_assignment PIN_AB20 -to gpio[9] +set_location_assignment PIN_AA19 -to gpio[10] +set_location_assignment PIN_AA18 -to gpio[11] +set_location_assignment PIN_AB18 -to gpio[12] +set_location_assignment PIN_AA17 -to gpio[13] +set_location_assignment PIN_U22 -to gpio[14] +# Hex 2 +set_location_assignment PIN_Y19 -to gpio[16] +set_location_assignment PIN_AB17 -to gpio[17] +set_location_assignment PIN_AA10 -to gpio[18] +set_location_assignment PIN_Y14 -to gpio[19] +set_location_assignment PIN_V14 -to gpio[20] +set_location_assignment PIN_AB22 -to gpio[21] +set_location_assignment PIN_AB21 -to gpio[22] +# Hex 3 +set_location_assignment PIN_Y16 -to gpio[24] +set_location_assignment PIN_W16 -to gpio[25] +set_location_assignment PIN_Y17 -to gpio[26] +set_location_assignment PIN_V16 -to gpio[27] +set_location_assignment PIN_U17 -to gpio[28] +set_location_assignment PIN_V18 -to gpio[29] +set_location_assignment PIN_V19 -to gpio[30] +# Hex 4 +set_location_assignment PIN_U20 -to gpio[32] +set_location_assignment PIN_Y20 -to gpio[33] +set_location_assignment PIN_V20 -to gpio[34] +set_location_assignment PIN_U16 -to gpio[35] +set_location_assignment PIN_U15 -to gpio[36] +set_location_assignment PIN_Y15 -to gpio[37] +set_location_assignment PIN_P9 -to gpio[38] +# Hex 5 +set_location_assignment PIN_N9 -to gpio[40] +set_location_assignment PIN_M8 -to gpio[41] +set_location_assignment PIN_T14 -to gpio[42] +set_location_assignment PIN_P14 -to gpio[43] +set_location_assignment PIN_C1 -to gpio[44] +set_location_assignment PIN_C2 -to gpio[45] +set_location_assignment PIN_W19 -to gpio[46] + +# Push buttons +set_location_assignment PIN_U7 -to gpio[60] +set_location_assignment PIN_W9 -to gpio[61] +set_location_assignment PIN_M7 -to gpio[62] +set_location_assignment PIN_M6 -to gpio[63] + +# Switches +set_location_assignment PIN_U13 -to gpio[48] +set_location_assignment PIN_V13 -to gpio[49] +set_location_assignment PIN_T13 -to gpio[50] +set_location_assignment PIN_T12 -to gpio[51] +set_location_assignment PIN_AA15 -to gpio[52] +set_location_assignment PIN_AB15 -to gpio[53] +set_location_assignment PIN_AA14 -to gpio[54] +set_location_assignment PIN_AA13 -to gpio[55] +set_location_assignment PIN_AB13 -to gpio[56] +set_location_assignment PIN_AB12 -to gpio[57] + # Classic Timing Assignments # ========================== set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 @@ -191,7 +258,9 @@ set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to s_banksel # ================== set_instance_assignment -name CURRENT_STRENGTH_NEW 2MA -to uart_tx set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to uart_rx +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to gpio[*] set_instance_assignment -name CURRENT_STRENGTH_NEW 2MA -to s_* +set_instance_assignment -name CURRENT_STRENGTH_NEW 2MA -to gpio[*] set_instance_assignment -name CURRENT_STRENGTH_NEW 2MA -to sdr_clk set_instance_assignment -name CURRENT_STRENGTH_NEW 2MA -to running set_instance_assignment -name CURRENT_STRENGTH_NEW 2MA -to spi_cs0_active @@ -231,6 +300,7 @@ set_global_assignment -name VERILOG_FILE ../../rtl/sdram/rtl/counter.v set_global_assignment -name VERILOG_FILE ../../rtl/keynsham/keynsham_sdram.v set_global_assignment -name VERILOG_FILE ../../rtl/keynsham/keynsham_uart.v set_global_assignment -name VERILOG_FILE ../../rtl/keynsham/keynsham_spimaster.v +set_global_assignment -name VERILOG_FILE ../../rtl/keynsham/keynsham_gpio.v set_global_assignment -name VERILOG_FILE ../../rtl/keynsham/keynsham_ram.v set_global_assignment -name VERILOG_FILE ../../rtl/keynsham/keynsham_irq.v set_global_assignment -name VERILOG_FILE ../../rtl/keynsham/keynsham_timer.v @@ -276,4 +346,6 @@ set_instance_assignment -name MATCH_PLL_COMPENSATION_CLOCK ON -to "sys_pll:pll|o set_global_assignment -name QIP_FILE ram.qip + + set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/fpga/de0-cv/keynsham-soc.sdc b/fpga/de0-cv/keynsham-soc.sdc index 3f5293d..37c2c02 100644 --- a/fpga/de0-cv/keynsham-soc.sdc +++ b/fpga/de0-cv/keynsham-soc.sdc @@ -80,6 +80,10 @@ set_multicycle_path -setup -end -from sdram_clk -to $sys_clk 2 set_false_path -from [get_ports uart_rx] set_false_path -to [get_ports uart_tx] +# GPI +set_false_path -from [get_ports gpio[*]] +set_false_path -to [get_ports gpio[*]] + # Status LEDs set_false_path -to [get_ports running] set_false_path -to [get_ports spi_cs0_active] diff --git a/rtl/fpga/de0cv/toplevel.v b/rtl/fpga/de0cv/toplevel.v index 23dc3b7..b3b1aa9 100644 --- a/rtl/fpga/de0cv/toplevel.v +++ b/rtl/fpga/de0cv/toplevel.v @@ -29,7 +29,8 @@ module toplevel(input wire clk, output wire spi_mosi2, input wire spi_miso2, /* Ethernet control */ - output reg ethernet_reset_n); + output reg ethernet_reset_n, + inout wire [63:0] gpio); wire sys_clk; wire dbg_clk; @@ -102,7 +103,8 @@ keynsham_soc #(.spi_num_cs(2)) .miso(spi_miso), .mosi(spi_mosi), .sclk(spi_clk), - .spi_ncs(spi_ncs)); + .spi_ncs(spi_ncs), + .gpio(gpio)); /* * Make the effects of running a little more visible - if we run for at least diff --git a/rtl/keynsham/keynsham_gpio.v b/rtl/keynsham/keynsham_gpio.v new file mode 100644 index 0000000..9307f7f --- /dev/null +++ b/rtl/keynsham/keynsham_gpio.v @@ -0,0 +1,92 @@ +`ifdef GPIO_ADDRESS +module keynsham_gpio(input wire clk, + /* Data bus. */ + input wire bus_access, + output wire bus_cs, + input wire [29:0] bus_addr, + input wire [31:0] bus_wr_val, + input wire bus_wr_en, + input wire [3:0] bus_bytesel, + output reg bus_error, + output reg bus_ack, + output wire [31:0] bus_data, + /* GPIO */ + inout wire [ngpio - 1:0] gpio); + +parameter num_banks = 2; +parameter bus_address = 32'h0; +parameter bus_size = 32'h0; +localparam ngpio = num_banks * 32; + +wire banksel = bus_addr[2]; +wire [1:0] regsel = bus_addr[1:0]; +wire access_value = {28'b0, regsel, 2'b00} == `GPIO_VALUE_REG_OFFS; +wire access_oe = {28'b0, regsel, 2'b00} == `GPIO_OUTPUT_ENABLE_REG_OFFS; +wire access_set = {28'b0, regsel, 2'b00} == `GPIO_SET_REG_OFFS; +wire access_clr = {28'b0, regsel, 2'b00} == `GPIO_CLEAR_REG_OFFS; + +reg [31:0] data = 32'b0; +assign bus_data = bus_ack ? data : 32'b0; + +cs_gen #(.address(bus_address), .size(bus_size)) + d_cs_gen(.bus_addr(bus_addr), .cs(bus_cs)); + +reg [ngpio - 1:0] gpio_internal = {ngpio{1'bz}}; +assign gpio = gpio_internal; + +reg [31:0] outputs[num_banks - 1:0]; +reg [31:0] oe[num_banks - 1:0]; +reg [$clog2(ngpio):0] pin = {$clog2(ngpio) + 1{1'b0}}; +reg [31:0] input_banks[num_banks - 1:0]; + +initial begin + bus_error = 1'b0; + bus_ack = 1'b0; + + /* verilator lint_off WIDTH */ + for (pin = 0; pin < ngpio; pin = pin + 1'b1) begin + gpio_internal[pin] = 1'bz; + outputs[pin / 32][pin % 32] = 1'b0; + oe[pin / 32][pin % 32] = 1'b0; + input_banks[pin / 32][pin % 32] = 1'b0; + end + /* verilator lint_on WIDTH */ +end + +always @(*) begin + /* verilator lint_off WIDTH */ + for (pin = 0; pin < ngpio; pin = pin + 1'b1) begin + gpio_internal[pin] = oe[pin / 32][pin % 32] ? outputs[pin / 32][pin % 32] : 1'bz; + input_banks[pin / 32][pin % 32] = gpio[pin]; + end + /* verilator lint_on WIDTH */ +end + +always @(*) begin + if (access_value) + data = (outputs[banksel] & oe[banksel]) | (input_banks[banksel] & ~oe[banksel]); + else if (access_oe) + data = oe[banksel]; + else + data = 32'b0; +end + +always @(posedge clk) begin + if (bus_access && bus_cs && bus_wr_en && bus_bytesel == 4'hf) begin + if (access_oe) + oe[banksel] <= bus_wr_val; + else if (access_set) + outputs[banksel] <= outputs[banksel] | bus_wr_val; + else if (access_clr) + outputs[banksel] <= outputs[banksel] & ~bus_wr_val; + end +end + +always @(posedge clk) + bus_ack <= bus_access & bus_cs; + +always @(posedge clk) + bus_error <= bus_access & bus_cs & (bus_bytesel != 4'hf); + +endmodule +`endif /* GPIO_ADDRESS */ diff --git a/rtl/keynsham/keynsham_soc.v b/rtl/keynsham/keynsham_soc.v index 186d108..7401289 100644 --- a/rtl/keynsham/keynsham_soc.v +++ b/rtl/keynsham/keynsham_soc.v @@ -31,6 +31,9 @@ module keynsham_soc(input wire clk, input wire dbg_wr_en, input wire dbg_req, output wire dbg_ack, +`ifdef GPIO_ADDRESS + inout wire [63:0] gpio, +`endif /* SPI bus. */ input wire miso, output wire mosi, @@ -87,6 +90,10 @@ wire [31:0] i_sdram_data; wire i_sdram_ack; wire i_sdram_error; +wire [31:0] gpio_data; +wire gpio_ack; +wire gpio_error; + wire [31:0] cpu_d_out; /* @@ -109,23 +116,26 @@ wire uart_cs; wire irq_cs; wire timer_cs; wire spimaster_cs; +wire gpio_cs; wire d_default_cs = ~(ram_cs | rom_cs | d_sdram_cs | d_sdram_ctrl_cs | uart_cs | irq_cs | - timer_cs | spimaster_cs); + timer_cs | spimaster_cs | gpio_cs); wire i_default_cs = ~(ram_i_cs | rom_i_cs | i_sdram_cs); wire d_ack = uart_ack | ram_ack | d_sdram_ack | rom_ack | irq_ack | - timer_ack | d_default_ack | spimaster_ack; + timer_ack | d_default_ack | spimaster_ack | gpio_ack; wire d_error = uart_error | d_sdram_error | irq_error | - timer_error | d_default_error | spimaster_error; + timer_error | d_default_error | spimaster_error | + gpio_error; wire i_access; wire i_ack = i_ram_ack | i_rom_ack | i_default_ack | i_sdram_ack; wire i_error = i_default_error | i_sdram_error; assign d_data = ram_data | uart_data | d_sdram_data | rom_data | - irq_data | timer_data | d_wr_val | spimaster_data; + irq_data | timer_data | d_wr_val | spimaster_data | + gpio_data; assign i_data = i_ram_data | i_rom_data | i_sdram_data; keynsham_ram #(.bus_address(`RAM_ADDRESS), @@ -257,6 +267,29 @@ keynsham_spimaster #(.bus_address(`SPIMASTER_ADDRESS), .sclk(sclk), .ncs(spi_ncs)); +`ifdef GPIO_ADDRESS +keynsham_gpio #(.bus_address(`GPIO_ADDRESS), + .bus_size(`GPIO_SIZE), + .num_banks(2)) + gpioinst(.clk(clk), + .bus_access(d_access), + .bus_cs(gpio_cs), + .bus_addr(d_addr), + .bus_wr_val(d_data), + .bus_wr_en(d_wr_en), + .bus_bytesel(d_bytesel), + .bus_error(gpio_error), + .bus_ack(gpio_ack), + .bus_data(gpio_data), + .gpio(gpio)); + +`else +assign gpio_data = 32'b0; +assign gpio_ack = 1'b0; +assign gpio_error = 1'b0; +assign gpio_cs = 1'b0; +`endif + oldland_cpu #(.icache_size(`ICACHE_SIZE), .icache_line_size(`ICACHE_LINE_SIZE), .icache_num_ways(`ICACHE_NUM_WAYS), diff --git a/verif/CMakeLists.txt b/verif/CMakeLists.txt index bfdaad6..1e3a36a 100644 --- a/verif/CMakeLists.txt +++ b/verif/CMakeLists.txt @@ -33,7 +33,7 @@ add_custom_target(generate add_custom_target(lint ALL DEPENDS generate - COMMAND verilator -Wfuture-PINCONNECTEMPTY --lint-only ${VERILATOR_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR} ${VERILATOR_INCLUDES} -D__ICARUS__ oldland_defines.v ${CMAKE_CURRENT_BINARY_DIR}/../config/keynsham_defines.v ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/keynsham/keynsham_soc.v) + COMMAND verilator -Wfuture-PINCONNECTEMPTY -Wfuture-PINNOCONNECT --lint-only ${VERILATOR_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR} ${VERILATOR_INCLUDES} -D__ICARUS__ oldland_defines.v ${CMAKE_CURRENT_BINARY_DIR}/../config/keynsham_defines.v ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/keynsham/keynsham_soc.v) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/decode.hex DESTINATION lib) INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/oldland-rtlsim DESTINATION bin) diff --git a/verif/icarus/oldland.cf b/verif/icarus/oldland.cf index 8bc20da..f702075 100644 --- a/verif/icarus/oldland.cf +++ b/verif/icarus/oldland.cf @@ -17,6 +17,7 @@ cpu_tb.v ../../rtl/keynsham/keynsham_soc.v ../../rtl/keynsham/keynsham_uart.v ../../rtl/keynsham/keynsham_spimaster.v +../../rtl/keynsham/keynsham_gpio.v ../../rtl/keynsham/keynsham_irq.v ../../rtl/keynsham/keynsham_timer.v ../../rtl/keynsham/keynsham_timer_block.v diff --git a/verif/verilator/CMakeLists.txt b/verif/verilator/CMakeLists.txt index 132515b..faf9a17 100644 --- a/verif/verilator/CMakeLists.txt +++ b/verif/verilator/CMakeLists.txt @@ -7,6 +7,7 @@ option(TRACE_VERILATOR "Enable tracing in verilator model" OFF) set(VERILATOR_FLAGS --cc -DSIMULATION=1 -DUSE_DEBUG_UART=1 -Wfuture-PINCONNECTEMPTY + -Wfuture-PINNOCONNECT -DOLDLAND_ROM_PATH=\\\"${CMAKE_INSTALL_PREFIX}/lib/\\\") if(TRACE_VERILATOR) diff --git a/verif/verilator/verilator_toplevel.v b/verif/verilator/verilator_toplevel.v index a93fc5e..27d3442 100644 --- a/verif/verilator/verilator_toplevel.v +++ b/verif/verilator/verilator_toplevel.v @@ -1,3 +1,5 @@ +`include "keynsham_defines.v" + module verilator_toplevel(input wire clk /*verilator public*/, input wire dbg_clk /*verilator public*/); @@ -31,6 +33,12 @@ wire [`NUM_SPI_CS - 1:0] spi_ncs; wire running; +`ifdef GPIO_ADDRESS +/* verilator lint_off UNUSED */ +wire [63:0] gpio; +/* verilator lint_on UNUSED */ +`endif + keynsham_soc #(.spi_num_cs(`NUM_SPI_CS)) soc(.clk(clk), .rst_req(1'b0), @@ -56,6 +64,9 @@ keynsham_soc #(.spi_num_cs(`NUM_SPI_CS)) .mosi(mosi), .sclk(sclk), .spi_ncs(spi_ncs), +`ifdef GPIO_ADDRESS + .gpio(gpio), +`endif .running(running)); debug_controller dbg(.clk(dbg_clk),