diff --git a/Bender.yml b/Bender.yml index 7055ceaf..c5cb73ed 100644 --- a/Bender.yml +++ b/Bender.yml @@ -68,6 +68,14 @@ sources: - xilinx/hw/croc_xilinx.sv - xilinx/hw/fan_ctrl.sv + - target: gatemate + files: + - nextpnr/gatemate_dev/src/croc_gm.sv + + - target: ecp5 + files: + - nextpnr/orangecrab/src/croc_ecp5.sv + vendor_package: ################################# # commonly used building blocks # diff --git a/nextpnr/gatemate_dev/.gitignore b/nextpnr/gatemate_dev/.gitignore new file mode 100644 index 00000000..810f8777 --- /dev/null +++ b/nextpnr/gatemate_dev/.gitignore @@ -0,0 +1,2 @@ +out +*.flist diff --git a/nextpnr/gatemate_dev/scripts/gen_bitstream.sh b/nextpnr/gatemate_dev/scripts/gen_bitstream.sh new file mode 100644 index 00000000..8a60a227 --- /dev/null +++ b/nextpnr/gatemate_dev/scripts/gen_bitstream.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# Copyright (c) 2025 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Authors: +# - Thomas Benz + +# prepare flist +bender script flist-plus \ + -t gatemate \ + -t synthesis \ + -D COMMON_CELLS_ASSERTS_OFF=1 \ + -D SYNTHESIS=1 \ + -D VERILATOR=1 \ + > croc_gm.flist + +# run synthesis +mkdir out +yosys -s scripts/yosys.ys + +# run PnR for gatemate dev board in typical conditions. use router 2 as router 1 does not converge +nextpnr-himbaechel \ + --device CCGM1A1 \ + --json out/croc_yosys_gm.json \ + --vopt time_mode=2 \ + --vopt out=out/croc_yosys_gm.config \ + --vopt ccf=src/croc_gm.ccf \ + --router router2 + +# create binary bitstream +gmpack out/croc_yosys_gm.config out/croc_yosys_gm.bit diff --git a/nextpnr/gatemate_dev/scripts/yosys.ys b/nextpnr/gatemate_dev/scripts/yosys.ys new file mode 100644 index 00000000..3e2e6fda --- /dev/null +++ b/nextpnr/gatemate_dev/scripts/yosys.ys @@ -0,0 +1,14 @@ +# Copyright (c) 2025 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Authors: +# - Thomas Benz + +plugin -i slang.so +read_slang --top croc_gm -F croc_gm.flist --compat-mode --keep-hierarchy --allow-use-before-declare --ignore-unknown-modules + +synth_gatemate -luttree -nomx8 -top croc_gm + +write_verilog out/croc_yosys_gm.v +write_json out/croc_yosys_gm.json diff --git a/nextpnr/gatemate_dev/src/croc_gm.ccf b/nextpnr/gatemate_dev/src/croc_gm.ccf new file mode 100644 index 00000000..4ac0f0b2 --- /dev/null +++ b/nextpnr/gatemate_dev/src/croc_gm.ccf @@ -0,0 +1,24 @@ +# Copyright (c) 2025 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Authors: +# - Thomas Benz + +# Sample constraints file for the gatemate dev board + +Net "pad_clk_i" Loc = "IO_SB_A8" | SCHMITT_TRIGGER=true; +Net "pad_button_i" Loc = "IO_EB_B0"; # SW3 +Net "pad_status_o" Loc = "IO_EB_B1"; # D1 + +Net "pad_jtag_tck_i" Loc = "IO_NB_A0"; # PMODA IO1 +Net "pad_jtag_tdi_i" Loc = "IO_NB_B0"; # PMODA IO2 +Net "pad_jtag_tdo_o" Loc = "IO_NB_A1"; # PMODA IO3 +Net "pad_jtag_tms_i" Loc = "IO_NB_B1"; # PMODA IO4 + +Net "pad_uart_rx_i" Loc = "IO_NB_A4"; # PMODB IO1 +Net "pad_uart_tx_o" Loc = "IO_NB_B4"; # PMODB IO2 + +Net "pad_gpio_0_io" Loc = "IO_EB_B2"; # D2 +Net "pad_gpio_1_io" Loc = "IO_EB_B3"; # D3 +Net "pad_gpio_2_io" Loc = "IO_EB_B4"; # D4 diff --git a/nextpnr/gatemate_dev/src/croc_gm.sv b/nextpnr/gatemate_dev/src/croc_gm.sv new file mode 100644 index 00000000..c3202ce0 --- /dev/null +++ b/nextpnr/gatemate_dev/src/croc_gm.sv @@ -0,0 +1,71 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Authors: +// - Thomas Benz + +module croc_gm ( + input logic pad_clk_i, + input logic pad_button_i, + output logic pad_status_o, + + input logic pad_jtag_tck_i, + input logic pad_jtag_tdi_i, + output logic pad_jtag_tdo_o, + input logic pad_jtag_tms_i, + + input logic pad_uart_rx_i, + output logic pad_uart_tx_o, + + inout logic pad_gpio_0_io, + inout logic pad_gpio_1_io, + inout logic pad_gpio_2_io +); + + + // frequency reduction + logic [22:0] count_d, count_q; + always_ff @(posedge pad_clk_i) begin : proc_counter + count_q <= count_d; + end + assign count_d = count_q + 1; + + // bidir pad driver + logic [2:0] gpio_i; + logic [2:0] gpio_o; + logic [2:0] gpio_out_en_o; + + assign gpio_i[0] = pad_gpio_0_io; + assign gpio_i[1] = pad_gpio_1_io; + assign gpio_i[2] = pad_gpio_2_io; + assign pad_gpio_0_io = gpio_out_en_o[0] ? ~gpio_o[0] : 1'bZ; + assign pad_gpio_1_io = gpio_out_en_o[1] ? ~gpio_o[1] : 1'bZ; + assign pad_gpio_2_io = gpio_out_en_o[2] ? ~gpio_o[2] : 1'bZ; + + croc_soc #( + .GpioCount( 3 ) + ) + i_croc_soc ( + .clk_i ( count_q[0] ), + .rst_ni ( pad_button_i ), + .ref_clk_i ( count_q[9] ), + .testmode_i ( 1'b0 ), + .fetch_en_i ( 1'b1 ), + .status_o ( pad_status_o ), + + .jtag_tck_i ( pad_jtag_tck_i ), + .jtag_tdi_i ( pad_jtag_tdi_i ), + .jtag_tdo_o ( pad_jtag_tdo_o ), + .jtag_tms_i ( pad_jtag_tms_i ), + .jtag_trst_ni ( 1'b1 ), + + .uart_rx_i ( pad_uart_rx_i ), + .uart_tx_o ( pad_uart_tx_o ), + + .gpio_i ( gpio_i ), + .gpio_o ( gpio_o ), + .gpio_out_en_o ( gpio_out_en_o ) + ); + +endmodule diff --git a/nextpnr/orangecrab/.gitignore b/nextpnr/orangecrab/.gitignore new file mode 100644 index 00000000..810f8777 --- /dev/null +++ b/nextpnr/orangecrab/.gitignore @@ -0,0 +1,2 @@ +out +*.flist diff --git a/nextpnr/orangecrab/scripts/gen_bitstream.sh b/nextpnr/orangecrab/scripts/gen_bitstream.sh new file mode 100644 index 00000000..6d7bac78 --- /dev/null +++ b/nextpnr/orangecrab/scripts/gen_bitstream.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# Copyright (c) 2025 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Authors: +# - Thomas Benz + +# prepare flist +bender script flist-plus \ + -t ecp5 \ + -t synthesis \ + -D COMMON_CELLS_ASSERTS_OFF=1 \ + -D SYNTHESIS=1 \ + -D VERILATOR=1 \ + > croc_ecp5.flist + +# run synthesis +mkdir out +yosys -s scripts/yosys.ys + +# PnR for the OrangeCrab FPGA +nextpnr-ecp5 \ + --85k \ + --package CSFBGA285 \ + --json out/croc_yosys_ecp5.json \ + --textcfg out/croc_yosys_ecp5.config + +# create binary bitstream +ecppack out/croc_yosys_ecp5.config out/croc_yosys_ecp5.bit diff --git a/nextpnr/orangecrab/scripts/yosys.ys b/nextpnr/orangecrab/scripts/yosys.ys new file mode 100644 index 00000000..7e0d8c6b --- /dev/null +++ b/nextpnr/orangecrab/scripts/yosys.ys @@ -0,0 +1,17 @@ +# Copyright (c) 2025 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Authors: +# - Thomas Benz + +# read IO module first, as yosys-slang will not know Trellis_IO +read_verilog -sv src/croc_ecp5_io.sv + +plugin -i slang.so +read_slang --top croc_ecp5 -F croc_ecp5.flist --compat-mode --keep-hierarchy --allow-use-before-declare --ignore-unknown-modules + +synth_ecp5 -top croc_ecp5 + +write_verilog out/croc_yosys_ecp5.v +write_json out/croc_yosys_ecp5.json diff --git a/nextpnr/orangecrab/src/croc_ecp5.sv b/nextpnr/orangecrab/src/croc_ecp5.sv new file mode 100644 index 00000000..2c433064 --- /dev/null +++ b/nextpnr/orangecrab/src/croc_ecp5.sv @@ -0,0 +1,97 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Authors: +// - Thomas Benz + +module croc_ecp5 ( + input logic pad_clk_48_i, + input logic pad_usr_btn_i, + output logic pad_status_o, + + input logic pad_jtag_tck_i, + input logic pad_jtag_tdi_i, + output logic pad_jtag_tdo_o, + input logic pad_jtag_tms_i, + + input logic pad_uart_rx_i, + output logic pad_uart_tx_o, + + inout logic [2:0] pad_gpio_io +); + + logic clk_48_i; + logic status_o; + logic jtag_tck_i; + logic jtag_tdi_i; + logic jtag_tms_i; + logic jtag_tdo_o; + logic uart_rx_i; + logic uart_tx_o; + logic [2:0] gpio_o; + logic [2:0] gpio_i; + logic [2:0] gpio_out_en_o; + + croc_ecp5_io i_croc_ecp5_io ( + .pad_clk_48_i ( pad_clk_48_i ), + .pad_usr_btn_i ( pad_usr_btn_i ), + .pad_status_o ( pad_status_o ), + .pad_jtag_tck_i ( pad_jtag_tck_i ), + .pad_jtag_tdi_i ( pad_jtag_tdi_i ), + .pad_jtag_tdo_o ( pad_jtag_tdo_o ), + .pad_jtag_tms_i ( pad_jtag_tms_i ), + .pad_uart_rx_i ( pad_uart_rx_i ), + .pad_uart_tx_o ( pad_uart_tx_o ), + .pad_gpio_io ( pad_gpio_io ), + .clk_48_i ( clk_48_i ), + .usr_btn_i ( usr_btn_i ), + .status_o ( status_o ), + .jtag_tck_i ( jtag_tck_i ), + .jtag_tdi_i ( jtag_tdi_i ), + .jtag_tdo_o ( jtag_tdo_o ), + .jtag_tms_i ( jtag_tms_i ), + .uart_rx_i ( uart_rx_i ), + .uart_tx_o ( uart_tx_o ), + .gpio_o ( gpio_o ), + .gpio_i ( gpio_i ), + .gpio_out_en_o ( gpio_out_en_o ) + ); + + // frequency reduction + logic [11:0] count_d, count_q; + always_ff @(posedge clk_48_i) begin : proc_counter + count_q <= count_d; + end + assign count_d = count_q + 1; + + // invert gpios + logic [2:0] gpio_no; + assign gpio_o = ~gpio_no; + + croc_soc #( + .GpioCount( 3 ) + ) + i_croc_soc ( + .clk_i ( count_q[1] ), + .rst_ni ( usr_btn_i ), + .ref_clk_i ( count_q[11] ), + .testmode_i ( 1'b0 ), + .fetch_en_i ( 1'b1 ), + .status_o ( status_o ), + + .jtag_tck_i ( jtag_tck_i ), + .jtag_tdi_i ( jtag_tdi_i ), + .jtag_tdo_o ( jtag_tdo_o ), + .jtag_tms_i ( jtag_tms_i ), + .jtag_trst_ni ( 1'b1 ), + + .uart_rx_i ( uart_rx_i ), + .uart_tx_o ( uart_tx_o ), + + .gpio_i ( gpio_i ), + .gpio_o ( gpio_no ), + .gpio_out_en_o ( gpio_out_en_o ) + ); + +endmodule diff --git a/nextpnr/orangecrab/src/croc_ecp5_io.sv b/nextpnr/orangecrab/src/croc_ecp5_io.sv new file mode 100644 index 00000000..9f5d97a8 --- /dev/null +++ b/nextpnr/orangecrab/src/croc_ecp5_io.sv @@ -0,0 +1,79 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Authors: +// - Thomas Benz + +// pin mapping chosen for the OrangeCrab FPGA + +module croc_ecp5_io ( + input logic pad_clk_48_i, + input logic pad_usr_btn_i, + output logic pad_status_o, + + input logic pad_jtag_tck_i, + input logic pad_jtag_tdi_i, + output logic pad_jtag_tdo_o, + input logic pad_jtag_tms_i, + + input logic pad_uart_rx_i, + output logic pad_uart_tx_o, + + inout logic [2:0] pad_gpio_io, + + output logic clk_48_i, + output logic usr_btn_i, + input logic status_o, + + output logic jtag_tck_i, + output logic jtag_tdi_i, + input logic jtag_tdo_o, + output logic jtag_tms_i, + + output logic uart_rx_i, + input logic uart_tx_o, + + input logic [2:0] gpio_o, + output logic [2:0] gpio_i, + input logic [2:0] gpio_out_en_o +); + + // get the clock from the oscillator + (* LOC="A9" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) i_pad_clk_48_i (.B(pad_clk_48_i), .O(clk_48_i)); + + (* LOC="J17" *) (* IO_TYPE="SSTL135_I" *) + TRELLIS_IO #(.DIR("INPUT")) i_pad_usr_btn_i (.B(pad_usr_btn_i), .O(usr_btn_i)); + + (* LOC="H4" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) i_pad_status_o (.B(pad_status_o), .I(status_o)); + + (* LOC="G4" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) i_pad_jtag_tck_i (.B(pad_jtag_tck_i), .O(jtag_tck_i)); + + (* LOC="T17" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) i_pad_jtag_tdi_i (.B(pad_jtag_tdi_i), .O(jtag_tdi_i)); + + (* LOC="R17" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) i_pad_jtag_tdo_o (.B(pad_jtag_tdo_o), .I(jtag_tdo_o)); + + (* LOC="N16" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) i_pad_jtag_tms_i (.B(pad_jtag_tms_i), .O(jtag_tms_i)); + + (* LOC="N15" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) i_pad_uart_rx_i (.B(pad_uart_rx_i), .O(uart_rx_i)); + + (* LOC="N17" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) i_pad_uart_tx_o (.B(pad_uart_tx_o), .I(uart_tx_o)); + + (* LOC="K4" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("BIDIR")) i_pad_gpio_0_io (.B(pad_gpio_io[0]), .I(gpio_o[0]), .O(gpio_i[0]), .T(~gpio_out_en_o[0])); + + (* LOC="M3" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("BIDIR")) i_pad_gpio_1_io (.B(pad_gpio_io[1]), .I(gpio_o[1]), .O(gpio_i[1]), .T(~gpio_out_en_o[1])); + + (* LOC="J3" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("BIDIR")) i_pad_gpio_2_io (.B(pad_gpio_io[2]), .I(gpio_o[2]), .O(gpio_i[2]), .T(~gpio_out_en_o[2])); + +endmodule diff --git a/sw/gpio.c b/sw/gpio.c new file mode 100644 index 00000000..7ca42aa5 --- /dev/null +++ b/sw/gpio.c @@ -0,0 +1,26 @@ +// Copyright (c) 2025 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0/ +// +// Authors: +// - Thomas Benz + +#include "timer.h" +#include "gpio.h" + +int main() { + + int now = 0; + + gpio_set_direction(0xFFFF, 0x0007); + gpio_enable(0x07); + gpio_write(now); + + while (1) { + sleep_ms(100); + now = now + 1; + gpio_write(now); + } + + return 0; +}