diff --git a/.gitmodules b/.gitmodules index f374fa1f..8756fbc9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -21,7 +21,7 @@ url = https://github.com/riscv-boom/riscv-boom.git [submodule "generators/sifive-blocks"] path = generators/sifive-blocks - url = https://github.com/sifive/sifive-blocks.git + url = https://github.com/abejgonzalez/sifive-blocks.git [submodule "generators/hwacha"] path = generators/hwacha url = https://github.com/ucb-bar/hwacha.git @@ -131,3 +131,6 @@ [submodule "generators/riscv-sodor"] path = generators/riscv-sodor url = https://github.com/ucb-bar/riscv-sodor.git +[submodule "fpga/fpga-shells"] + path = fpga/fpga-shells + url = git@github.com:sifive/fpga-shells.git diff --git a/build.sbt b/build.sbt index 750878ab..0de63b3a 100644 --- a/build.sbt +++ b/build.sbt @@ -221,3 +221,10 @@ lazy val firechip = conditionalDependsOn(project in file("generators/firechip")) testGrouping in Test := isolateAllTests( (definedTests in Test).value ), testOptions in Test += Tests.Argument("-oF") ) +lazy val fpga_shells = (project in file("./fpga/fpga-shells")) + .dependsOn(rocketchip, sifive_blocks, chipyard) + .settings(commonSettings) + +lazy val fpga_platforms = (project in file("./fpga")) + .dependsOn(chipyard, fpga_shells) + .settings(commonSettings) diff --git a/common.mk b/common.mk index 8ebc262c..9f21dcbb 100644 --- a/common.mk +++ b/common.mk @@ -58,7 +58,7 @@ include $(base_dir)/tools/dromajo/dromajo.mk # Returns a list of files in directory $1 with file extension $2. lookup_srcs = $(shell find -L $(1)/ -name target -prune -o -iname "*.$(2)" -print 2> /dev/null) -SOURCE_DIRS = $(addprefix $(base_dir)/,generators sims/firesim/sim tools/barstools/iocell) +SOURCE_DIRS = $(addprefix $(base_dir)/,generators sims/firesim/sim tools/barstools/iocell fpga) SCALA_SOURCES = $(call lookup_srcs,$(SOURCE_DIRS),scala) VLOG_SOURCES = $(call lookup_srcs,$(SOURCE_DIRS),sv) $(call lookup_srcs,$(SOURCE_DIRS),v) # This assumes no SBT meta-build sources diff --git a/fpga/.gitignore b/fpga/.gitignore new file mode 100644 index 00000000..814384f3 --- /dev/null +++ b/fpga/.gitignore @@ -0,0 +1 @@ +generated-src diff --git a/fpga/Makefile b/fpga/Makefile new file mode 100644 index 00000000..74af21e9 --- /dev/null +++ b/fpga/Makefile @@ -0,0 +1,132 @@ +######################################################################################### +# fpga prototype makefile +######################################################################################### + +######################################################################################### +# general path variables +######################################################################################### +base_dir=$(abspath ..) +sim_dir=$(abspath .) + +# do not generate simulation files +sim_name := none + +######################################################################################### +# include shared variables +######################################################################################### +SUB_PROJECT ?= vcu118 + +ifeq ($(SUB_PROJECT),vcu118) + SBT_PROJECT ?= fpga_platforms + MODEL ?= VCU118FPGATestHarness + VLOG_MODEL ?= VCU118FPGATestHarness + MODEL_PACKAGE ?= chipyard.fpga.vcu118 + CONFIG ?= RocketVCU118Config + CONFIG_PACKAGE ?= chipyard.fpga.vcu118 + GENERATOR_PACKAGE ?= chipyard + TB ?= none # unused + TOP ?= ChipTop + BOARD ?= vcu118 +endif + +ifeq ($(SUB_PROJECT),bringup) + SBT_PROJECT ?= fpga_platforms + MODEL ?= BringupVCU118FPGATestHarness + VLOG_MODEL ?= BringupVCU118FPGATestHarness + MODEL_PACKAGE ?= chipyard.fpga.vcu118.bringup + CONFIG ?= RocketBringupConfig + CONFIG_PACKAGE ?= chipyard.fpga.vcu118.bringup + GENERATOR_PACKAGE ?= chipyard + TB ?= none # unused + TOP ?= ChipTop + BOARD ?= vcu118 +endif + +ifeq ($(SUB_PROJECT),arty) + # TODO: Fix with Arty + SBT_PROJECT ?= fpga_platforms + MODEL ?= BringupVCU118FPGATestHarness + VLOG_MODEL ?= BringupVCU118FPGATestHarness + MODEL_PACKAGE ?= chipyard.fpga.vcu118.bringup + CONFIG ?= RocketBringupConfig + CONFIG_PACKAGE ?= chipyard.fpga.vcu118.bringup + GENERATOR_PACKAGE ?= chipyard + TB ?= none # unused + TOP ?= ChipTop + BOARD ?= arty +endif + +include $(base_dir)/variables.mk + +# default variables to build the arty example +# setup the board to use + +.PHONY: default +default: $(mcs) + +######################################################################################### +# misc. directories +######################################################################################### +fpga_dir := $(base_dir)/fpga/fpga-shells/xilinx +fpga_common_script_dir := $(fpga_dir)/common/tcl + +######################################################################################### +# import other necessary rules and variables +######################################################################################### +include $(base_dir)/common.mk + +######################################################################################### +# copy from other directory +######################################################################################### +all_vsrcs := \ + $(sim_vsrcs) \ + $(base_dir)/generators/sifive-blocks/vsrc/SRLatch.v \ + $(fpga_dir)/common/vsrc/PowerOnResetFPGAOnly.v + +######################################################################################### +# vivado rules +######################################################################################### +# combine all sources into single .f +synth_list_f := $(build_dir)/$(long_name).vsrcs.f +$(synth_list_f): $(sim_common_files) $(all_vsrcs) + $(foreach file,$(all_vsrcs),echo "$(file)" >> $@;) + cat $(sim_common_files) >> $@ + +BIT_FILE := $(build_dir)/obj/$(MODEL).bit +$(BIT_FILE): $(synth_list_f) + cd $(build_dir); vivado \ + -nojournal -mode batch \ + -source $(fpga_common_script_dir)/vivado.tcl \ + -tclargs \ + -top-module "$(MODEL)" \ + -F "$(synth_list_f)" \ + -ip-vivado-tcls "$(shell find '$(build_dir)' -name '*.vivado.tcl')" \ + -board "$(BOARD)" + +.PHONY: bit +bit: $(BIT_FILE) + +.PHONY: debug-bitstream +debug-bitstream: $(build_dir)/obj/post_synth.dcp + cd $(build_dir); vivado \ + -nojournal -mode batch \ + -source $(sim_dir)/scripts/run_impl_bitstream.tcl \ + -tclargs \ + $(build_dir)/obj/post_synth.dcp \ + xcvu9p-flga2104-2l-e \ + $(build_dir)/obj/debug_output + +# Build .mcs +MCS_FILE := $(build_dir)/obj/$(MODEL).mcs +$(MCS_FILE): $(BIT_FILE) + cd $(build_dir); vivado -nojournal -mode batch -source $(fpga_common_script_dir)/write_cfgmem.tcl -tclargs $(BOARD) $@ $< + +.PHONY: mcs +mcs: $(MCS_FILE) + +######################################################################################### +# general cleanup rules +######################################################################################### +.PHONY: clean +clean: + rm -rf $(gen_dir) diff --git a/fpga/fpga-shells b/fpga/fpga-shells new file mode 160000 index 00000000..89a5efec --- /dev/null +++ b/fpga/fpga-shells @@ -0,0 +1 @@ +Subproject commit 89a5efec011ebc21b9455923501df70783161cb8 diff --git a/fpga/scripts/run_impl_bitstream.tcl b/fpga/scripts/run_impl_bitstream.tcl new file mode 100644 index 00000000..ec3828e8 --- /dev/null +++ b/fpga/scripts/run_impl_bitstream.tcl @@ -0,0 +1,45 @@ +#### Command line arguments to this script +# argv[0] = absolute path to post_synth checkpoint file +# argv[1] = part +# argv[2] = output directory + +set synth_checkpoint_file [lindex $argv 0] +set part [lindex $argv 1] +set output_dir [lindex $argv 2] + +# Set the project part to the part passed into this script +set_part ${part} + +# Create output directory if it doesn't exist +file mkdir ${output_dir} +file mkdir ${output_dir}/reports +file mkdir ${output_dir}/outputs + +# Load synthesis checkpoint +open_checkpoint ${synth_checkpoint_file} + +# Run implementation and save reports as needed +opt_design +place_design +phys_opt_design +write_checkpoint -force ${output_dir}/outputs/post_place +report_timing_summary -file ${output_dir}/reports/post_place_timing_summary.rpt +report_drc -file ${output_dir}/reports/post_place_drc.rpt + +route_design +write_checkpoint -force ${output_dir}/outputs/post_route +report_timing_summary -file ${output_dir}/reports/post_route_timing_summary.rpt +report_timing -sort_by group -max_paths 100 -path_type summary -file ${output_dir}/reports/post_route_timing.rpt +report_clock_utilization -file ${output_dir}/reports/post_route_clock_utilization.rpt +report_utilization -file ${output_dir}/reports/post_route_utilization.rpt +report_drc -file ${output_dir}/reports/post_route_drc.rpt +report_cdc -details -file ${output_dir}/reports/post_route_cdc.rpt +report_clock_interaction -file ${output_dir}/reports/post_route_clock_interaction.rpt +report_bus_skew -file ${output_dir}/reports/post_route_bus_skew.rpt +report_design_analysis -logic_level_distribution -of_timing_paths [get_timing_paths -max_paths 1000 -slack_lesser_than 0] -file ${output_dir}/reports/post_route_timing_violations.rpt + +write_verilog -force ${output_dir}/outputs/post_route.v +write_xdc -no_fixed_only -force ${output_dir}/outputs/post_route.xdc + +write_bitstream -force ${output_dir}/outputs/top.bit +write_debug_probes -force ${output_dir}/outputs/debug_nets.ltx diff --git a/fpga/scripts/write_mmi.tcl b/fpga/scripts/write_mmi.tcl new file mode 100644 index 00000000..e577dd2b --- /dev/null +++ b/fpga/scripts/write_mmi.tcl @@ -0,0 +1,75 @@ +proc write_mmi {filepath inst} { + current_instance + current_instance $inst + set chn [open $filepath w] + puts $chn "" + puts $chn "" + puts $chn "\t" + set brams [dict create] + foreach cell [get_cells -hierarchical -filter { PRIMITIVE_GROUP =~ BLOCKRAM }] { + set name [get_property RTL_RAM_NAME $cell] + dict update brams $name name { + dict lappend name cells $cell + dict set name size [get_property RTL_RAM_BITS $cell] + } + } + proc compare {a b} { + set a_addr [get_property bram_addr_begin $a] + set b_addr [get_property bram_addr_begin $b] + if {$a_addr > $b_addr} { + return 1 + } elseif {$a_addr < $b_addr} { + return -1 + } + set a_slice [get_property bram_slice_begin $a] + set b_slice [get_property bram_slice_begin $b] + if {$a_slice > $b_slice} { + return 1 + } elseif {$a_slice < $b_slice} { + return -1 + } + return 0 + } + dict for {name desc} $brams { + dict with desc { + puts $chn "\t\t> 3]\">" + puts $chn "\t\t\t" + foreach cell [lsort -command compare $cells] { + set type [switch [get_property REF_NAME $cell] \ + RAMB36E2 {expr {"RAMB32"}} \ + RAMB36E1 {expr {"RAMB32"}}] + set loc [lindex [split [get_property LOC $cell] "_"] 1] + set lsb [get_property bram_slice_begin $cell] + set msb [get_property bram_slice_end $cell] + set addr_bgn [get_property bram_addr_begin $cell] + set addr_end [get_property bram_addr_end $cell] + puts $chn "\t\t\t\t" + puts $chn "\t\t\t\t\t" + puts $chn "\t\t\t\t\t" + puts $chn "\t\t\t\t\t" + puts $chn "\t\t\t\t" + } + puts $chn "\t\t\t" + puts $chn "\t\t" + } + } + puts $chn "\t" + puts $chn "\t" + puts $chn "\t\t" + puts $chn "" + close $chn + current_instance + +} + +if {$argc != 3} { + puts $argc + puts {Error: Invalid number of arguments} + puts {Usage: write_mmi.tcl checkpoint mmi_file instance} +} + +lassign $argv checkpoint mmi_file instance + +open_checkpoint $checkpoint +write_mmi $mmi_file $instance diff --git a/fpga/src/main/resources/vcu118/sdboot/.gitignore b/fpga/src/main/resources/vcu118/sdboot/.gitignore new file mode 100644 index 00000000..378eac25 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/.gitignore @@ -0,0 +1 @@ +build diff --git a/fpga/src/main/resources/vcu118/sdboot/Makefile b/fpga/src/main/resources/vcu118/sdboot/Makefile new file mode 100644 index 00000000..b9c21470 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/Makefile @@ -0,0 +1,39 @@ +# RISCV environment variable must be set +ROOT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +BUILD_DIR := $(ROOT_DIR)/build + +CC=$(RISCV)/bin/riscv64-unknown-elf-gcc +OBJCOPY=$(RISCV)/bin/riscv64-unknown-elf-objcopy +OBJDUMP=$(RISCV)/bin/riscv64-unknown-elf-objdump +CFLAGS=-march=rv64ima -mcmodel=medany -O2 -std=gnu11 -Wall -nostartfiles +CFLAGS+= -fno-common -g -DENTROPY=0 -mabi=lp64 -DNONSMP_HART=0 +CFLAGS+= -I $(ROOT_DIR)/include -I. +LFLAGS=-static -nostdlib -L $(ROOT_DIR)/linker -T sdboot.elf.lds + +#PBUS_CLK passed in +elf := $(BUILD_DIR)/sdboot.elf +$(elf): head.S kprintf.c sd.c + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) -DTL_CLK="$(PBUS_CLK)UL" $(LFLAGS) -o $@ head.S sd.c kprintf.c + +.PHONY: elf +elf: $(elf) + +bin := $(BUILD_DIR)/sdboot.bin +$(bin): $(elf) + mkdir -p $(BUILD_DIR) + $(OBJCOPY) -O binary --change-addresses=-0x10000 $< $@ + +.PHONY: bin +bin: $(bin) + +dump := $(BUILD_DIR)/sdboot.dump +$(dump): $(elf) + $(OBJDUMP) -D -S $< > $@ + +.PHONY: dump +dump: $(dump) + +.PHONY: clean +clean:: + rm -rf $(BUILD_DIR) diff --git a/fpga/src/main/resources/vcu118/sdboot/common.h b/fpga/src/main/resources/vcu118/sdboot/common.h new file mode 100644 index 00000000..4f71e103 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/common.h @@ -0,0 +1,9 @@ +#ifndef _SDBOOT_COMMON_H +#define _SDBOOT_COMMON_H + +#ifndef PAYLOAD_DEST + #define PAYLOAD_DEST MEMORY_MEM_ADDR +#endif + + +#endif diff --git a/fpga/src/main/resources/vcu118/sdboot/head.S b/fpga/src/main/resources/vcu118/sdboot/head.S new file mode 100644 index 00000000..d871b824 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/head.S @@ -0,0 +1,21 @@ +// See LICENSE for license details. +#include +#include +#include "common.h" + + .section .text.init + .option norvc + .globl _prog_start +_prog_start: + smp_pause(s1, s2) + li sp, (PAYLOAD_DEST + 0xffff000) + call main + smp_resume(s1, s2) + csrr a0, mhartid // hartid for next level bootloader + la a1, dtb // dtb address for next level bootloader + li s1, PAYLOAD_DEST + jr s1 + + .section .dtb + .align 3 +dtb: diff --git a/fpga/src/main/resources/vcu118/sdboot/include/bits.h b/fpga/src/main/resources/vcu118/sdboot/include/bits.h new file mode 100644 index 00000000..bfe656fe --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/bits.h @@ -0,0 +1,36 @@ +// See LICENSE for license details. +#ifndef _RISCV_BITS_H +#define _RISCV_BITS_H + +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) + +#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b)) +#define ROUNDDOWN(a, b) ((a)/(b)*(b)) + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi) + +#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1))) +#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1)))) + +#define STR(x) XSTR(x) +#define XSTR(x) #x + +#if __riscv_xlen == 64 +# define SLL32 sllw +# define STORE sd +# define LOAD ld +# define LWU lwu +# define LOG_REGBYTES 3 +#else +# define SLL32 sll +# define STORE sw +# define LOAD lw +# define LWU lw +# define LOG_REGBYTES 2 +#endif +#define REGBYTES (1 << LOG_REGBYTES) + +#endif diff --git a/fpga/src/main/resources/vcu118/sdboot/include/const.h b/fpga/src/main/resources/vcu118/sdboot/include/const.h new file mode 100644 index 00000000..8dcffbb0 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/const.h @@ -0,0 +1,18 @@ +// See LICENSE for license details. +/* Derived from */ + +#ifndef _SIFIVE_CONST_H +#define _SIFIVE_CONST_H + +#ifdef __ASSEMBLER__ +#define _AC(X,Y) X +#define _AT(T,X) X +#else +#define _AC(X,Y) (X##Y) +#define _AT(T,X) ((T)(X)) +#endif /* !__ASSEMBLER__*/ + +#define _BITUL(x) (_AC(1,UL) << (x)) +#define _BITULL(x) (_AC(1,ULL) << (x)) + +#endif /* _SIFIVE_CONST_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/devices/clint.h b/fpga/src/main/resources/vcu118/sdboot/include/devices/clint.h new file mode 100644 index 00000000..c2b05bae --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/devices/clint.h @@ -0,0 +1,14 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_CLINT_H +#define _SIFIVE_CLINT_H + + +#define CLINT_MSIP 0x0000 +#define CLINT_MSIP_size 0x4 +#define CLINT_MTIMECMP 0x4000 +#define CLINT_MTIMECMP_size 0x8 +#define CLINT_MTIME 0xBFF8 +#define CLINT_MTIME_size 0x8 + +#endif /* _SIFIVE_CLINT_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/devices/gpio.h b/fpga/src/main/resources/vcu118/sdboot/include/devices/gpio.h new file mode 100644 index 00000000..f7f0acb4 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/devices/gpio.h @@ -0,0 +1,24 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_GPIO_H +#define _SIFIVE_GPIO_H + +#define GPIO_INPUT_VAL (0x00) +#define GPIO_INPUT_EN (0x04) +#define GPIO_OUTPUT_EN (0x08) +#define GPIO_OUTPUT_VAL (0x0C) +#define GPIO_PULLUP_EN (0x10) +#define GPIO_DRIVE (0x14) +#define GPIO_RISE_IE (0x18) +#define GPIO_RISE_IP (0x1C) +#define GPIO_FALL_IE (0x20) +#define GPIO_FALL_IP (0x24) +#define GPIO_HIGH_IE (0x28) +#define GPIO_HIGH_IP (0x2C) +#define GPIO_LOW_IE (0x30) +#define GPIO_LOW_IP (0x34) +#define GPIO_IOF_EN (0x38) +#define GPIO_IOF_SEL (0x3C) +#define GPIO_OUTPUT_XOR (0x40) + +#endif /* _SIFIVE_GPIO_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/devices/plic.h b/fpga/src/main/resources/vcu118/sdboot/include/devices/plic.h new file mode 100644 index 00000000..4d5b2d8d --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/devices/plic.h @@ -0,0 +1,31 @@ +// See LICENSE for license details. + +#ifndef PLIC_H +#define PLIC_H + +#include + +// 32 bits per source +#define PLIC_PRIORITY_OFFSET _AC(0x0000,UL) +#define PLIC_PRIORITY_SHIFT_PER_SOURCE 2 +// 1 bit per source (1 address) +#define PLIC_PENDING_OFFSET _AC(0x1000,UL) +#define PLIC_PENDING_SHIFT_PER_SOURCE 0 + +//0x80 per target +#define PLIC_ENABLE_OFFSET _AC(0x2000,UL) +#define PLIC_ENABLE_SHIFT_PER_TARGET 7 + + +#define PLIC_THRESHOLD_OFFSET _AC(0x200000,UL) +#define PLIC_CLAIM_OFFSET _AC(0x200004,UL) +#define PLIC_THRESHOLD_SHIFT_PER_TARGET 12 +#define PLIC_CLAIM_SHIFT_PER_TARGET 12 + +#define PLIC_MAX_SOURCE 1023 +#define PLIC_SOURCE_MASK 0x3FF + +#define PLIC_MAX_TARGET 15871 +#define PLIC_TARGET_MASK 0x3FFF + +#endif /* PLIC_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/devices/spi.h b/fpga/src/main/resources/vcu118/sdboot/include/devices/spi.h new file mode 100644 index 00000000..7118572a --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/devices/spi.h @@ -0,0 +1,79 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_SPI_H +#define _SIFIVE_SPI_H + +/* Register offsets */ + +#define SPI_REG_SCKDIV 0x00 +#define SPI_REG_SCKMODE 0x04 +#define SPI_REG_CSID 0x10 +#define SPI_REG_CSDEF 0x14 +#define SPI_REG_CSMODE 0x18 + +#define SPI_REG_DCSSCK 0x28 +#define SPI_REG_DSCKCS 0x2a +#define SPI_REG_DINTERCS 0x2c +#define SPI_REG_DINTERXFR 0x2e + +#define SPI_REG_FMT 0x40 +#define SPI_REG_TXFIFO 0x48 +#define SPI_REG_RXFIFO 0x4c +#define SPI_REG_TXCTRL 0x50 +#define SPI_REG_RXCTRL 0x54 + +#define SPI_REG_FCTRL 0x60 +#define SPI_REG_FFMT 0x64 + +#define SPI_REG_IE 0x70 +#define SPI_REG_IP 0x74 + +/* Fields */ + +#define SPI_SCK_POL 0x1 +#define SPI_SCK_PHA 0x2 + +#define SPI_FMT_PROTO(x) ((x) & 0x3) +#define SPI_FMT_ENDIAN(x) (((x) & 0x1) << 2) +#define SPI_FMT_DIR(x) (((x) & 0x1) << 3) +#define SPI_FMT_LEN(x) (((x) & 0xf) << 16) + +/* TXCTRL register */ +#define SPI_TXWM(x) ((x) & 0xffff) +/* RXCTRL register */ +#define SPI_RXWM(x) ((x) & 0xffff) + +#define SPI_IP_TXWM 0x1 +#define SPI_IP_RXWM 0x2 + +#define SPI_FCTRL_EN 0x1 + +#define SPI_INSN_CMD_EN 0x1 +#define SPI_INSN_ADDR_LEN(x) (((x) & 0x7) << 1) +#define SPI_INSN_PAD_CNT(x) (((x) & 0xf) << 4) +#define SPI_INSN_CMD_PROTO(x) (((x) & 0x3) << 8) +#define SPI_INSN_ADDR_PROTO(x) (((x) & 0x3) << 10) +#define SPI_INSN_DATA_PROTO(x) (((x) & 0x3) << 12) +#define SPI_INSN_CMD_CODE(x) (((x) & 0xff) << 16) +#define SPI_INSN_PAD_CODE(x) (((x) & 0xff) << 24) + +#define SPI_TXFIFO_FULL (1 << 31) +#define SPI_RXFIFO_EMPTY (1 << 31) + +/* Values */ + +#define SPI_CSMODE_AUTO 0 +#define SPI_CSMODE_HOLD 2 +#define SPI_CSMODE_OFF 3 + +#define SPI_DIR_RX 0 +#define SPI_DIR_TX 1 + +#define SPI_PROTO_S 0 +#define SPI_PROTO_D 1 +#define SPI_PROTO_Q 2 + +#define SPI_ENDIAN_MSB 0 +#define SPI_ENDIAN_LSB 1 + +#endif /* _SIFIVE_SPI_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/devices/uart.h b/fpga/src/main/resources/vcu118/sdboot/include/devices/uart.h new file mode 100644 index 00000000..aecfd912 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/devices/uart.h @@ -0,0 +1,28 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_UART_H +#define _SIFIVE_UART_H + +/* Register offsets */ +#define UART_REG_TXFIFO 0x00 +#define UART_REG_RXFIFO 0x04 +#define UART_REG_TXCTRL 0x08 +#define UART_REG_RXCTRL 0x0c +#define UART_REG_IE 0x10 +#define UART_REG_IP 0x14 +#define UART_REG_DIV 0x18 + +/* TXCTRL register */ +#define UART_TXEN 0x1 +#define UART_TXNSTOP 0x2 +#define UART_TXWM(x) (((x) & 0xffff) << 16) + +/* RXCTRL register */ +#define UART_RXEN 0x1 +#define UART_RXWM(x) (((x) & 0xffff) << 16) + +/* IP register */ +#define UART_IP_TXWM 0x1 +#define UART_IP_RXWM 0x2 + +#endif /* _SIFIVE_UART_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/platform.h b/fpga/src/main/resources/vcu118/sdboot/include/platform.h new file mode 100644 index 00000000..c240e0e5 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/platform.h @@ -0,0 +1,108 @@ +// See LICENSE for license details. + +#ifndef _EAGLE_PLATFORM_H +#define _EAGLE_PLATFORM_H + +#include "const.h" +#include "riscv_test_defaults.h" +#include "devices/clint.h" +#include "devices/gpio.h" +#include "devices/plic.h" +#include "devices/spi.h" +#include "devices/uart.h" + + // Some things missing from the official encoding.h +#if __riscv_xlen == 32 + #define MCAUSE_INT 0x80000000UL + #define MCAUSE_CAUSE 0x7FFFFFFFUL +#else + #define MCAUSE_INT 0x8000000000000000UL + #define MCAUSE_CAUSE 0x7FFFFFFFFFFFFFFFUL +#endif + +/**************************************************************************** + * Platform definitions + *****************************************************************************/ + +// CPU info +#define NUM_CORES 1 +#define GLOBAL_INT_SIZE 38 +#define GLOBAL_INT_MAX_PRIORITY 7 + +// Memory map +#define CLINT_CTRL_ADDR _AC(0x2000000,UL) +#define CLINT_CTRL_SIZE _AC(0x10000,UL) +#define DEBUG_CTRL_ADDR _AC(0x0,UL) +#define DEBUG_CTRL_SIZE _AC(0x1000,UL) +#define ERROR_MEM_ADDR _AC(0x3000,UL) +#define ERROR_MEM_SIZE _AC(0x1000,UL) +#define GPIO_CTRL_ADDR _AC(0x64002000,UL) +#define GPIO_CTRL_SIZE _AC(0x1000,UL) +#define MASKROM_MEM_ADDR _AC(0x10000,UL) +#define MASKROM_MEM_SIZE _AC(0x10000,UL) +#define MEMORY_MEM_ADDR _AC(0x80000000,UL) +#define MEMORY_MEM_SIZE _AC(0x10000000,UL) +#define PLIC_CTRL_ADDR _AC(0xc000000,UL) +#define PLIC_CTRL_SIZE _AC(0x4000000,UL) +#define SPI_CTRL_ADDR _AC(0x64001000,UL) +#define SPI_CTRL_SIZE _AC(0x1000,UL) +#define SPI1_CTRL_ADDR _AC(0x64004000,UL) +#define SPI1_CTRL_SIZE _AC(0x1000,UL) +#define TEST_CTRL_ADDR _AC(0x4000,UL) +#define TEST_CTRL_SIZE _AC(0x1000,UL) +#define UART_CTRL_ADDR _AC(0x64000000,UL) +#define UART_CTRL_SIZE _AC(0x1000,UL) +#define UART1_CTRL_ADDR _AC(0x64003000,UL) +#define UART1_CTRL_SIZE _AC(0x1000,UL) +#define I2C_CTRL_ADDR _AC(0x64005000,UL) +#define I2C_CTRL_SIZE _AC(0x1000,UL) + +// IOF masks + + +// Interrupt numbers +#define UART_INT_BASE 1 +#define UART1_INT_BASE 2 +#define I2C_INT_BASE 3 +#define GPIO_INT_BASE 4 +#define SPI_INT_BASE 36 +#define SPI1_INT_BASE 37 + +// Helper functions +#define _REG64(p, i) (*(volatile uint64_t *)((p) + (i))) +#define _REG32(p, i) (*(volatile uint32_t *)((p) + (i))) +#define _REG16(p, i) (*(volatile uint16_t *)((p) + (i))) +// Bulk set bits in `reg` to either 0 or 1. +// E.g. SET_BITS(MY_REG, 0x00000007, 0) would generate MY_REG &= ~0x7 +// E.g. SET_BITS(MY_REG, 0x00000007, 1) would generate MY_REG |= 0x7 +#define SET_BITS(reg, mask, value) if ((value) == 0) { (reg) &= ~(mask); } else { (reg) |= (mask); } +#define AXI_PCIE_HOST_1_00_A_REG(offset) _REG32(AXI_PCIE_HOST_1_00_A_CTRL_ADDR, offset) +#define CLINT_REG(offset) _REG32(CLINT_CTRL_ADDR, offset) +#define DEBUG_REG(offset) _REG32(DEBUG_CTRL_ADDR, offset) +#define ERROR_REG(offset) _REG32(ERROR_CTRL_ADDR, offset) +#define GPIO_REG(offset) _REG32(GPIO_CTRL_ADDR, offset) +#define MASKROM_REG(offset) _REG32(MASKROM_CTRL_ADDR, offset) +#define MEMORY_REG(offset) _REG32(MEMORY_CTRL_ADDR, offset) +#define PLIC_REG(offset) _REG32(PLIC_CTRL_ADDR, offset) +#define SPI_REG(offset) _REG32(SPI_CTRL_ADDR, offset) +#define TEST_REG(offset) _REG32(TEST_CTRL_ADDR, offset) +#define UART_REG(offset) _REG32(UART_CTRL_ADDR, offset) +#define AXI_PCIE_HOST_1_00_A_REG64(offset) _REG64(AXI_PCIE_HOST_1_00_A_CTRL_ADDR, offset) +#define CLINT_REG64(offset) _REG64(CLINT_CTRL_ADDR, offset) +#define DEBUG_REG64(offset) _REG64(DEBUG_CTRL_ADDR, offset) +#define ERROR_REG64(offset) _REG64(ERROR_CTRL_ADDR, offset) +#define GPIO_REG64(offset) _REG64(GPIO_CTRL_ADDR, offset) +#define MASKROM_REG64(offset) _REG64(MASKROM_CTRL_ADDR, offset) +#define MEMORY_REG64(offset) _REG64(MEMORY_CTRL_ADDR, offset) +#define PLIC_REG64(offset) _REG64(PLIC_CTRL_ADDR, offset) +#define SPI_REG64(offset) _REG64(SPI_CTRL_ADDR, offset) +#define SPI1_REG64(offset) _REG64(SPI1_CTRL_ADDR, offset) +#define TEST_REG64(offset) _REG64(TEST_CTRL_ADDR, offset) +#define UART_REG64(offset) _REG64(UART_CTRL_ADDR, offset) +#define UART1_REG64(offset) _REG64(UART1_CTRL_ADDR, offset) +#define I2C_REG64(offset) _REG64(I2C_CTRL_ADDR, offset) + +// Misc + + +#endif /* _SIFIVE_PLATFORM_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/riscv_test_defaults.h b/fpga/src/main/resources/vcu118/sdboot/include/riscv_test_defaults.h new file mode 100644 index 00000000..a2dea3d4 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/riscv_test_defaults.h @@ -0,0 +1,81 @@ +// See LICENSE for license details. +#ifndef _RISCV_TEST_DEFAULTS_H +#define _RISCV_TEST_DEFAULTS_H + +#define TESTNUM x28 +#define TESTBASE 0x4000 + +#define RVTEST_RV32U \ + .macro init; \ + .endm + +#define RVTEST_RV64U \ + .macro init; \ + .endm + +#define RVTEST_RV32UF \ + .macro init; \ + /* If FPU exists, initialize FCSR. */ \ + csrr t0, misa; \ + andi t0, t0, 1 << ('F' - 'A'); \ + beqz t0, 1f; \ + /* Enable FPU if it exists. */ \ + li t0, MSTATUS_FS; \ + csrs mstatus, t0; \ + fssr x0; \ +1: ; \ + .endm + +#define RVTEST_RV64UF \ + .macro init; \ + /* If FPU exists, initialize FCSR. */ \ + csrr t0, misa; \ + andi t0, t0, 1 << ('F' - 'A'); \ + beqz t0, 1f; \ + /* Enable FPU if it exists. */ \ + li t0, MSTATUS_FS; \ + csrs mstatus, t0; \ + fssr x0; \ +1: ; \ + .endm + +#define RVTEST_CODE_BEGIN \ + .section .text.init; \ + .globl _prog_start; \ +_prog_start: \ + init; + +#define RVTEST_CODE_END \ + unimp + +#define RVTEST_PASS \ + fence; \ + li t0, TESTBASE; \ + li t1, 0x5555; \ + sw t1, 0(t0); \ +1: \ + j 1b; + +#define RVTEST_FAIL \ + li t0, TESTBASE; \ + li t1, 0x3333; \ + slli a0, a0, 16; \ + add a0, a0, t1; \ + sw a0, 0(t0); \ +1: \ + j 1b; + +#define EXTRA_DATA + +#define RVTEST_DATA_BEGIN \ + EXTRA_DATA \ + .align 4; .global begin_signature; begin_signature: + +#define RVTEST_DATA_END \ + _msg_init: .asciz "RUN\r\n"; \ + _msg_pass: .asciz "PASS"; \ + _msg_fail: .asciz "FAIL "; \ + _msg_end: .asciz "\r\n"; \ + .align 4; .global end_signature; end_signature: + +#endif /* _RISCV_TEST_DEFAULTS_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/sections.h b/fpga/src/main/resources/vcu118/sdboot/include/sections.h new file mode 100644 index 00000000..6e1f0518 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/sections.h @@ -0,0 +1,17 @@ +// See LICENSE for license details. +#ifndef _SECTIONS_H +#define _SECTIONS_H + +extern unsigned char _rom[]; +extern unsigned char _rom_end[]; + +extern unsigned char _ram[]; +extern unsigned char _ram_end[]; + +extern unsigned char _ftext[]; +extern unsigned char _etext[]; +extern unsigned char _fbss[]; +extern unsigned char _ebss[]; +extern unsigned char _end[]; + +#endif /* _SECTIONS_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/include/smp.h b/fpga/src/main/resources/vcu118/sdboot/include/smp.h new file mode 100644 index 00000000..145ceb37 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/include/smp.h @@ -0,0 +1,142 @@ +#ifndef SIFIVE_SMP +#define SIFIVE_SMP +#include "platform.h" + +// The maximum number of HARTs this code supports +#ifndef MAX_HARTS +#define MAX_HARTS 32 +#endif +#define CLINT_END_HART_IPI CLINT_CTRL_ADDR + (MAX_HARTS*4) +#define CLINT1_END_HART_IPI CLINT1_CTRL_ADDR + (MAX_HARTS*4) + +// The hart that non-SMP tests should run on +#ifndef NONSMP_HART +#define NONSMP_HART 0 +#endif + +/* If your test cannot handle multiple-threads, use this: + * smp_disable(reg1) + */ +#define smp_disable(reg1, reg2) \ + csrr reg1, mhartid ;\ + li reg2, NONSMP_HART ;\ + beq reg1, reg2, hart0_entry ;\ +42: ;\ + wfi ;\ + j 42b ;\ +hart0_entry: + +/* If your test needs to temporarily block multiple-threads, do this: + * smp_pause(reg1, reg2) + * ... single-threaded work ... + * smp_resume(reg1, reg2) + * ... multi-threaded work ... + */ + +#define smp_pause(reg1, reg2) \ + li reg2, 0x8 ;\ + csrw mie, reg2 ;\ + li reg1, NONSMP_HART ;\ + csrr reg2, mhartid ;\ + bne reg1, reg2, 42f + +#ifdef CLINT1_CTRL_ADDR +// If a second CLINT exists, then make sure we: +// 1) Trigger a software interrupt on all harts of both CLINTs. +// 2) Locate your own hart's software interrupt pending register and clear it. +// 3) Wait for all harts on both CLINTs to clear their software interrupt +// pending register. +// WARNING: This code makes these assumptions, which are only true for Fadu as +// of now: +// 1) hart0 uses CLINT0 at offset 0 +// 2) hart2 uses CLINT1 at offset 0 +// 3) hart3 uses CLINT1 at offset 1 +// 4) There are no other harts or CLINTs in the system. +#define smp_resume(reg1, reg2) \ + /* Trigger software interrupt on CLINT0 */ \ + li reg1, CLINT_CTRL_ADDR ;\ +41: ;\ + li reg2, 1 ;\ + sw reg2, 0(reg1) ;\ + addi reg1, reg1, 4 ;\ + li reg2, CLINT_END_HART_IPI ;\ + blt reg1, reg2, 41b ;\ + /* Trigger software interrupt on CLINT1 */ \ + li reg1, CLINT1_CTRL_ADDR ;\ +41: ;\ + li reg2, 1 ;\ + sw reg2, 0(reg1) ;\ + addi reg1, reg1, 4 ;\ + li reg2, CLINT1_END_HART_IPI ;\ + blt reg1, reg2, 41b ;\ + /* Wait to receive software interrupt */ \ +42: ;\ + wfi ;\ + csrr reg2, mip ;\ + andi reg2, reg2, 0x8 ;\ + beqz reg2, 42b ;\ + /* Clear own software interrupt bit */ \ + csrr reg2, mhartid ;\ + bnez reg2, 41f; \ + /* hart0 case: Use CLINT0 */ \ + li reg1, CLINT_CTRL_ADDR ;\ + slli reg2, reg2, 2 ;\ + add reg2, reg2, reg1 ;\ + sw zero, 0(reg2) ;\ + j 42f; \ +41: \ + /* hart 2, 3 case: Use CLINT1 and remap hart IDs to 0 and 1 */ \ + li reg1, CLINT1_CTRL_ADDR ;\ + addi reg2, reg2, -2; \ + slli reg2, reg2, 2 ;\ + add reg2, reg2, reg1 ;\ + sw zero, 0(reg2) ; \ +42: \ + /* Wait for all software interrupt bits to be cleared on CLINT0 */ \ + li reg1, CLINT_CTRL_ADDR ;\ +41: ;\ + lw reg2, 0(reg1) ;\ + bnez reg2, 41b ;\ + addi reg1, reg1, 4 ;\ + li reg2, CLINT_END_HART_IPI ;\ + blt reg1, reg2, 41b; \ + /* Wait for all software interrupt bits to be cleared on CLINT1 */ \ + li reg1, CLINT1_CTRL_ADDR ;\ +41: ;\ + lw reg2, 0(reg1) ;\ + bnez reg2, 41b ;\ + addi reg1, reg1, 4 ;\ + li reg2, CLINT1_END_HART_IPI ;\ + blt reg1, reg2, 41b; \ + /* End smp_resume() */ + +#else + +#define smp_resume(reg1, reg2) \ + li reg1, CLINT_CTRL_ADDR ;\ +41: ;\ + li reg2, 1 ;\ + sw reg2, 0(reg1) ;\ + addi reg1, reg1, 4 ;\ + li reg2, CLINT_END_HART_IPI ;\ + blt reg1, reg2, 41b ;\ +42: ;\ + wfi ;\ + csrr reg2, mip ;\ + andi reg2, reg2, 0x8 ;\ + beqz reg2, 42b ;\ + li reg1, CLINT_CTRL_ADDR ;\ + csrr reg2, mhartid ;\ + slli reg2, reg2, 2 ;\ + add reg2, reg2, reg1 ;\ + sw zero, 0(reg2) ;\ +41: ;\ + lw reg2, 0(reg1) ;\ + bnez reg2, 41b ;\ + addi reg1, reg1, 4 ;\ + li reg2, CLINT_END_HART_IPI ;\ + blt reg1, reg2, 41b + +#endif /* ifdef CLINT1_CTRL_ADDR */ + +#endif diff --git a/fpga/src/main/resources/vcu118/sdboot/kprintf.c b/fpga/src/main/resources/vcu118/sdboot/kprintf.c new file mode 100644 index 00000000..57627011 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/kprintf.c @@ -0,0 +1,75 @@ +// See LICENSE for license details. +#include +#include +#include + +#include "kprintf.h" + +static inline void _kputs(const char *s) +{ + char c; + for (; (c = *s) != '\0'; s++) + kputc(c); +} + +void kputs(const char *s) +{ + _kputs(s); + kputc('\r'); + kputc('\n'); +} + +void kprintf(const char *fmt, ...) +{ + va_list vl; + bool is_format, is_long, is_char; + char c; + + va_start(vl, fmt); + is_format = false; + is_long = false; + is_char = false; + while ((c = *fmt++) != '\0') { + if (is_format) { + switch (c) { + case 'l': + is_long = true; + continue; + case 'h': + is_char = true; + continue; + case 'x': { + unsigned long n; + long i; + if (is_long) { + n = va_arg(vl, unsigned long); + i = (sizeof(unsigned long) << 3) - 4; + } else { + n = va_arg(vl, unsigned int); + i = is_char ? 4 : (sizeof(unsigned int) << 3) - 4; + } + for (; i >= 0; i -= 4) { + long d; + d = (n >> i) & 0xF; + kputc(d < 10 ? '0' + d : 'a' + d - 10); + } + break; + } + case 's': + _kputs(va_arg(vl, const char *)); + break; + case 'c': + kputc(va_arg(vl, int)); + break; + } + is_format = false; + is_long = false; + is_char = false; + } else if (c == '%') { + is_format = true; + } else { + kputc(c); + } + } + va_end(vl); +} diff --git a/fpga/src/main/resources/vcu118/sdboot/kprintf.h b/fpga/src/main/resources/vcu118/sdboot/kprintf.h new file mode 100644 index 00000000..26cc8055 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/kprintf.h @@ -0,0 +1,49 @@ +// See LICENSE for license details. +#ifndef _SDBOOT_KPRINTF_H +#define _SDBOOT_KPRINTF_H + +#include +#include + +#define REG32(p, i) ((p)[(i) >> 2]) + +#ifndef UART_CTRL_ADDR + #ifndef UART_NUM + #define UART_NUM 0 + #endif + + #define _CONCAT3(A, B, C) A ## B ## C + #define _UART_CTRL_ADDR(UART_NUM) _CONCAT3(UART, UART_NUM, _CTRL_ADDR) + #define UART_CTRL_ADDR _UART_CTRL_ADDR(UART_NUM) +#endif +static volatile uint32_t * const uart = (void *)(UART_CTRL_ADDR); + +static inline void kputc(char c) +{ + volatile uint32_t *tx = ®32(uart, UART_REG_TXFIFO); +#ifdef __riscv_atomic + int32_t r; + do { + __asm__ __volatile__ ( + "amoor.w %0, %2, %1\n" + : "=r" (r), "+A" (*tx) + : "r" (c)); + } while (r < 0); +#else + while ((int32_t)(*tx) < 0); + *tx = c; +#endif +} + +extern void kputs(const char *); +extern void kprintf(const char *, ...); + +#ifdef DEBUG +#define dprintf(s, ...) kprintf((s), ##__VA_ARGS__) +#define dputs(s) kputs((s)) +#else +#define dprintf(s, ...) do { } while (0) +#define dputs(s) do { } while (0) +#endif + +#endif /* _SDBOOT_KPRINTF_H */ diff --git a/fpga/src/main/resources/vcu118/sdboot/linker/memory.lds b/fpga/src/main/resources/vcu118/sdboot/linker/memory.lds new file mode 100644 index 00000000..997de4d3 --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/linker/memory.lds @@ -0,0 +1,5 @@ +MEMORY +{ + bootrom_mem (rx) : ORIGIN = 0x10000, LENGTH = 0x2000 + memory_mem (rwx) : ORIGIN = 0x80000000, LENGTH = 0x40000000 +} diff --git a/fpga/src/main/resources/vcu118/sdboot/linker/sdboot.elf.lds b/fpga/src/main/resources/vcu118/sdboot/linker/sdboot.elf.lds new file mode 100644 index 00000000..7a0a42fe --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/linker/sdboot.elf.lds @@ -0,0 +1,80 @@ +OUTPUT_ARCH("riscv") +ENTRY(_prog_start) + +INCLUDE memory.lds + +PHDRS +{ + text PT_LOAD; + data PT_LOAD; + bss PT_LOAD; +} + +SECTIONS +{ + PROVIDE(_ram = ORIGIN(memory_mem)); + PROVIDE(_ram_end = _ram + LENGTH(memory_mem)); + + .text ALIGN((ORIGIN(bootrom_mem) + 0x0), 8) : AT(ALIGN((ORIGIN(bootrom_mem) + 0x0), 8)) { + PROVIDE(_ftext = .); + *(.text.init) + *(.text.unlikely .text.unlikely.*) + *(.text .text.* .gnu.linkonce.t.*) + PROVIDE(_etext = .); + . += 0x40; /* to create a gap between .text and .data b/c ifetch can fetch ahead from .data */ + } >bootrom_mem :text + + .eh_frame ALIGN((ADDR(.text) + SIZEOF(.text)), 8) : AT(ALIGN((LOADADDR(.text) + SIZEOF(.text)), 8)) { + *(.eh_frame) + } >bootrom_mem :text + + .srodata ALIGN((ADDR(.eh_frame) + SIZEOF(.eh_frame)), 8) : AT(ALIGN((LOADADDR(.eh_frame) + SIZEOF(.eh_frame)), 8)) ALIGN_WITH_INPUT { + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata.*) + } >bootrom_mem :data + + .data ALIGN((ADDR(.srodata) + SIZEOF(.srodata)), 8) : AT(ALIGN((LOADADDR(.srodata) + SIZEOF(.srodata)), 8)) ALIGN_WITH_INPUT { + *(.data .data.* .gnu.linkonce.d.*) + *(.tohost) /* TODO: Support sections that aren't explicitly listed in this linker script */ + } >bootrom_mem :data + + .sdata ALIGN((ADDR(.data) + SIZEOF(.data)), 8) : AT(ALIGN((LOADADDR(.data) + SIZEOF(.data)), 8)) ALIGN_WITH_INPUT { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } >bootrom_mem :data + + .rodata ALIGN((ADDR(.sdata) + SIZEOF(.sdata)), 8) : AT(ALIGN((LOADADDR(.sdata) + SIZEOF(.sdata)), 8)) ALIGN_WITH_INPUT { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.dtb) + } >bootrom_mem :data + + PROVIDE(_data = ADDR(.rodata)); + PROVIDE(_data_lma = LOADADDR(.rodata)); + PROVIDE(_edata = .); + + .bss ALIGN((ORIGIN(memory_mem) + 0x0), 8) : AT(ALIGN((ORIGIN(memory_mem) + 0x0), 8)) ALIGN(8) { + PROVIDE(_fbss = .); + PROVIDE(__global_pointer$ = . + 0x7C0); + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.bss .bss.* .gnu.linkonce.b.*) + . = ALIGN(8); + PROVIDE(_ebss = .); + } >memory_mem :bss + + PROVIDE(_end = .); + + /* + * heap_stack_region_usable_end: (ORIGIN(memory_mem) + LENGTH(memory_mem)) + * heap_stack_min_size: 4096 + * heap_stack_max_size: 1048576 + */ + PROVIDE(_sp = ALIGN(MIN((ORIGIN(memory_mem) + LENGTH(memory_mem)), _ebss + 1048576) - 7, 8)); + PROVIDE(_heap_end = _sp - 2048); + + /* This section is a noop and is only used for the ASSERT */ + .stack : { + ASSERT(_sp >= (_ebss + 4096), "Error: No room left for the heap and stack"); + } +} diff --git a/fpga/src/main/resources/vcu118/sdboot/sd.c b/fpga/src/main/resources/vcu118/sdboot/sd.c new file mode 100644 index 00000000..bdd9d62a --- /dev/null +++ b/fpga/src/main/resources/vcu118/sdboot/sd.c @@ -0,0 +1,236 @@ +// See LICENSE for license details. +#include + +#include + +#include "common.h" + +#define DEBUG +#include "kprintf.h" + +#define MAX_CORES 8 + +// A sector is 512 bytes, so ((1 << 11) * 512) = 1 MiB +#define PAYLOAD_SIZE (16 << 11) + +// The sector at which the BBL partition starts +#define BBL_PARTITION_START_SECTOR 34 + +#ifndef TL_CLK +#error Must define TL_CLK +#endif + +#define F_CLK TL_CLK + +static volatile uint32_t * const spi = (void *)(SPI_CTRL_ADDR); + +static inline uint8_t spi_xfer(uint8_t d) +{ + int32_t r; + + REG32(spi, SPI_REG_TXFIFO) = d; + do { + r = REG32(spi, SPI_REG_RXFIFO); + } while (r < 0); + return r; +} + +static inline uint8_t sd_dummy(void) +{ + return spi_xfer(0xFF); +} + +static uint8_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) +{ + unsigned long n; + uint8_t r; + + REG32(spi, SPI_REG_CSMODE) = SPI_CSMODE_HOLD; + sd_dummy(); + spi_xfer(cmd); + spi_xfer(arg >> 24); + spi_xfer(arg >> 16); + spi_xfer(arg >> 8); + spi_xfer(arg); + spi_xfer(crc); + + n = 1000; + do { + r = sd_dummy(); + if (!(r & 0x80)) { +// dprintf("sd:cmd: %hx\r\n", r); + goto done; + } + } while (--n > 0); + kputs("sd_cmd: timeout"); +done: + return r; +} + +static inline void sd_cmd_end(void) +{ + sd_dummy(); + REG32(spi, SPI_REG_CSMODE) = SPI_CSMODE_AUTO; +} + + +static void sd_poweron(void) +{ + long i; + REG32(spi, SPI_REG_SCKDIV) = (F_CLK / 300000UL); + REG32(spi, SPI_REG_CSMODE) = SPI_CSMODE_OFF; + for (i = 10; i > 0; i--) { + sd_dummy(); + } + REG32(spi, SPI_REG_CSMODE) = SPI_CSMODE_AUTO; +} + +static int sd_cmd0(void) +{ + int rc; + dputs("CMD0"); + rc = (sd_cmd(0x40, 0, 0x95) != 0x01); + sd_cmd_end(); + return rc; +} + +static int sd_cmd8(void) +{ + int rc; + dputs("CMD8"); + rc = (sd_cmd(0x48, 0x000001AA, 0x87) != 0x01); + sd_dummy(); /* command version; reserved */ + sd_dummy(); /* reserved */ + rc |= ((sd_dummy() & 0xF) != 0x1); /* voltage */ + rc |= (sd_dummy() != 0xAA); /* check pattern */ + sd_cmd_end(); + return rc; +} + +static void sd_cmd55(void) +{ + sd_cmd(0x77, 0, 0x65); + sd_cmd_end(); +} + +static int sd_acmd41(void) +{ + uint8_t r; + dputs("ACMD41"); + do { + sd_cmd55(); + r = sd_cmd(0x69, 0x40000000, 0x77); /* HCS = 1 */ + } while (r == 0x01); + return (r != 0x00); +} + +static int sd_cmd58(void) +{ + int rc; + dputs("CMD58"); + rc = (sd_cmd(0x7A, 0, 0xFD) != 0x00); + rc |= ((sd_dummy() & 0x80) != 0x80); /* Power up status */ + sd_dummy(); + sd_dummy(); + sd_dummy(); + sd_cmd_end(); + return rc; +} + +static int sd_cmd16(void) +{ + int rc; + dputs("CMD16"); + rc = (sd_cmd(0x50, 0x200, 0x15) != 0x00); + sd_cmd_end(); + return rc; +} + +static uint16_t crc16_round(uint16_t crc, uint8_t data) { + crc = (uint8_t)(crc >> 8) | (crc << 8); + crc ^= data; + crc ^= (uint8_t)(crc >> 4) & 0xf; + crc ^= crc << 12; + crc ^= (crc & 0xff) << 5; + return crc; +} + +#define SPIN_SHIFT 6 +#define SPIN_UPDATE(i) (!((i) & ((1 << SPIN_SHIFT)-1))) +#define SPIN_INDEX(i) (((i) >> SPIN_SHIFT) & 0x3) + +static const char spinner[] = { '-', '/', '|', '\\' }; + +static int copy(void) +{ + volatile uint8_t *p = (void *)(PAYLOAD_DEST); + long i = PAYLOAD_SIZE; + int rc = 0; + + dputs("CMD18"); + kprintf("LOADING "); + + // John: Let's go slow until we get this working + //REG32(spi, SPI_REG_SCKDIV) = (F_CLK / 16666666UL); + REG32(spi, SPI_REG_SCKDIV) = (F_CLK / 5000000UL); + if (sd_cmd(0x52, BBL_PARTITION_START_SECTOR, 0xE1) != 0x00) { + sd_cmd_end(); + return 1; + } + do { + uint16_t crc, crc_exp; + long n; + + crc = 0; + n = 512; + while (sd_dummy() != 0xFE); + do { + uint8_t x = sd_dummy(); + *p++ = x; + crc = crc16_round(crc, x); + } while (--n > 0); + + crc_exp = ((uint16_t)sd_dummy() << 8); + crc_exp |= sd_dummy(); + + if (crc != crc_exp) { + kputs("\b- CRC mismatch "); + rc = 1; + break; + } + + if (SPIN_UPDATE(i)) { + kputc('\b'); + kputc(spinner[SPIN_INDEX(i)]); + } + } while (--i > 0); + sd_cmd_end(); + + sd_cmd(0x4C, 0, 0x01); + sd_cmd_end(); + kputs("\b "); + return rc; +} + +int main(void) +{ + REG32(uart, UART_REG_TXCTRL) = UART_TXEN; + + kputs("INIT"); + sd_poweron(); + if (sd_cmd0() || + sd_cmd8() || + sd_acmd41() || + sd_cmd58() || + sd_cmd16() || + copy()) { + kputs("ERROR"); + return 1; + } + + kputs("BOOT"); + + __asm__ __volatile__ ("fence.i" : : : "memory"); + + return 0; +} diff --git a/fpga/src/main/scala/arty/TestHarness.scala b/fpga/src/main/scala/arty/TestHarness.scala new file mode 100644 index 00000000..6571f3d6 --- /dev/null +++ b/fpga/src/main/scala/arty/TestHarness.scala @@ -0,0 +1,34 @@ +//package chipyard.fpga.arty +// +//import chisel3._ +//import chisel3.experimental.{Analog} +// +//import freechips.rocketchip.diplomacy.{LazyModule} +//import freechips.rocketchip.config.{Parameters} +// +//import sifive.fpgashells.shell.xilinx.artyshell.{ArtyShell} +// +//import chipyard.{BuildTop, HasHarnessSignalReferences} +// +//class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell with HasHarnessSignalReferences { +// +// val ldut = LazyModule(p(BuildTop)(p)).suggestName("chiptop") +// +// // turn IO clock into Reset type +// val hReset = Wire(Reset()) +// hReset := ck_rst +// +// // default to 32MHz clock +// withClockAndReset(clock_32MHz, hReset) { +// val dut = Module(ldut.module) +// } +// +// val harnessClock = clock_32MHz +// val harnessReset = hReset +// val success = false.B +// val dutReset = hReset +// +// // must be after HasHarnessSignalReferences assignments +// ldut.harnessFunctions.foreach(_(this)) +//} +// diff --git a/fpga/src/main/scala/arty/e300/Configs.scala b/fpga/src/main/scala/arty/e300/Configs.scala new file mode 100644 index 00000000..9e04d8df --- /dev/null +++ b/fpga/src/main/scala/arty/e300/Configs.scala @@ -0,0 +1,72 @@ +//// See LICENSE for license details. +//package chipyard.fpga.arty.e300 +// +//import freechips.rocketchip.config._ +//import freechips.rocketchip.subsystem._ +//import freechips.rocketchip.devices.debug._ +//import freechips.rocketchip.devices.tilelink._ +//import freechips.rocketchip.diplomacy.{DTSModel, DTSTimebase} +//import freechips.rocketchip.system._ +//import freechips.rocketchip.tile._ +// +//import sifive.blocks.devices.mockaon._ +//import sifive.blocks.devices.gpio._ +//import sifive.blocks.devices.pwm._ +//import sifive.blocks.devices.spi._ +//import sifive.blocks.devices.uart._ +//import sifive.blocks.devices.i2c._ +// +//import chipyard.{BuildSystem} +// +//class E300DevKitExtra extends Config((site, here, up) => { +// case PeripheryGPIOKey => List( +// GPIOParams(address = 0x10012000, width = 32, includeIOF = true)) +// case PeripheryPWMKey => List( +// PWMParams(address = 0x10015000, cmpWidth = 8), +// PWMParams(address = 0x10025000, cmpWidth = 16), +// PWMParams(address = 0x10035000, cmpWidth = 16)) +// case PeripherySPIKey => List( +// SPIParams(csWidth = 4, rAddress = 0x10024000, defaultSampleDel = 3), +// SPIParams(csWidth = 1, rAddress = 0x10034000, defaultSampleDel = 3)) +// case PeripherySPIFlashKey => List( +// SPIFlashParams( +// fAddress = 0x20000000, +// rAddress = 0x10014000, +// defaultSampleDel = 3)) +// case PeripheryUARTKey => List( +// UARTParams(address = 0x10013000), +// UARTParams(address = 0x10023000)) +// case PeripheryI2CKey => List( +// I2CParams(address = 0x10016000)) +// case PeripheryMockAONKey => +// MockAONParams(address = 0x10000000) +// case DTSTimebase => BigInt(32768) +// case JtagDTMKey => new JtagDTMConfig ( +// idcodeVersion = 2, +// idcodePartNum = 0x000, +// idcodeManufId = 0x489, +// debugIdleCycles = 5) +//}) +// +//class WithE300System extends Config((site, here, up) => { +// case BuildSystem => (p: Parameters) => new E300DigitalTop()(p) +//}) +// +//class E300ArtyDevKitConfig extends Config( +// new WithE300System ++ +// new WithE300Connections ++ +// new E300DevKitExtra ++ +// new chipyard.config.WithBootROM ++ +// new chipyard.config.WithL2TLBs(1024) ++ +// new freechips.rocketchip.subsystem.With1TinyCore ++ +// new freechips.rocketchip.subsystem.WithNBanks(0) ++ +// new freechips.rocketchip.subsystem.WithNoMemPort ++ +// new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ +// new freechips.rocketchip.subsystem.WithNBreakpoints(2) ++ +// new freechips.rocketchip.subsystem.WithJtagDTM ++ +// new freechips.rocketchip.subsystem.WithNoMMIOPort ++ +// new freechips.rocketchip.subsystem.WithNoSlavePort ++ +// new freechips.rocketchip.subsystem.WithInclusiveCache ++ +// new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ +// new freechips.rocketchip.subsystem.WithIncoherentBusTopology ++ +// new freechips.rocketchip.system.BaseConfig) diff --git a/fpga/src/main/scala/arty/e300/DigitalTop.scala b/fpga/src/main/scala/arty/e300/DigitalTop.scala new file mode 100644 index 00000000..45018c00 --- /dev/null +++ b/fpga/src/main/scala/arty/e300/DigitalTop.scala @@ -0,0 +1,23 @@ +//package chipyard.fpga.arty.e300 +// +//import chisel3._ +// +//import freechips.rocketchip.subsystem._ +//import freechips.rocketchip.system._ +//import freechips.rocketchip.config.Parameters +//import freechips.rocketchip.devices.tilelink._ +// +//import chipyard.{DigitalTop, DigitalTopModule} +// +//// ------------------------------------ +//// E300 DigitalTop +//// ------------------------------------ +// +//class E300DigitalTop(implicit p: Parameters) extends DigitalTop +// with sifive.blocks.devices.mockaon.HasPeripheryMockAON +//{ +// override lazy val module = new E300DigitalTopModule(this) +//} +// +//class E300DigitalTopModule[+L <: E300DigitalTop](l: L) extends DigitalTopModule(l) +// with sifive.blocks.devices.mockaon.HasPeripheryMockAONModuleImp diff --git a/fpga/src/main/scala/arty/e300/IOBinders.scala b/fpga/src/main/scala/arty/e300/IOBinders.scala new file mode 100644 index 00000000..82da669c --- /dev/null +++ b/fpga/src/main/scala/arty/e300/IOBinders.scala @@ -0,0 +1,365 @@ +//package chipyard.fpga.arty.e300 +// +//import chisel3._ +//import chisel3.experimental.{attach, IO} +// +//import freechips.rocketchip.util._ +//import freechips.rocketchip.devices.debug._ +//import freechips.rocketchip.subsystem.{NExtTopInterrupts} +// +//import sifive.blocks.devices.gpio._ +//import sifive.blocks.devices.uart._ +//import sifive.blocks.devices.spi._ +//import sifive.blocks.devices.pwm._ +//import sifive.blocks.devices.i2c._ +//import sifive.blocks.devices.mockaon._ +//import sifive.blocks.devices.jtag._ +//import sifive.blocks.devices.pinctrl._ +// +//import sifive.fpgashells.shell.xilinx.artyshell.{ArtyShell} +//import sifive.fpgashells.ip.xilinx.{IBUFG, IOBUF, PULLUP, PowerOnResetFPGAOnly} +// +//import chipsalliance.rocketchip.config._ +// +//import chipyard.iobinders.{OverrideIOBinder, GetSystemParameters} +//import chipyard.{HasHarnessSignalReferences} +// +//class WithE300Connections extends OverrideIOBinder({ +// (system: HasPeripheryGPIOModuleImp +// with HasPeripheryUARTModuleImp +// with HasPeripherySPIModuleImp +// with HasPeripheryDebugModuleImp +// with HasPeripheryPWMModuleImp +// with HasPeripherySPIFlashModuleImp +// with HasPeripheryMockAONModuleImp +// with HasPeripheryI2CModuleImp) => { +// +// implicit val p: Parameters = GetSystemParameters(system) +// +// //----------------------------------------------------------------------- +// //----------------------------------------------------------------------- +// // E300DigitalTop <-> ChipTop connections +// //----------------------------------------------------------------------- +// //----------------------------------------------------------------------- +// +// object PinGen { +// def apply(): BasePin = { +// val pin = new BasePin() +// pin +// } +// } +// +// val io_jtag = IO(new JTAGPins(() => PinGen(), false)).suggestName("jtag") +// val io_gpio = IO(new GPIOPins(() => PinGen(), p(PeripheryGPIOKey)(0))).suggestName("gpio") +// val io_qspi = IO(new SPIPins(() => PinGen(), p(PeripherySPIFlashKey)(0))).suggestName("qspi") +// val io_aon = IO(new MockAONWrapperPins()).suggestName("aon") +// val io_jtag_reset = IO(Input(Bool())).suggestName("jtag_reset") +// val io_ndreset = IO(Output(Bool())).suggestName("ndreset") +// +// // This needs to be de-asserted synchronously to the coreClk. +// val async_corerst = system.aon.rsts.corerst +// // Add in debug-controlled reset. +// system.reset := ResetCatchAndSync(system.clock, async_corerst, 20) +// Debug.connectDebugClockAndReset(system.debug, system.clock) +// +// //----------------------------------------------------------------------- +// // Check for unsupported rocket-chip connections +// //----------------------------------------------------------------------- +// +// require (p(NExtTopInterrupts) == 0, "No Top-level interrupts supported"); +// +// //----------------------------------------------------------------------- +// // Build GPIO Pin Mux +// //----------------------------------------------------------------------- +// // Pin Mux for UART, SPI, PWM +// // First convert the System outputs into "IOF" using the respective *GPIOPort +// // converters. +// +// val sys_uart = system.uart +// val sys_pwm = system.pwm +// val sys_spi = system.spi +// val sys_i2c = system.i2c +// +// val uart_pins = p(PeripheryUARTKey).map { c => Wire(new UARTPins(() => PinGen()))} +// val pwm_pins = p(PeripheryPWMKey).map { c => Wire(new PWMPins(() => PinGen(), c))} +// val spi_pins = p(PeripherySPIKey).map { c => Wire(new SPIPins(() => PinGen(), c))} +// val i2c_pins = p(PeripheryI2CKey).map { c => Wire(new I2CPins(() => PinGen()))} +// +// (uart_pins zip sys_uart) map {case (p, r) => UARTPinsFromPort(p, r, clock = system.clock, reset = system.reset.asBool, syncStages = 0)} +// (pwm_pins zip sys_pwm) map {case (p, r) => PWMPinsFromPort(p, r) } +// (spi_pins zip sys_spi) map {case (p, r) => SPIPinsFromPort(p, r, clock = system.clock, reset = system.reset.asBool, syncStages = 0)} +// (i2c_pins zip sys_i2c) map {case (p, r) => I2CPinsFromPort(p, r, clock = system.clock, reset = system.reset.asBool, syncStages = 0)} +// +// //----------------------------------------------------------------------- +// // Default Pin connections before attaching pinmux +// +// for (iof_0 <- system.gpio(0).iof_0.get) { +// iof_0.default() +// } +// +// for (iof_1 <- system.gpio(0).iof_1.get) { +// iof_1.default() +// } +// +// //----------------------------------------------------------------------- +// +// val iof_0 = system.gpio(0).iof_0.get +// val iof_1 = system.gpio(0).iof_1.get +// +// // SPI1 (0 is the dedicated) +// BasePinToIOF(spi_pins(0).cs(0), iof_0(2)) +// BasePinToIOF(spi_pins(0).dq(0), iof_0(3)) +// BasePinToIOF(spi_pins(0).dq(1), iof_0(4)) +// BasePinToIOF(spi_pins(0).sck, iof_0(5)) +// BasePinToIOF(spi_pins(0).dq(2), iof_0(6)) +// BasePinToIOF(spi_pins(0).dq(3), iof_0(7)) +// BasePinToIOF(spi_pins(0).cs(1), iof_0(8)) +// BasePinToIOF(spi_pins(0).cs(2), iof_0(9)) +// BasePinToIOF(spi_pins(0).cs(3), iof_0(10)) +// +// // SPI2 +// BasePinToIOF(spi_pins(1).cs(0), iof_0(26)) +// BasePinToIOF(spi_pins(1).dq(0), iof_0(27)) +// BasePinToIOF(spi_pins(1).dq(1), iof_0(28)) +// BasePinToIOF(spi_pins(1).sck, iof_0(29)) +// BasePinToIOF(spi_pins(1).dq(2), iof_0(30)) +// BasePinToIOF(spi_pins(1).dq(3), iof_0(31)) +// +// // I2C +// if (p(PeripheryI2CKey).length == 1) { +// BasePinToIOF(i2c_pins(0).sda, iof_0(12)) +// BasePinToIOF(i2c_pins(0).scl, iof_0(13)) +// } +// +// // UART0 +// BasePinToIOF(uart_pins(0).rxd, iof_0(16)) +// BasePinToIOF(uart_pins(0).txd, iof_0(17)) +// +// // UART1 +// BasePinToIOF(uart_pins(1).rxd, iof_0(24)) +// BasePinToIOF(uart_pins(1).txd, iof_0(25)) +// +// //PWM +// BasePinToIOF(pwm_pins(0).pwm(0), iof_1(0) ) +// BasePinToIOF(pwm_pins(0).pwm(1), iof_1(1) ) +// BasePinToIOF(pwm_pins(0).pwm(2), iof_1(2) ) +// BasePinToIOF(pwm_pins(0).pwm(3), iof_1(3) ) +// +// BasePinToIOF(pwm_pins(1).pwm(1), iof_1(19)) +// BasePinToIOF(pwm_pins(1).pwm(0), iof_1(20)) +// BasePinToIOF(pwm_pins(1).pwm(2), iof_1(21)) +// BasePinToIOF(pwm_pins(1).pwm(3), iof_1(22)) +// +// BasePinToIOF(pwm_pins(2).pwm(0), iof_1(10)) +// BasePinToIOF(pwm_pins(2).pwm(1), iof_1(11)) +// BasePinToIOF(pwm_pins(2).pwm(2), iof_1(12)) +// BasePinToIOF(pwm_pins(2).pwm(3), iof_1(13)) +// +// //----------------------------------------------------------------------- +// // Drive actual Pads +// //----------------------------------------------------------------------- +// +// // Result of Pin Mux +// GPIOPinsFromPort(io_gpio, system.gpio(0)) +// +// // Dedicated SPI Pads +// SPIPinsFromPort(io_qspi, system.qspi(0), clock = system.clock, reset = system.reset.asBool, syncStages = 3) +// +// // JTAG Debug Interface +// val sjtag = system.debug.get.systemjtag.get +// JTAGPinsFromPort(io_jtag, sjtag.jtag) +// sjtag.reset := io_jtag_reset +// sjtag.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) +// +// io_ndreset := system.debug.get.ndreset +// +// // AON Pads -- direct connection is OK because +// // EnhancedPin is hard-coded in MockAONPads +// // and thus there is no .fromPort method. +// io_aon <> system.aon.pins +// +// //----------------------------------------------------------------------- +// //----------------------------------------------------------------------- +// // Harness Function (ArtyHarness <-> ChipTop) +// //----------------------------------------------------------------------- +// //----------------------------------------------------------------------- +// val harnessFn = (baseTh: HasHarnessSignalReferences) => { +// baseTh match { case th: ArtyShell => +// +// //----------------------------------------------------------------------- +// // Clock divider +// //----------------------------------------------------------------------- +// val slow_clock = Wire(Bool()) +// +// // Divide clock by 256, used to generate 32.768 kHz clock for AON block +// withClockAndReset(th.clock_8MHz, ~th.mmcm_locked) { +// val clockToggleReg = RegInit(false.B) +// val (_, slowTick) = chisel3.util.Counter(true.B, 256) +// when (slowTick) {clockToggleReg := ~clockToggleReg} +// slow_clock := clockToggleReg +// } +// +// //----------------------------------------------------------------------- +// // DUT +// //----------------------------------------------------------------------- +// withClockAndReset(th.clock_32MHz, th.ck_rst) { +// +// //--------------------------------------------------------------------- +// // SPI flash IOBUFs +// //--------------------------------------------------------------------- +// +// IOBUF(th.qspi_sck, io_qspi.sck) +// IOBUF(th.qspi_cs, io_qspi.cs(0)) +// +// IOBUF(th.qspi_dq(0), io_qspi.dq(0)) +// IOBUF(th.qspi_dq(1), io_qspi.dq(1)) +// IOBUF(th.qspi_dq(2), io_qspi.dq(2)) +// IOBUF(th.qspi_dq(3), io_qspi.dq(3)) +// +// //--------------------------------------------------------------------- +// // JTAG IOBUFs +// //--------------------------------------------------------------------- +// +// io_jtag.TCK.i.ival := IBUFG(IOBUF(th.jd_2).asClock).asUInt +// +// IOBUF(th.jd_5, io_jtag.TMS) +// PULLUP(th.jd_5) +// +// IOBUF(th.jd_4, io_jtag.TDI) +// PULLUP(th.jd_4) +// +// IOBUF(th.jd_0, io_jtag.TDO) +// +// // mimic putting a pullup on this line (part of reset vote) +// th.SRST_n := IOBUF(th.jd_6) +// PULLUP(th.jd_6) +// +// // jtag reset +// val jtag_power_on_reset = PowerOnResetFPGAOnly(th.clock_32MHz) +// io_jtag_reset := jtag_power_on_reset +// +// // debug reset +// th.dut_ndreset := io_ndreset +// +// //--------------------------------------------------------------------- +// // Assignment to package pins +// //--------------------------------------------------------------------- +// // Pins IO0-IO13 +// // +// // FTDI UART TX/RX are not connected to th.ck_io[0,1] +// // the way they are on Arduino boards. We copy outgoing +// // data to both places, switch 3 (sw[3]) determines whether +// // input to UART comes from FTDI chip or gpio_16 (shield pin PD0) +// +// val iobuf_ck0 = Module(new IOBUF()) +// iobuf_ck0.io.I := io_gpio.pins(16).o.oval +// iobuf_ck0.io.T := ~io_gpio.pins(16).o.oe +// attach(iobuf_ck0.io.IO, th.ck_io(0)) // UART0 RX +// +// val iobuf_uart_txd = Module(new IOBUF()) +// iobuf_uart_txd.io.I := io_gpio.pins(16).o.oval +// iobuf_uart_txd.io.T := ~io_gpio.pins(16).o.oe +// attach(iobuf_uart_txd.io.IO, th.uart_txd_in) +// +// // gpio(16) input is shared between FTDI TX pin and the Arduino shield pin using SW[3] +// val sw_3_in = IOBUF(th.sw_3) +// io_gpio.pins(16).i.ival := Mux(sw_3_in, +// iobuf_ck0.io.O & io_gpio.pins(16).o.ie, +// iobuf_uart_txd.io.O & io_gpio.pins(16).o.ie) +// +// IOBUF(th.uart_rxd_out, io_gpio.pins(17)) +// +// // Shield header row 0: PD2-PD7 +// IOBUF(th.ck_io(2), io_gpio.pins(18)) +// IOBUF(th.ck_io(3), io_gpio.pins(19)) // PWM1(1) +// IOBUF(th.ck_io(4), io_gpio.pins(20)) // PWM1(0) +// IOBUF(th.ck_io(5), io_gpio.pins(21)) // PWM1(2) +// IOBUF(th.ck_io(6), io_gpio.pins(22)) // PWM1(3) +// IOBUF(th.ck_io(7), io_gpio.pins(23)) +// +// // Header row 1: PB0-PB5 +// IOBUF(th.ck_io(8), io_gpio.pins(0)) // PWM0(0) +// IOBUF(th.ck_io(9), io_gpio.pins(1)) // PWM0(1) +// IOBUF(th.ck_io(10), io_gpio.pins(2)) // SPI CS(0) / PWM0(2) +// IOBUF(th.ck_io(11), io_gpio.pins(3)) // SPI MOSI / PWM0(3) +// IOBUF(th.ck_io(12), io_gpio.pins(4)) // SPI MISO +// IOBUF(th.ck_io(13), io_gpio.pins(5)) // SPI SCK +// +// io_gpio.pins(6).i.ival := 0.U +// io_gpio.pins(7).i.ival := 0.U +// io_gpio.pins(8).i.ival := 0.U +// +// // Header row 3: A0-A5 (we don't support using them as analog inputs) +// // just treat them as regular digital GPIOs +// IOBUF(th.ck_io(15), io_gpio.pins(9)) // A1 = CS(2) +// IOBUF(th.ck_io(16), io_gpio.pins(10)) // A2 = CS(3) / PWM2(0) +// IOBUF(th.ck_io(17), io_gpio.pins(11)) // A3 = PWM2(1) +// IOBUF(th.ck_io(18), io_gpio.pins(12)) // A4 = PWM2(2) / SDA +// IOBUF(th.ck_io(19), io_gpio.pins(13)) // A5 = PWM2(3) / SCL +// +// // Mirror outputs of GPIOs with PWM peripherals to RGB LEDs on Arty +// // assign RGB LED0 R,G,B inputs = PWM0(1,2,3) when iof_1 is active +// IOBUF(th.led0_r, io_gpio.pins(1)) +// IOBUF(th.led0_g, io_gpio.pins(2)) +// IOBUF(th.led0_b, io_gpio.pins(3)) +// +// // Note that this is the one which is actually connected on the HiFive/Crazy88 +// // Board. Same with RGB LED1 R,G,B inputs = PWM1(1,2,3) when iof_1 is active +// IOBUF(th.led1_r, io_gpio.pins(19)) +// IOBUF(th.led1_g, io_gpio.pins(21)) +// IOBUF(th.led1_b, io_gpio.pins(22)) +// +// // and RGB LED2 R,G,B inputs = PWM2(1,2,3) when iof_1 is active +// IOBUF(th.led2_r, io_gpio.pins(11)) +// IOBUF(th.led2_g, io_gpio.pins(12)) +// IOBUF(th.led2_b, io_gpio.pins(13)) +// +// // Only 19 out of 20 shield pins connected to GPIO pins +// // Shield pin A5 (pin 14) left unconnected +// // The buttons are connected to some extra GPIO pins not connected on the +// // HiFive1 board +// IOBUF(th.btn_0, io_gpio.pins(15)) +// IOBUF(th.btn_1, io_gpio.pins(30)) +// IOBUF(th.btn_2, io_gpio.pins(31)) +// +// val iobuf_btn_3 = Module(new IOBUF()) +// iobuf_btn_3.io.I := ~io_aon.pmu.dwakeup_n.o.oval +// iobuf_btn_3.io.T := ~io_aon.pmu.dwakeup_n.o.oe +// attach(th.btn_3, iobuf_btn_3.io.IO) +// io_aon.pmu.dwakeup_n.i.ival := ~iobuf_btn_3.io.O & io_aon.pmu.dwakeup_n.o.ie +// +// // UART1 RX/TX pins are assigned to PMOD_D connector pins 0/1 +// IOBUF(th.ja_0, io_gpio.pins(25)) // UART1 TX +// IOBUF(th.ja_1, io_gpio.pins(24)) // UART1 RX +// +// // SPI2 pins mapped to 6 pin ICSP connector (standard on later +// // arduinos) These are connected to some extra GPIO pins not connected +// // on the HiFive1 board +// IOBUF(th.ck_ss, io_gpio.pins(26)) +// IOBUF(th.ck_mosi, io_gpio.pins(27)) +// IOBUF(th.ck_miso, io_gpio.pins(28)) +// IOBUF(th.ck_sck, io_gpio.pins(29)) +// +// // Use the LEDs for some more useful debugging things +// IOBUF(th.led_0, th.ck_rst) +// IOBUF(th.led_1, th.SRST_n) +// IOBUF(th.led_2, io_aon.pmu.dwakeup_n.i.ival) +// IOBUF(th.led_3, io_gpio.pins(14)) +// +// //--------------------------------------------------------------------- +// // Unconnected inputs +// //--------------------------------------------------------------------- +// +// io_aon.erst_n.i.ival := ~th.reset_periph +// io_aon.lfextclk.i.ival := slow_clock +// io_aon.pmu.vddpaden.i.ival := 1.U +// } +// +// Nil +// } +// } +// +// Seq((Nil, Nil, Some(harnessFn))) +// } +//}) +// diff --git a/fpga/src/main/scala/vcu118/Configs.scala b/fpga/src/main/scala/vcu118/Configs.scala new file mode 100644 index 00000000..f7b0df10 --- /dev/null +++ b/fpga/src/main/scala/vcu118/Configs.scala @@ -0,0 +1,85 @@ +package chipyard.fpga.vcu118 + +import sys.process._ + +import freechips.rocketchip.config.{Config} +import freechips.rocketchip.subsystem.{SystemBusKey, PeripheryBusKey, ControlBusKey, ExtMem} +import freechips.rocketchip.devices.debug.{DebugModuleKey, ExportDebug, JTAG} +import freechips.rocketchip.devices.tilelink.{DevNullParams, BootROMLocated} +import freechips.rocketchip.diplomacy.{DTSModel, DTSTimebase, RegionType, AddressSet} +import freechips.rocketchip.tile.{XLen} + +import sifive.blocks.devices.spi.{PeripherySPIKey, SPIParams} +import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} + +import sifive.fpgashells.shell.{DesignKey} +import sifive.fpgashells.shell.xilinx.{VCU118ShellPMOD, VCU118DDRSize} + +class WithDefaultPeripherals extends Config((site, here, up) => { + case PeripheryUARTKey => List(UARTParams(address = BigInt(0x64000000L))) + case PeripherySPIKey => List(SPIParams(rAddress = BigInt(0x64001000L))) + case VCU118ShellPMOD => "SDIO" +}) + +class WithSystemModifications extends Config((site, here, up) => { + case DebugModuleKey => None // disable debug module + case ExportDebug => up(ExportDebug).copy(protocols = Set(JTAG)) // don't generate HTIF DTS + case SystemBusKey => up(SystemBusKey).copy( + errorDevice = Some(DevNullParams( + Seq(AddressSet(0x3000, 0xfff)), + maxAtomic=site(XLen)/8, + maxTransfer=128, + region = RegionType.TRACKED))) + case PeripheryBusKey => up(PeripheryBusKey, site).copy(dtsFrequency = + Some(BigDecimal(site(FPGAFrequencyKey)*1000000).setScale(0, BigDecimal.RoundingMode.HALF_UP).toBigInt)) + case ControlBusKey => up(ControlBusKey, site).copy( + errorDevice = None) + case DTSTimebase => BigInt(1000000) + case BootROMLocated(x) => up(BootROMLocated(x), site).map { p => + // invoke makefile for sdboot + val freqMHz = site(FPGAFrequencyKey).toInt * 1000000 + val make = s"make -C fpga/src/main/resources/vcu118/sdboot PBUS_CLK=${freqMHz} bin" + require (make.! == 0, "Failed to build bootrom") + p.copy(hang = 0x10000, contentFileName = s"./fpga/src/main/resources/vcu118/sdboot/build/sdboot.bin") + } + case ExtMem => up(ExtMem, site).map(x => x.copy(master = x.master.copy(size = site(VCU118DDRSize)))) +}) + +class AbstractVCU118Config extends Config( + new WithUART ++ + new WithSPISDCard ++ + new WithDDRMem ++ + new WithUARTIOPassthrough ++ + new WithSPIIOPassthrough ++ + new WithTLIOPassthrough ++ + new WithDefaultPeripherals ++ + new WithSystemModifications ++ // remove debug module, setup busses, use sdboot bootrom, setup ext. mem. size + new freechips.rocketchip.subsystem.WithoutTLMonitors ++ + new chipyard.config.WithNoSubsystemDrivenClocks ++ + new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ + new chipyard.config.WithL2TLBs(1024) ++ + new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ++ + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ + new freechips.rocketchip.subsystem.WithNoSlavePort ++ + new freechips.rocketchip.subsystem.WithInclusiveCache ++ + new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ + new chipyard.WithMulticlockCoherentBusTopology ++ + new freechips.rocketchip.system.BaseConfig) + +class RocketVCU118Config extends Config( + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new AbstractVCU118Config) + +class BoomVCU118Config extends Config( + new WithFPGAFrequency(75) ++ + new boom.common.WithNLargeBooms(1) ++ + new AbstractVCU118Config) + +class WithFPGAFrequency(MHz: Double) extends Config((site, here, up) => { + case FPGAFrequencyKey => MHz +}) + +class WithFPGAFreq25MHz extends WithFPGAFrequency(25) +class WithFPGAFreq50MHz extends WithFPGAFrequency(50) +class WithFPGAFreq75MHz extends WithFPGAFrequency(75) +class WithFPGAFreq100MHz extends WithFPGAFrequency(100) diff --git a/fpga/src/main/scala/vcu118/FMCUtil.scala b/fpga/src/main/scala/vcu118/FMCUtil.scala new file mode 100644 index 00000000..00982585 --- /dev/null +++ b/fpga/src/main/scala/vcu118/FMCUtil.scala @@ -0,0 +1,334 @@ +package chipyard.fpga.vcu118 + +import scala.collection.immutable.HashMap + +// TODO: was typed by hand, so this needs a once-over before it can be considered trustworthy + +object FMCMap { + // Take an FMC pin name and return the VCU118 package pin + // See https://www.xilinx.com/support/documentation/boards_and_kits/vcu118/ug1224-vcu118-eval-bd.pdf + // Pages 97-98 + // Omitted pins are not connected to a GPIO + def apply(fmcPin: String): String = HashMap( + "C10" -> "BD13", + "C11" -> "BE13", + "C14" -> "BB13", + "C15" -> "BB12", + "C18" -> "AW8", + "C19" -> "AW7", + "C22" -> "AP12", + "C23" -> "AR12", + "C26" -> "AL14", + "C27" -> "AM14", + "D1" -> "AK35", + "D8" -> "BF10", + "D9" -> "BF9", + "D11" -> "BE14", + "D12" -> "BF14", + "D14" -> "BA14", + "D15" -> "BB14", + "D17" -> "AY8", + "D18" -> "AY7", + "D20" -> "AR14", + "D21" -> "AT14", + "D23" -> "AN16", + "D24" -> "AP16", + "D26" -> "AK15", + "D27" -> "AL15", + "F1" -> "BA7", + "G2" -> "AV14", + "G3" -> "AV13", + "G6" -> "AY9", + "G7" -> "BA9", + "G9" -> "BD12", + "G10" -> "BE12", + "G12" -> "BE15", + "G13" -> "BF15", + "G15" -> "BC14", + "G16" -> "BC13", + "G18" -> "AV9", + "G19" -> "AV8", + "G21" -> "AW11", + "G22" -> "AY10", + "G24" -> "AW13", + "G25" -> "AY13", + "G27" -> "AT12", + "G28" -> "AU12", + "G30" -> "AN15", + "G31" -> "AP15", + "G33" -> "AM13", + "G34" -> "AM12", + "G36" -> "AK14", + "G37" -> "AK13", + "H2" -> "BB7", + "H4" -> "BC9", + "H5" -> "BC8", + "H7" -> "BC11", + "H8" -> "BD11", + "H10" -> "BF12", + "H11" -> "BF11", + "H13" -> "BC15", + "H14" -> "BD15", + "H16" -> "BA16", + "H17" -> "BA15", + "H19" -> "BB16", + "H20" -> "BC16", + "H22" -> "AW12", + "H23" -> "AY12", + "H25" -> "AU11", + "H26" -> "AV11", + "H28" -> "AP13", + "H29" -> "AR13", + "H31" -> "AV10", + "H32" -> "AW10", + "H34" -> "AK12", + "H35" -> "AL12", + "H37" -> "AJ13", + "H38" -> "AJ12" + )(fmcPin) +} + +object FMCPMap { + // Take an FMC+ pin name and return the VCU118 package pin + // See https://www.xilinx.com/support/documentation/boards_and_kits/vcu118/ug1224-vcu118-eval-bd.pdf + // Pages 100-106 + // Omitted pins are not connected to a GPIO + def apply(fmcpPin: String): String = HashMap( + "A2" -> "AN45", + "A3" -> "AN46", + "A6" -> "AL45", + "A7" -> "AL45", + "A10" -> "AJ45", + "A11" -> "AJ46", + "A14" -> "W45", + "A15" -> "W46", + "A18" -> "U45", + "A19" -> "U46", + "A22" -> "AP42", + "A23" -> "AP43", + "A26" -> "AM42", + "A27" -> "AM43", + "A30" -> "AL40", + "A31" -> "AL41", + "A34" -> "T42", + "A35" -> "T43", + "A38" -> "P42", + "A39" -> "P43", + "B4" -> "AF43", + "B5" -> "AF44", + "B8" -> "AG45", + "B9" -> "AG46", + "B12" -> "N45", + "B13" -> "N46", + "B16" -> "R45", + "B17" -> "R46", + "B24" -> "AJ40", + "B25" -> "AJ41", + "B28" -> "AK42", + "B29" -> "AK43", + "B32" -> "K42", + "B33" -> "K43", + "B36" -> "M42", + "B37" -> "M43", + "C2" -> "AT42", + "C3" -> "AT43", + "C6" -> "AR45", + "C7" -> "AR46", + "C10" -> "AT35", + "C11" -> "AT36", + "C14" -> "AP35", + "C15" -> "AR35", + "C18" -> "AG31", + "C19" -> "AH31", + "C22" -> "R31", + "C23" -> "P31", + "C26" -> "V33", + "C27" -> "V34", + "D1" -> "AK35", + "D8" -> "AL30", + "D9" -> "AL31", + "D11" -> "AP38", + "D12" -> "AR38", + "D14" -> "AJ33", + "D15" -> "AK33", + "D17" -> "AJ35", + "D18" -> "AJ36", + "D20" -> "R34", + "D21" -> "P34", + "D23" -> "Y32", + "D24" -> "W32", + "D26" -> "V32", + "D27" -> "U33", + "E2" -> "V15", + "E3" -> "U15", + "E6" -> "R14", + "E7" -> "P14", + "E9" -> "W14", + "E10" -> "V14", + "E12" -> "V13", + "E13" -> "U12", + "E15" -> "T14", + "E16" -> "R13", + "E18" -> "M15", + "E19" -> "L15", + "F1" -> "AM34", + "F4" -> "N14", + "F5" -> "N13", + "F7" -> "AA13", + "F8" -> "Y13", + "F10" -> "U11", + "F11" -> "T11", + "F13" -> "T16", + "F14" -> "T15", + "F16" -> "M13", + "F17" -> "M12", + "F19" -> "L14", + "F20" -> "L13", + "G2" -> "P35", + "G3" -> "P36", + "G6" -> "AL35", + "G7" -> "AL36", + "G9" -> "AT39", + "G10" -> "AT40", + "G12" -> "AK29", + "G13" -> "AK30", + "G15" -> "AH33", + "G16" -> "AH34", + "G18" -> "AG34", + "G19" -> "AH35", + "G21" -> "N32", + "G22" -> "M32", + "G24" -> "N34", + "G25" -> "N35", + "G27" -> "Y34", + "G28" -> "W34", + "G30" -> "U35", + "G31" -> "T36", + "G33" -> "P37", + "G34" -> "N37", + "G36" -> "L34", + "G37" -> "K34", + "H2" -> "AM33", + "H4" -> "AL32", + "H5" -> "AM32", + "H7" -> "AJ32", + "H8" -> "AK32", + "H10" -> "AR37", + "H11" -> "AT37", + "H13" -> "AP36", + "H14" -> "AP37", + "H16" -> "AJ30", + "H17" -> "AJ31", + "H19" -> "AG32", + "H20" -> "AG33", + "H22" -> "N33", + "H23" -> "M33", + "H25" -> "M35", + "H26" -> "L35", + "H28" -> "T34", + "H29" -> "T35", + "H31" -> "M36", + "H32" -> "L36", + "H34" -> "N38", + "H35" -> "M38", + "H37" -> "L33", + "H38" -> "K33", + "J6" -> "W12", + "J7" -> "V12", + "J9" -> "AA14", + "J10" -> "Y14", + "J12" -> "R12", + "J13" -> "P12", + "J15" -> "M11", + "J16" -> "L11", + "J18" -> "P15", + "J19" -> "N15", + "J21" -> "K12", + "J22" -> "J12", + "K7" -> "AA12", + "K8" -> "Y12", + "K10" -> "U13", + "K11" -> "T13", + "K13" -> "V16", + "K14" -> "U16", + "K16" -> "R11", + "K17" -> "P11", + "K19" -> "K14", + "K20" -> "K13", + "K22" -> "K11", + "K23" -> "J11", + "L4" -> "R40", + "L5" -> "R41", + "L8" -> "AB38", + "L9" -> "AB39", + "L12" -> "AF38", + "L13" -> "AF39", + "L16" -> "AN34", + "L17" -> "AN35", + "L20" -> "AN33", + "L21" -> "AP33", + "L24" -> "AK34", + "L25" -> "AL34", + "L28" -> "AM36", + "L29" -> "AN36", + "M2" -> "AU45", + "M3" -> "AU46", + "M6" -> "AW45", + "M7" -> "AW46", + "M10" -> "BA45", + "M11" -> "BA46", + "M14" -> "BC45", + "M15" -> "BC46", + "M18" -> "W40", + "M19" -> "W41", + "M22" -> "U40", + "M23" -> "U41", + "M26" -> "H42", + "M27" -> "H43", + "M30" -> "F42", + "M31" -> "F43", + "M34" -> "D42", + "M35" -> "D43", + "M38" -> "B42", + "M39" -> "B43", + "Y2" -> "AV42", + "Y3" -> "AV43", + "Y6" -> "BB42", + "Y7" -> "BB43", + "Y10" -> "AE45", + "Y11" -> "AE46", + "Y14" -> "AC45", + "Y15" -> "AC46", + "Y18" -> "AA45", + "Y19" -> "AA46", + "Y22" -> "Y43", + "Y23" -> "Y44", + "Y26" -> "AE40", + "Y27" -> "AE41", + "Y30" -> "AA40", + "Y31" -> "AA41", + "Y34" -> "J45", + "Y35" -> "J46", + "Y38" -> "E45", + "Y39" -> "E46", + "Z1" -> "AM29", + "Z4" -> "AY42", + "Z5" -> "AY43", + "Z8" -> "BD42", + "Z9" -> "BD43", + "Z12" -> "AD43", + "Z13" -> "AD44", + "Z16" -> "AB43", + "Z17" -> "AB44", + "Z20" -> "AN40", + "Z21" -> "AN41", + "Z24" -> "AG40", + "Z25" -> "AG41", + "Z28" -> "AC40", + "Z29" -> "AC41", + "Z32" -> "L45", + "Z33" -> "L46", + "Z36" -> "G45", + "Z37" -> "G46" + )(fmcpPin) +} diff --git a/fpga/src/main/scala/vcu118/HarnessBinders.scala b/fpga/src/main/scala/vcu118/HarnessBinders.scala new file mode 100644 index 00000000..ae2462a2 --- /dev/null +++ b/fpga/src/main/scala/vcu118/HarnessBinders.scala @@ -0,0 +1,51 @@ +package chipyard.fpga.vcu118 + +import chisel3._ +import chisel3.experimental.{BaseModule} + +import freechips.rocketchip.util.{HeterogeneousBag} +import freechips.rocketchip.tilelink.{TLBundle} + +import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp, UARTPortIO} +import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO} + +import chipyard.{CanHaveMasterTLMemPort, HasHarnessSignalReferences} +import chipyard.harness.{OverrideHarnessBinder} + +/*** UART ***/ +class WithUART extends OverrideHarnessBinder({ + (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + th match { case vcu118th: VCU118FPGATestHarnessImp => { + vcu118th.vcu118Outer.io_uart_bb.bundle <> ports.head + } } + + Nil + } +}) + +/*** SPI ***/ +class WithSPISDCard extends OverrideHarnessBinder({ + (system: HasPeripherySPI, th: BaseModule with HasHarnessSignalReferences, ports: Seq[SPIPortIO]) => { + th match { case vcu118th: VCU118FPGATestHarnessImp => { + vcu118th.vcu118Outer.io_spi_bb.bundle <> ports.head + } } + + Nil + } +}) + +/*** Experimental DDR ***/ +class WithDDRMem extends OverrideHarnessBinder({ + (system: CanHaveMasterTLMemPort, th: BaseModule with HasHarnessSignalReferences, ports: Seq[HeterogeneousBag[TLBundle]]) => { + th match { case vcu118th: VCU118FPGATestHarnessImp => { + require(ports.size == 1) + + val bundles = vcu118th.vcu118Outer.ddrClient.out.map(_._1) + val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType))) + bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io } + ddrClientBundle <> ports.head + } } + + Nil + } +}) diff --git a/fpga/src/main/scala/vcu118/IOBinders.scala b/fpga/src/main/scala/vcu118/IOBinders.scala new file mode 100644 index 00000000..a1f67bcd --- /dev/null +++ b/fpga/src/main/scala/vcu118/IOBinders.scala @@ -0,0 +1,52 @@ +package chipyard.fpga.vcu118 + +import chisel3._ +import chisel3.experimental.{IO, DataMirror} + +import freechips.rocketchip.diplomacy.{ResourceBinding, Resource, ResourceAddress, InModuleBody} +import freechips.rocketchip.subsystem.{BaseSubsystem} +import freechips.rocketchip.util.{HeterogeneousBag} +import freechips.rocketchip.tilelink.{TLBundle} + +import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp} +import sifive.blocks.devices.spi.{HasPeripherySPI, HasPeripherySPIModuleImp, MMCDevice} + +import chipyard.{CanHaveMasterTLMemPort} +import chipyard.iobinders.{OverrideIOBinder, OverrideLazyIOBinder} + +class WithUARTIOPassthrough extends OverrideIOBinder({ + (system: HasPeripheryUARTModuleImp) => { + val io_uart_pins_temp = system.uart.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"uart_$i") } + (io_uart_pins_temp zip system.uart).map { case (io, sysio) => + io <> sysio + } + (io_uart_pins_temp, Nil) + } +}) + +class WithSPIIOPassthrough extends OverrideLazyIOBinder({ + (system: HasPeripherySPI) => { + // attach resource to 1st SPI + ResourceBinding { + Resource(new MMCDevice(system.tlSpiNodes.head.device, 1), "reg").bind(ResourceAddress(0)) + } + + InModuleBody { + system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripherySPIModuleImp => { + val io_spi_pins_temp = system.spi.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"spi_$i") } + (io_spi_pins_temp zip system.spi).map { case (io, sysio) => + io <> sysio + } + (io_spi_pins_temp, Nil) + } } + } + } +}) + +class WithTLIOPassthrough extends OverrideIOBinder({ + (system: CanHaveMasterTLMemPort) => { + val io_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.mem_tl)).suggestName("tl_slave") + io_tl_mem_pins_temp <> system.mem_tl + (Seq(io_tl_mem_pins_temp), Nil) + } +}) diff --git a/fpga/src/main/scala/vcu118/TestHarness.scala b/fpga/src/main/scala/vcu118/TestHarness.scala new file mode 100644 index 00000000..4748c528 --- /dev/null +++ b/fpga/src/main/scala/vcu118/TestHarness.scala @@ -0,0 +1,144 @@ +package chipyard.fpga.vcu118 + +import chisel3._ +import chisel3.experimental.{IO} + +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.config._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.tilelink._ + +import sifive.fpgashells.shell.xilinx._ +import sifive.fpgashells.ip.xilinx._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.clocks._ + +import sifive.blocks.devices.uart._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.i2c._ +import sifive.blocks.devices.gpio._ + +import chipyard.{HasHarnessSignalReferences, HasTestHarnessFunctions, BuildTop, CanHaveMasterTLMemPort, ChipTop} +import chipyard.iobinders.{HasIOBinders} +import chipyard.harness.{ApplyHarnessBinders} + +case object FPGAFrequencyKey extends Field[Double](100.0) + +class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118ShellBasicOverlays { + + def dp = designParameters + + val pmod_is_sdio = p(VCU118ShellPMOD) == "SDIO" + val jtag_location = Some(if (pmod_is_sdio) "FMC_J2" else "PMOD_J52") + + // Order matters; ddr depends on sys_clock + val uart = Overlay(UARTOverlayKey, new UARTVCU118ShellPlacer(this, UARTShellInput())) + val sdio = if (pmod_is_sdio) Some(Overlay(SPIOverlayKey, new SDIOVCU118ShellPlacer(this, SPIShellInput()))) else None + val jtag = Overlay(JTAGDebugOverlayKey, new JTAGDebugVCU118ShellPlacer(this, JTAGDebugShellInput(location = jtag_location))) + val cjtag = Overlay(cJTAGDebugOverlayKey, new cJTAGDebugVCU118ShellPlacer(this, cJTAGDebugShellInput())) + val jtagBScan = Overlay(JTAGDebugBScanOverlayKey, new JTAGDebugBScanVCU118ShellPlacer(this, JTAGDebugBScanShellInput())) + val fmc = Overlay(PCIeOverlayKey, new PCIeVCU118FMCShellPlacer(this, PCIeShellInput())) + val edge = Overlay(PCIeOverlayKey, new PCIeVCU118EdgeShellPlacer(this, PCIeShellInput())) + + val topDesign = LazyModule(p(BuildTop)(dp)) + + // place all clocks in the shell + dp(ClockInputOverlayKey).foreach { _.place(ClockInputDesignInput()) } + + /*** Connect/Generate clocks ***/ + + // connect to the PLL that will generate multiple clocks + val harnessSysPLL = dp(PLLFactoryKey)() + sys_clock.get() match { + case Some(x : SysClockVCU118PlacedOverlay) => { + harnessSysPLL := x.node + } + } + + // create and connect to the dutClock + val dutClock = ClockSinkNode(freqMHz = dp(FPGAFrequencyKey)) + val dutWrangler = LazyModule(new ResetWrangler) + val dutGroup = ClockGroup() + dutClock := dutWrangler.node := dutGroup := harnessSysPLL + + // connect ref clock to dummy sink node + ref_clock.get() match { + case Some(x : RefClockVCU118PlacedOverlay) => { + val sink = ClockSinkNode(Seq(ClockSinkParameters())) + sink := x.node + } + } + + /*** UART ***/ + + // 1st UART goes to the VCU118 dedicated UART + + val io_uart_bb = BundleBridgeSource(() => (new UARTPortIO(dp(PeripheryUARTKey).head))) + dp(UARTOverlayKey).head.place(UARTDesignInput(io_uart_bb)) + + /*** SPI ***/ + + // 1st SPI goes to the VCU118 SDIO port + + val io_spi_bb = BundleBridgeSource(() => (new SPIPortIO(dp(PeripherySPIKey).head))) + dp(SPIOverlayKey).head.place(SPIDesignInput(dp(PeripherySPIKey).head, io_spi_bb)) + + /*** DDR ***/ + + val ddrPlaced = dp(DDROverlayKey).head.place(DDRDesignInput(dp(ExtMem).get.master.base, dutWrangler.node, harnessSysPLL)) + + // connect 1 mem. channel to the FPGA DDR + val inParams = topDesign match { case td: ChipTop => + td.lazySystem match { case lsys: CanHaveMasterTLMemPort => + lsys.memTLNode.edges.in(0) + } + } + val ddrClient = TLClientNode(Seq(inParams.master)) + ddrPlaced.overlayOutput.ddr := ddrClient + + // module implementation + override lazy val module = new VCU118FPGATestHarnessImp(this) +} + +class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawModuleImp(_outer) with HasHarnessSignalReferences { + + val vcu118Outer = _outer + + val reset = IO(Input(Bool())) + _outer.xdc.addPackagePin(reset, "L19") + _outer.xdc.addIOStandard(reset, "LVCMOS12") + + val reset_ibuf = Module(new IBUF) + reset_ibuf.io.I := reset + + val sysclk: Clock = _outer.sys_clock.get() match { + case Some(x: SysClockVCU118PlacedOverlay) => x.clock + } + + val powerOnReset: Bool = PowerOnResetFPGAOnly(sysclk) + _outer.sdc.addAsyncPath(Seq(powerOnReset)) + + val ereset: Bool = _outer.chiplink.get() match { + case Some(x: ChipLinkVCU118PlacedOverlay) => !x.ereset_n + case _ => false.B + } + + _outer.pllReset := (reset_ibuf.io.O || powerOnReset || ereset) + + // cy stuff + val harnessClock = _outer.dutClock.in.head._1.clock + val harnessReset = WireInit(_outer.dutClock.in.head._1.reset) + val dutReset = harnessReset + val success = false.B + + childClock := harnessClock + childReset := harnessReset + + // harness binders are non-lazy + _outer.topDesign match { case d: HasTestHarnessFunctions => + d.harnessFunctions.foreach(_(this)) + } + _outer.topDesign match { case d: HasIOBinders => + ApplyHarnessBinders(this, d.lazySystem, d.portMap) + } +} diff --git a/fpga/src/main/scala/vcu118/bringup/BringupGPIOs.scala b/fpga/src/main/scala/vcu118/bringup/BringupGPIOs.scala new file mode 100644 index 00000000..1e11dfa2 --- /dev/null +++ b/fpga/src/main/scala/vcu118/bringup/BringupGPIOs.scala @@ -0,0 +1,28 @@ +package chipyard.fpga.vcu118.bringup + +import scala.collection.mutable.{LinkedHashMap} + +object BringupGPIOs { + // map of the pin name (akin to die pin name) to (fpga package pin, IOSTANDARD) + val pinMapping = LinkedHashMap( + // these connect to LEDs and switches on the VCU118 (and use 1.2V) + "led0" -> ("AT32", "LVCMOS12"), // 0 + "led1" -> ("AV34", "LVCMOS12"), // 1 + "led2" -> ("AY30", "LVCMOS12"), // 2 + "led3" -> ("BB32", "LVCMOS12"), // 3 + "led4" -> ("BF32", "LVCMOS12"), // 4 + "led5" -> ("AU37", "LVCMOS12"), // 5 + "led6" -> ("AV36", "LVCMOS12"), // 6 + "led7" -> ("BA37", "LVCMOS12"), // 7 + "sw0" -> ("B17", "LVCMOS12"), // 8 + "sw1" -> ("G16", "LVCMOS12"), // 9 + "sw2" -> ("J16", "LVCMOS12"), // 10 + "sw3" -> ("D21", "LVCMOS12") // 11 + ) + + // return list of names (ordered) + def names: Seq[String] = pinMapping.keys.toSeq + + // return number of GPIOs + def width: Int = pinMapping.size +} diff --git a/fpga/src/main/scala/vcu118/bringup/Configs.scala b/fpga/src/main/scala/vcu118/bringup/Configs.scala new file mode 100644 index 00000000..0e5602e5 --- /dev/null +++ b/fpga/src/main/scala/vcu118/bringup/Configs.scala @@ -0,0 +1,52 @@ +package chipyard.fpga.vcu118.bringup + +import math.min + +import freechips.rocketchip.config.{Config} +import freechips.rocketchip.diplomacy.{DTSModel, DTSTimebase, RegionType, AddressSet, ResourceBinding, Resource, ResourceAddress} + +import sifive.blocks.devices.gpio.{PeripheryGPIOKey, GPIOParams} +import sifive.blocks.devices.i2c.{PeripheryI2CKey, I2CParams} +import sifive.blocks.devices.spi.{PeripherySPIKey, SPIParams} +import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} + +import sifive.fpgashells.shell.{DesignKey} +import sifive.fpgashells.shell.xilinx.{VCU118ShellPMOD, VCU118DDRSize} + +import chipyard.fpga.vcu118.{RocketVCU118Config, BoomVCU118Config} + +class WithBringupPeripherals extends Config((site, here, up) => { + case PeripheryUARTKey => up(PeripheryUARTKey, site) ++ List(UARTParams(address = BigInt(0x64003000L))) + case PeripherySPIKey => up(PeripherySPIKey, site) ++ List(SPIParams(rAddress = BigInt(0x64004000L))) + case PeripheryI2CKey => List(I2CParams(address = BigInt(0x64005000L))) + case PeripheryGPIOKey => { + if (BringupGPIOs.width > 0) { + require(BringupGPIOs.width <= 64) // currently only support 64 GPIOs (change addrs to get more) + val gpioAddrs = Seq(BigInt(0x64002000), BigInt(0x64007000)) + val maxGPIOSupport = 32 // max gpios supported by SiFive driver (split by 32) + List.tabulate(((BringupGPIOs.width - 1)/maxGPIOSupport) + 1)(n => { + GPIOParams(address = gpioAddrs(n), width = min(BringupGPIOs.width - maxGPIOSupport*n, maxGPIOSupport)) + }) + } + else { + List.empty[GPIOParams] + } + } +}) + +class WithBringupAdditions extends Config( + new WithBringupUART ++ + new WithBringupSPI ++ + new WithBringupI2C ++ + new WithBringupGPIO ++ + new WithI2CIOPassthrough ++ + new WithGPIOIOPassthrough ++ + new WithBringupPeripherals) + +class RocketBringupConfig extends Config( + new WithBringupPeripherals ++ + new RocketVCU118Config) + +class BoomBringupConfig extends Config( + new WithBringupPeripherals ++ + new BoomVCU118Config) diff --git a/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala b/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala new file mode 100644 index 00000000..c0a96d3c --- /dev/null +++ b/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala @@ -0,0 +1,147 @@ +package chipyard.fpga.vcu118.bringup + +import chisel3._ +import chisel3.experimental.{attach} + +import freechips.rocketchip.diplomacy._ + +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ +import sifive.fpgashells.shell.xilinx._ + +import chipyard.fpga.vcu118.{FMCPMap} + +/* Connect the I2C to certain FMC pins */ +class BringupI2CVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name: String, val designInput: I2CDesignInput, val shellInput: I2CShellInput) + extends I2CXilinxPlacedOverlay(name, designInput, shellInput) +{ + shell { InModuleBody { + require(shellInput.index == 0) // only support 1 I2C <-> FMC connection + val i2cLocations = List(List(FMCPMap("K11"), FMCPMap("E2"))) + val packagePinsWithPackageIOs = Seq((i2cLocations(shellInput.index)(0), IOPin(io.scl)), + (i2cLocations(shellInput.index)(1), IOPin(io.sda))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + shell.xdc.addIOB(io) + } } + } } +} + +class BringupI2CVCU118ShellPlacer(val shell: VCU118ShellBasicOverlays, val shellInput: I2CShellInput)(implicit val valName: ValName) + extends I2CShellPlacer[VCU118ShellBasicOverlays] +{ + def place(designInput: I2CDesignInput) = new BringupI2CVCU118PlacedOverlay(shell, valName.name, designInput, shellInput) +} + +/* Connect the UART to certain FMC pins */ +class BringupUARTVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name: String, val designInput: UARTDesignInput, val shellInput: UARTShellInput) + extends UARTXilinxPlacedOverlay(name, designInput, shellInput, true) +{ + shell { InModuleBody { + val packagePinsWithPackageIOs = Seq((FMCPMap("E9"), IOPin(io.ctsn.get)), // unused + (FMCPMap("E10"), IOPin(io.rtsn.get)), // unused + (FMCPMap("C15"), IOPin(io.rxd)), + (FMCPMap("C14"), IOPin(io.txd))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + shell.xdc.addIOB(io) + } } + + // add pullup on ctsn (ctsn is an input that is not used or driven) + packagePinsWithPackageIOs take 1 foreach { case (pin, io) => { + shell.xdc.addPullup(io) + } } + } } +} + +class BringupUARTVCU118ShellPlacer(shell: VCU118ShellBasicOverlays, val shellInput: UARTShellInput)(implicit val valName: ValName) + extends UARTShellPlacer[VCU118ShellBasicOverlays] { + def place(designInput: UARTDesignInput) = new BringupUARTVCU118PlacedOverlay(shell, valName.name, designInput, shellInput) +} + +/* Connect SPI to ADI device */ +class BringupSPIVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name: String, val designInput: SPIDesignInput, val shellInput: SPIShellInput) + extends SDIOXilinxPlacedOverlay(name, designInput, shellInput) +{ + shell { InModuleBody { + val packagePinsWithPackageIOs = Seq((FMCPMap("H37"), IOPin(io.spi_clk)), + (FMCPMap("H19"), IOPin(io.spi_cs)), + (FMCPMap("H17"), IOPin(io.spi_dat(0))), + (FMCPMap("H28"), IOPin(io.spi_dat(1))), + (FMCPMap("H29"), IOPin(io.spi_dat(2))), + (FMCPMap("H16"), IOPin(io.spi_dat(3)))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + } } + packagePinsWithPackageIOs drop 1 foreach { case (pin, io) => { + shell.xdc.addPullup(io) + shell.xdc.addIOB(io) + } } + } } +} + +class BringupSPIVCU118ShellPlacer(shell: VCU118ShellBasicOverlays, val shellInput: SPIShellInput)(implicit val valName: ValName) + extends SPIShellPlacer[VCU118ShellBasicOverlays] { + def place(designInput: SPIDesignInput) = new BringupSPIVCU118PlacedOverlay(shell, valName.name, designInput, shellInput) +} + +// TODO: Move this to a different location +// SPI device description for ADI part +class ADISPIDevice(spi: Device, maxMHz: Double = 1) extends SimpleDevice("clkgen", Seq("analog,adi9516-4")) { + override def parent = Some(spi) + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + val extra = Map("spi-max-frequency" -> Seq(ResourceInt(maxMHz * 1000000))) + Description(name, mapping ++ extra) + } +} + +/* Connect GPIOs to FMC */ +abstract class GPIOXilinxPlacedOverlay(name: String, di: GPIODesignInput, si: GPIOShellInput) + extends GPIOPlacedOverlay(name, di, si) +{ + def shell: XilinxShell + + shell { InModuleBody { + (io.gpio zip tlgpioSink.bundle.pins).map { case (ioPin, sinkPin) => + val iobuf = Module(new IOBUF) + iobuf.suggestName(s"gpio_iobuf") + attach(ioPin, iobuf.io.IO) + sinkPin.i.ival := iobuf.io.O + iobuf.io.T := !sinkPin.o.oe + iobuf.io.I := sinkPin.o.oval + } + } } +} + +class BringupGPIOVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name: String, val designInput: GPIODesignInput, val shellInput: GPIOShellInput, gpioNames: Seq[String]) + extends GPIOXilinxPlacedOverlay(name, designInput, shellInput) +{ + shell { InModuleBody { + require(gpioNames.length == io.gpio.length) + + val packagePinsWithIOStdWithPackageIOs = (gpioNames zip io.gpio).map { case (name, io) => + val (pin, iostd) = BringupGPIOs.pinMapping(name) + (pin, iostd, IOPin(io)) + } + + packagePinsWithIOStdWithPackageIOs foreach { case (pin, iostd, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, iostd) + if (iostd == "LVCMOS12") { shell.xdc.addDriveStrength(io, "8") } + } } + } } +} + +class BringupGPIOVCU118ShellPlacer(shell: VCU118ShellBasicOverlays, val shellInput: GPIOShellInput, gpioNames: Seq[String])(implicit val valName: ValName) + extends GPIOShellPlacer[VCU118ShellBasicOverlays] { + def place(designInput: GPIODesignInput) = new BringupGPIOVCU118PlacedOverlay(shell, valName.name, designInput, shellInput, gpioNames) +} + + diff --git a/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala b/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala new file mode 100644 index 00000000..b6693036 --- /dev/null +++ b/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala @@ -0,0 +1,64 @@ +package chipyard.fpga.vcu118.bringup + +import chisel3._ +import chisel3.experimental.{Analog, IO, BaseModule} + +import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp, UARTPortIO} +import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO} +import sifive.blocks.devices.i2c.{HasPeripheryI2CModuleImp, I2CPort} +import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp, GPIOPortIO} + +import chipyard.{HasHarnessSignalReferences} +import chipyard.harness.{ComposeHarnessBinder, OverrideHarnessBinder} + +/*** UART ***/ +class WithBringupUART extends ComposeHarnessBinder({ + (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { + require(ports.size == 2) + + vcu118th.bringupOuter.io_fmc_uart_bb.bundle <> ports.last + } } + + Nil + } +}) + +/*** SPI ***/ +class WithBringupSPI extends ComposeHarnessBinder({ + (system: HasPeripherySPI, th: BaseModule with HasHarnessSignalReferences, ports: Seq[SPIPortIO]) => { + th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { + require(ports.size == 2) + + vcu118th.bringupOuter.io_adi_spi_bb.bundle <> ports.last + } } + + Nil + } +}) + +/*** I2C ***/ +class WithBringupI2C extends OverrideHarnessBinder({ + (system: HasPeripheryI2CModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[I2CPort]) => { + th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { + require(ports.size == 1) + + vcu118th.bringupOuter.io_i2c_bb.bundle <> ports.head + } } + + Nil + } +}) + +/*** GPIO ***/ +class WithBringupGPIO extends OverrideHarnessBinder({ + (system: HasPeripheryGPIOModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[GPIOPortIO]) => { + th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { + (vcu118th.bringupOuter.io_gpio_bb zip ports).map { case (bb_io, dut_io) => + bb_io.bundle <> dut_io + } + } } + + Nil + } +}) diff --git a/fpga/src/main/scala/vcu118/bringup/IOBinders.scala b/fpga/src/main/scala/vcu118/bringup/IOBinders.scala new file mode 100644 index 00000000..168933f7 --- /dev/null +++ b/fpga/src/main/scala/vcu118/bringup/IOBinders.scala @@ -0,0 +1,29 @@ +package chipyard.fpga.vcu118.bringup + +import chisel3._ +import chisel3.experimental.{IO, DataMirror} + +import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp} +import sifive.blocks.devices.i2c.{HasPeripheryI2CModuleImp} + +import chipyard.iobinders.{OverrideIOBinder} + +class WithGPIOIOPassthrough extends OverrideIOBinder({ + (system: HasPeripheryGPIOModuleImp) => { + val io_gpio_pins_temp = system.gpio.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"gpio_$i") } + (io_gpio_pins_temp zip system.gpio).map { case (io, sysio) => + io <> sysio + } + (io_gpio_pins_temp, Nil) + } +}) + +class WithI2CIOPassthrough extends OverrideIOBinder({ + (system: HasPeripheryI2CModuleImp) => { + val io_i2c_pins_temp = system.i2c.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"i2c_$i") } + (io_i2c_pins_temp zip system.i2c).map { case (io, sysio) => + io <> sysio + } + (io_i2c_pins_temp, Nil) + } +}) diff --git a/fpga/src/main/scala/vcu118/bringup/TestHarness.scala b/fpga/src/main/scala/vcu118/bringup/TestHarness.scala new file mode 100644 index 00000000..080f6189 --- /dev/null +++ b/fpga/src/main/scala/vcu118/bringup/TestHarness.scala @@ -0,0 +1,72 @@ +package chipyard.fpga.vcu118.bringup + +import chisel3._ + +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.config._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.tilelink._ + +import sifive.fpgashells.shell.xilinx._ +import sifive.fpgashells.ip.xilinx._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.clocks._ + +import sifive.blocks.devices.uart._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.i2c._ +import sifive.blocks.devices.gpio._ + +import chipyard.fpga.vcu118.{VCU118FPGATestHarness, VCU118FPGATestHarnessImp} + +class BringupVCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118FPGATestHarness { + + /*** UART ***/ + + require(dp(PeripheryUARTKey).size == 2) + + // 2nd UART goes to the FMC UART + + val uart_fmc = Overlay(UARTOverlayKey, new BringupUARTVCU118ShellPlacer(this, UARTShellInput())) + + val io_fmc_uart_bb = BundleBridgeSource(() => (new UARTPortIO(dp(PeripheryUARTKey).last))) + dp(UARTOverlayKey).last.place(UARTDesignInput(io_fmc_uart_bb)) + + /*** SPI ***/ + + require(dp(PeripherySPIKey).size == 2) + + // 2nd SPI goes to the ADI port + + val adi = Overlay(SPIOverlayKey, new BringupSPIVCU118ShellPlacer(this, SPIShellInput())) + + val io_adi_spi_bb = BundleBridgeSource(() => (new SPIPortIO(dp(PeripherySPIKey).last))) + dp(SPIOverlayKey).last.place(SPIDesignInput(dp(PeripherySPIKey).last, io_adi_spi_bb)) + + /*** I2C ***/ + + val i2c = Overlay(I2COverlayKey, new BringupI2CVCU118ShellPlacer(this, I2CShellInput())) + + val io_i2c_bb = BundleBridgeSource(() => (new I2CPort)) + dp(I2COverlayKey).head.place(I2CDesignInput(io_i2c_bb)) + + /*** GPIO ***/ + + val gpio = Seq.tabulate(dp(PeripheryGPIOKey).size)(i => { + val maxGPIOSupport = 32 // max gpio per gpio chip + val names = BringupGPIOs.names.slice(maxGPIOSupport*i, maxGPIOSupport*(i+1)) + Overlay(GPIOOverlayKey, new BringupGPIOVCU118ShellPlacer(this, GPIOShellInput(), names)) + }) + + val io_gpio_bb = dp(PeripheryGPIOKey).map { p => BundleBridgeSource(() => (new GPIOPortIO(p))) } + (dp(GPIOOverlayKey) zip dp(PeripheryGPIOKey)).zipWithIndex.map { case ((placer, params), i) => + placer.place(GPIODesignInput(params, io_gpio_bb(i))) + } + + // module implementation + override lazy val module = new BringupVCU118FPGATestHarnessImp(this) +} + +class BringupVCU118FPGATestHarnessImp(_outer: BringupVCU118FPGATestHarness) extends VCU118FPGATestHarnessImp(_outer) { + val bringupOuter = _outer +} diff --git a/generators/chipyard/src/main/scala/ChipTop.scala b/generators/chipyard/src/main/scala/ChipTop.scala index e7456d80..61a043b6 100644 --- a/generators/chipyard/src/main/scala/ChipTop.scala +++ b/generators/chipyard/src/main/scala/ChipTop.scala @@ -7,7 +7,7 @@ import scala.collection.mutable.{ArrayBuffer} import freechips.rocketchip.prci.{ClockGroupIdentityNode, ClockSinkParameters, ClockSinkNode, ClockGroup} import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey} import freechips.rocketchip.config.{Parameters, Field} -import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, LazyRawModuleImp, LazyModuleImpLike} +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, LazyRawModuleImp, LazyModuleImpLike, BindingScope} import freechips.rocketchip.util.{ResetCatchAndSync} import chipyard.iobinders._ @@ -23,7 +23,7 @@ case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) * drive clock and reset generation */ -class ChipTop(implicit p: Parameters) extends LazyModule +class ChipTop(implicit p: Parameters) extends LazyModule with BindingScope with HasTestHarnessFunctions with HasIOBinders { // The system module specified by BuildSystem lazy val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system") diff --git a/generators/chipyard/src/main/scala/DigitalTop.scala b/generators/chipyard/src/main/scala/DigitalTop.scala index c0ac1ff7..aee70903 100644 --- a/generators/chipyard/src/main/scala/DigitalTop.scala +++ b/generators/chipyard/src/main/scala/DigitalTop.scala @@ -20,12 +20,16 @@ class DigitalTop(implicit p: Parameters) extends ChipyardSystem with sifive.blocks.devices.uart.HasPeripheryUART // Enables optionally adding the sifive UART with sifive.blocks.devices.gpio.HasPeripheryGPIO // Enables optionally adding the sifive GPIOs with sifive.blocks.devices.spi.HasPeripherySPIFlash // Enables optionally adding the sifive SPI flash controller + with sifive.blocks.devices.spi.HasPeripherySPI // Enables optionally adding the sifive SPI + with sifive.blocks.devices.pwm.HasPeripheryPWM // Enables optionally adding the sifive PWM + with sifive.blocks.devices.i2c.HasPeripheryI2C // Enables optionally adding the sifive I2C with icenet.CanHavePeripheryIceNIC // Enables optionally adding the IceNIC for FireSim with chipyard.example.CanHavePeripheryInitZero // Enables optionally adding the initzero example widget with chipyard.example.CanHavePeripheryGCD // Enables optionally adding the GCD example widget with chipyard.example.CanHavePeripheryStreamingFIR // Enables optionally adding the DSPTools FIR example widget with chipyard.example.CanHavePeripheryStreamingPassthrough // Enables optionally adding the DSPTools streaming-passthrough example widget with nvidia.blocks.dla.CanHavePeripheryNVDLA // Enables optionally having an NVDLA + with CanHaveMasterTLMemPort { override lazy val module = new DigitalTopModule(this) } @@ -35,6 +39,48 @@ class DigitalTopModule[+L <: DigitalTop](l: L) extends ChipyardSystemModule(l) with sifive.blocks.devices.uart.HasPeripheryUARTModuleImp with sifive.blocks.devices.gpio.HasPeripheryGPIOModuleImp with sifive.blocks.devices.spi.HasPeripherySPIFlashModuleImp + with sifive.blocks.devices.spi.HasPeripherySPIModuleImp + with sifive.blocks.devices.pwm.HasPeripheryPWMModuleImp + with sifive.blocks.devices.i2c.HasPeripheryI2CModuleImp with chipyard.example.CanHavePeripheryGCDModuleImp with freechips.rocketchip.util.DontTouch // DOC include end: DigitalTop + +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ + +/** Adds a TileLink port to the system intended to master an MMIO device bus */ +trait CanHaveMasterTLMemPort { this: BaseSubsystem => + private val memPortParamsOpt = p(ExtMem) + private val portName = "tl_mem" + private val device = new MemoryDevice + private val idBits = memPortParamsOpt.map(_.master.idBits).getOrElse(1) + + val memTLNode = TLManagerNode(memPortParamsOpt.map({ case MemoryPortParams(memPortParams, nMemoryChannels) => + Seq.tabulate(nMemoryChannels) { channel => + val base = AddressSet.misaligned(memPortParams.base, memPortParams.size) + val filter = AddressSet(channel * mbus.blockBytes, ~((nMemoryChannels-1) * mbus.blockBytes)) + + TLSlavePortParameters.v1( + managers = Seq(TLSlaveParameters.v1( + address = base.flatMap(_.intersect(filter)), + resources = device.reg, + regionType = RegionType.UNCACHED, // cacheable + executable = true, + supportsGet = TransferSizes(1, mbus.blockBytes), + supportsPutFull = TransferSizes(1, mbus.blockBytes), + supportsPutPartial = TransferSizes(1, mbus.blockBytes))), + beatBytes = memPortParams.beatBytes) + } + }).toList.flatten) + + mbus.coupleTo(s"memory_controller_port_named_$portName") { + (memTLNode + :*= TLBuffer() + :*= TLSourceShrinker(1 << idBits) + :*= TLWidthWidget(mbus.beatBytes) + :*= _) + } + + val mem_tl = InModuleBody { memTLNode.makeIOs() } +} diff --git a/generators/chipyard/src/main/scala/System.scala b/generators/chipyard/src/main/scala/System.scala index bd20ddc7..f8906e04 100644 --- a/generators/chipyard/src/main/scala/System.scala +++ b/generators/chipyard/src/main/scala/System.scala @@ -23,7 +23,6 @@ import freechips.rocketchip.util.{DontTouch} */ class ChipyardSystem(implicit p: Parameters) extends ChipyardSubsystem with HasAsyncExtInterrupts - with CanHaveMasterAXI4MemPort with CanHaveMasterAXI4MMIOPort with CanHaveSlaveAXI4Port { diff --git a/generators/sifive-blocks b/generators/sifive-blocks index c240e629..7e2121ee 160000 --- a/generators/sifive-blocks +++ b/generators/sifive-blocks @@ -1 +1 @@ -Subproject commit c240e629e2fc111cbb12e4fe707be898b5204984 +Subproject commit 7e2121ee26e614f2144a9e4c67c440773aa7544d diff --git a/generators/utilities/src/main/scala/Simulator.scala b/generators/utilities/src/main/scala/Simulator.scala index f40ad032..45939343 100644 --- a/generators/utilities/src/main/scala/Simulator.scala +++ b/generators/utilities/src/main/scala/Simulator.scala @@ -11,6 +11,7 @@ case class GenerateSimConfig( sealed trait Simulator object VerilatorSimulator extends Simulator object VCSSimulator extends Simulator +object NotSimulator extends Simulator trait HasGenerateSimConfig { val parser = new scopt.OptionParser[GenerateSimConfig]("GenerateSimFiles") { @@ -22,15 +23,16 @@ trait HasGenerateSimConfig { .action((x, c) => x match { case "verilator" => c.copy(simulator = VerilatorSimulator) case "vcs" => c.copy(simulator = VCSSimulator) + case "none" => c.copy(simulator = NotSimulator) case _ => throw new Exception(s"Unrecognized simulator $x") }) - .text("Name of simulator to generate files for (verilator, vcs)") + .text("Name of simulator to generate files for (verilator, vcs, none)") opt[String]("target-dir") .abbr("td") .valueName("") .action((x, c) => c.copy(targetDir = x)) - .text("Target director to put files") + .text("Target directory to put files") opt[String]("dotFName") .abbr("df") @@ -50,6 +52,7 @@ object GenerateSimFiles extends App with HasGenerateSimConfig { case VerilatorSimulator => s"-FI ${fname}" // vcs pulls headers in with +incdir, doesn't have anything like verilator.h case VCSSimulator => "" + case _ => "" } } else { // do nothing otherwise fname @@ -95,15 +98,30 @@ object GenerateSimFiles extends App with HasGenerateSimConfig { "/csrc/remote_bitbang.h", "/csrc/remote_bitbang.cc", "/vsrc/EICG_wrapper.v", - ) ++ (sim match { // simulator specific files to include - case VerilatorSimulator => Seq( - "/csrc/emulator.cc", - "/csrc/verilator.h", - ) - case VCSSimulator => Seq( - "/vsrc/TestDriver.v", - ) - }) + ) ++ (sim match { + case NotSimulator => Seq() + case _ => Seq( + "/testchipip/csrc/SimSerial.cc", + "/testchipip/csrc/SimDRAM.cc", + "/testchipip/csrc/mm.h", + "/testchipip/csrc/mm.cc", + "/testchipip/csrc/mm_dramsim2.h", + "/testchipip/csrc/mm_dramsim2.cc", + "/csrc/SimDTM.cc", + "/csrc/SimJTAG.cc", + "/csrc/remote_bitbang.h", + "/csrc/remote_bitbang.cc", + ) + }) ++ (sim match { // simulator specific files to include + case VerilatorSimulator => Seq( + "/csrc/emulator.cc", + "/csrc/verilator.h", + ) + case VCSSimulator => Seq( + "/vsrc/TestDriver.v", + ) + case _ => Seq() + }) def writeBootrom(): Unit = { firrtl.FileUtils.makeDirectory("./bootrom/") diff --git a/scripts/init-fpga.sh b/scripts/init-fpga.sh new file mode 100755 index 00000000..08203259 --- /dev/null +++ b/scripts/init-fpga.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# exit script if any command fails +set -e +set -o pipefail + +# Enable submodule update for FPGA tools. +git config --unset submodule.fpga/fpga-shells.update +# Initialize local FPGA tools. +git submodule update --init --recursive fpga/fpga-shells +# Disable submodule update for FPGA tools. +git config submodule.fpga/fpga-shells.update none diff --git a/scripts/init-submodules-no-riscv-tools-nolog.sh b/scripts/init-submodules-no-riscv-tools-nolog.sh index c861658d..db16d125 100755 --- a/scripts/init-submodules-no-riscv-tools-nolog.sh +++ b/scripts/init-submodules-no-riscv-tools-nolog.sh @@ -39,6 +39,8 @@ git config submodule.vlsi/hammer-cadence-plugins.update none git config submodule.vlsi/hammer-synopsys-plugins.update none git config submodule.vlsi/hammer-mentor-plugins.update none git config submodule.software/firemarshal.update none +# Disable updates to the local FPGA tools +git config submodule.fpga/fpga-shells.update none git submodule update --init --recursive #--jobs 8 # Un-ignore toolchain submodules