diff --git a/.github/workflows/update_defaults.yaml b/.github/workflows/update_defaults.yaml index 20240ff..b743fb4 100644 --- a/.github/workflows/update_defaults.yaml +++ b/.github/workflows/update_defaults.yaml @@ -33,4 +33,30 @@ jobs: curl -o $GITHUB_WORKSPACE/tmp_default_content/README.md -L https://raw.githubusercontent.com/efabless/$repo_name/main/README.md curl -o $GITHUB_WORKSPACE/tmp_default_content/gds/$gds_name.gds -L https://raw.githubusercontent.com/efabless/$repo_name/main/gds/$gds_name.gds - python3 $GITHUB_WORKSPACE/checks/defaults_check.py -i $GITHUB_WORKSPACE/tmp_default_content -d $GITHUB_WORKSPACE/_default_content \ No newline at end of file + python3 $GITHUB_WORKSPACE/checks/defaults_check.py -i $GITHUB_WORKSPACE/tmp_default_content -d $GITHUB_WORKSPACE/_default_content -t ${{ matrix.design_types }} > $GITHUB_WORKSPACE/defaults.log + + vio=$(grep -c "clean" $GITHUB_WORKSPACE/defaults.log) + if [[ $vio -gt 0 ]]; + then + cp $GITHUB_WORKSPACE/tmp_default_content/README.md $GITHUB_WORKSPACE/_default_content/README_${{ matrix.design_types }}.md + cp $GITHUB_WORKSPACE/tmp_default_content/gds/$gds_name.gds $GITHUB_WORKSPACE/_default_content/gds/$gds_name.gds + echo "UPDATE_DEFAULTS=1" >> $GITHUB_ENV + else + echo "UPDATE_DEFAULTS=0" >> $GITHUB_ENV + echo No Updates + fi + + - name: Create Pull Request + if: ${{ env.UPDATE_DEFAULTS == '1' }} + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + title: "[BOT] Update Default files" + body: | + This is an automated PR. + + See the individual commits for details. + commit-message: | + [BOT] Update Default files + branch: update-branch + delete-branch: true \ No newline at end of file diff --git a/_default_content/README_analog.md b/_default_content/README_analog.md new file mode 100644 index 0000000..d7d53a3 --- /dev/null +++ b/_default_content/README_analog.md @@ -0,0 +1,18 @@ +# Caravel Analog User + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![CI](https://github.com/efabless/caravel_user_project_analog/actions/workflows/user_project_ci.yml/badge.svg)](https://github.com/efabless/caravel_user_project_analog/actions/workflows/user_project_ci.yml) [![Caravan Build](https://github.com/efabless/caravel_user_project_analog/actions/workflows/caravan_build.yml/badge.svg)](https://github.com/efabless/caravel_user_project_analog/actions/workflows/caravan_build.yml) + +--- + +| :exclamation: Important Note | +|-----------------------------------------| + +## Please fill in your project documentation in this README.md file + + +:warning: | Use this sample project for analog user projects. +:---: | :--- + +--- + +Refer to [README](docs/source/index.rst) for this sample project documentation. diff --git a/_default_content/README.md b/_default_content/README_digital.md similarity index 74% rename from _default_content/README.md rename to _default_content/README_digital.md index 56dd695..0c49da1 100644 --- a/_default_content/README.md +++ b/_default_content/README_digital.md @@ -5,6 +5,10 @@ | :exclamation: Important Note | |-----------------------------------------| -## Please fill in your project documentation in this README.md file +## Please fill in your project documentation in this README.md file + +Refer to [README](docs/source/index.rst#section-quickstart) for a quickstart of how to use caravel_user_project Refer to [README](docs/source/index.rst) for this sample project documentation. + +Refer to the following [readthedocs](https://caravel-sim-infrastructure.readthedocs.io/en/latest/index.html) for how to add cocotb tests to your project. \ No newline at end of file diff --git a/_default_content/README_openframe.md b/_default_content/README_openframe.md new file mode 100644 index 0000000..0ea5648 --- /dev/null +++ b/_default_content/README_openframe.md @@ -0,0 +1,240 @@ +OpenFrame Project Example +===================================== + +The OpenFrame Project Example is a user project designed to showcase how to use +the Caravel "OpenFrame" design, which is an alternative user project harness +chip that differs from the Caravel and Caravan designs by (1) having no integrated +SoC on chip, (2) allowing access to all GPIO controls, (3) maximizing the user +project area, and (4) minimizing the support circuitry to comprise only the +padframe, a power-on-reset circuit, and a digital ROM containing the 32-bit +project ID. The padframe design and placement of pins matches the Caravel and +Caravan chips. The pin types also remain the same, with power and ground pins +in the same positions, with the same power domains available. Pins which +previously had functions connected with the CPU (flash controller interface, +SPI interface, UART) use the same GPIO pads but allocate them to +general-purpose I/O for any purpose. + +One reason for choosing the Openframe harness is to implement an alternative +SoC or implement an SoC with the user project integrated into the same level +of hierarchy. This project example demonstrates that approach, where the +VexRISC CPU from the Caravel and Caravan chips is replaced with a PicoRV32, +which is the same processor core that was used on the first Caravel design +from MPW-one. To facilitate testing, the design maintains the same +special-purpose pins used by Caravel and Caravan, such as (critially) the +flash controller and housekeeping SPI, so that the chip after fabrication +will be fully compatible with the development board shipped by Efabless +with the chips. + +The primary difference between this Openframe project example and the +original MPW-one Caravel design is that there is no user project in the +middle, since the whole thing is now the user project. Interfaces that +existed between the SoC core and user project, such as the logic analyzer, +have no meaning in this context and are eliminated. The Wishbone address +space to the user project is eliminated, but the design is free to add +any additional Wishbone modules at any valid memory map location. The +GPIOs are no longer shared between the CPU and the user project. Each +GPIO is therefore configured individually, with a separate Wishbone +interface connecting to each one for configuration and I/O. + +Otherwise, this project example does not seek to provide additional +components above and beyond what was already on the Caravel harness chip, +which includes the flash controller, UART, an SPI master, two counter/timers, +housekeeping SPI, and digital locked loop (DLL). It provides only one new +module that groups GPIO signals into a vector that can be written or read +at the same time; that module recovers the function of simultaneous GPIO +reads and writes that was handled in Caravel and Caravan by the housekeeping +module, but was eliminated by moving GPIO configuration to individual +Wishbone interfaces. + +This README file provides basic information about the project's features, +configurations, and usage. Complete documentation can be found in the +file docs/caravel_openframe_datasheet.pdf. The datasheet does not contain +information about architecting or hardening the design. + +Table of Contents +----------------- +- Module Overview +- Designing +- Building +- Submitting +- Contributing +- License + +Module Overview +--------------- + +The OpenFrame project example is built around the PicoRV32 CPU from YosysHQ, +specifically the version which utilizes the Wishbone interface to communicate +with various modules. This project example includes the following IPs, listed +with their respective base addresses: + +- RAM: 0x00000000 +- FLASH: 0x10000000 +- UART: 0x20000000 +- GPIO: 0x21000000 +- Counter Timer 0: 0x22000000 +- Counter Timer 1: 0x23000000 +- SPI Master: 0x24000000 +- GPIO Vector: 0x25000000 +- Flash Controller: 0x2D000000 +- Debug Registers: 0x41000000 + +Additionally, the project includes a "housekeeping" module that is accessed +by SPI protocol for DLL configuration, chip information, and flash programming. +This IP is not accessible through the Wishbone bus in this version, but is +indirectly accessible by coupling internally to the SPI master. + +Designing +--------- + +The main challenge of architecting an Openframe project is understanding +the GPIO pad interface, which is quite complicated. The Caravel and +Caravan designs purposefully kept details away from the end user. This +example presents a similar solution in which each GPIO pad is interfaced +by an independent Wishbone interface (gpio_wb.v). Each GPIO has I/O +similar to the user project connections on Caravel and Caravan, but with +a four-signal interface that adds the input disable pin (cpu_gpio_ieb) +to the common three-pin interface with output disable (cpu_gpio_oeb), +output (cpu_gpio_out), and input (cpu_gpio_in). The remaining configuration +options for the GPIO pad are handled through Wishbone writes. The +Wishbone interface additionally allows the three I/O signals to be +overridden by an internal register value. + +Any additions to the Wishbone bus need to be added to the Wishbone +address interpreter (intercon_wb.v). Note that this has been done +differently for the GPIO modules so that all of the GPIO wishbone +instances (one per GPIO pin) can act as a single wishbone interface; +each instance decodes only its own address, and all GPIO instances +share the GPIO data bus and acknowledge signal. + +Where on Caravel, the default configuration of each GPIO pin at power-up +is declared in a separate file, here the default configuration data is +kept as a parameter array (picosoc.v) and applied to each GPIO wishbone +instance. + +The "cpu_gpio_*" pins on the GPIO wishbone interface (see above) define +a "standard function" for each GPIO pin (such as SPI master pins, UART +transmit/receive, etc.). Since many of these GPIO do not change +configuration (are always either input or output), the input and output +disables, and sometimes the output value, are fixed constant high or +low. For this purpose, each pad provides an individual pair of pins +"gpio_loopback_zero" and "gpio_loopback_one" that are placed next to +the pad and should be used for applying constant values to pad-related +signals. + +The loopback constants can also be used to blanket disable specific +unneeded functions of the GPIO pins. In openframe_project_wrapper.v, +they have been used to disable the obscure inputs "gpio_analog_*" +(an interface to a switched-capacitor analog bus pair) and +"gpio_holdover" (related to a sleep state that possibly cannot be +achieved given the wiring inside the padframe). + +The hierarchy of the Openframe project is: + +Top level: openframe_project_wrapper.v. This must always be the name +of the top level cell, as it is what gets integrated into the Openframe +design to create the completed chip. The openframe_project_wrapper +module instantiates the SoC and ties off (or leaves unconnected) pins +unused by the SoC. + +Second level: picosoc.v. This is the SoC definition. It instantiates +all of the blocks of the SoC as Wishbone components: The CPU +(picorv32_wb), the SPI flash controller (spimemio_wb), the UART +(simpleuart_wb), SRAM (mem_wb), and others. It defines all of the +wiring to the I/Os. It also defines a few modules that have not (by +design choice) been implemented as Wishbone components: The +housekeeping module (housekeeping), the DLL (digital_locked_loop), and +the clock and reset routing and synchronization (clock_routing). + +Third level: All SoC modules. + +Power domain considerations: + +This design example connects the entire user project design to the +vccd1/vssd1 domain using power connection cells (with verilog, +layout, abstract, etc. views) that are treated as macros and placed +at the appropriate position in the layout to connect between the +padframe power pads and the power ring surrounding the synthesized +digital core. In general, however, it is preferable to connect +together as many domains as possible to maximize the amount of +current delivered to the project and minimize the amount of I-R +drop from the pads to any point in the core. The 3.3-5.0V domains +(vdda/vssa, vdda1/vssa1, vdda2/vssa2, vddio/vssio) should be kept +separate from the 1.8V domains (vccd/vssd, vccd1/vssd1, vccd2/vssd2), +but otherwise the user is encouraged to short together all the 1.8V +domains and optionally (if used) the 3.3V domains with the exception +of vddio/vssio, which is the ESD supply for the padframe and should +remain isolated. + +Analog and mixed-signal designs: + +Analog designs may make use of Openframe, but since there is no +Caravan-equivalent of Openframe with bare analog pads, any analog +signals in the Openframe design must connect to the GPIO pads, which +limits them to the voltage range of (vddio, vssio), and limits the +frequency to approximately 60MHz. All GPIOs connected to analog +signals must have the input and output buffers disabled. + +The two choices of connections for analog signals to a GPIO pad are +(1) the analog_io[] pins, which connect to the pad through a resistor +and are the preferred connection, having some ESD protection; and +(2) the analog_noesd_io[] pins, which connect directly to the pad and +are very ESD sensitive. They should not be used unless the signal +in question cannot tolerate the voltage drop across the ESD protection +resistor on the analog_io[] pin. + +Analog circuits that need 3.3V-5.0V compatible digital controls can +make use of the gpio_in_h digital inputs from the GPIO pins, which +are in the high voltage domain. However, there is no equivalent +GPIO high voltage output, so any outputs in a high voltage domain +must be level-shifted to 1.8V before connecting to a gpio_out[] pin. + +Caravel board compatibility: + +To keep compatibility with the caravel circuit board, projects should +note which pins connect on the board to other (potentially) driving +circuitry: Pins gpio[1] through gpio[4] connect to the FTDI chip (used +by the housekeeping SPI on Caravel, and which can theoretically be +placed into a high-impedence state through software). Pin gpio[38] +connects to the CMOS clock (which can be disabled to a high impedence +state with a jumper); pins gpio[39] to gpio[42] connect directly to +the SPI flash chip and can only be disconnected by desoldering the +SPI flash chip; and pin gpio[43] is connected to an LED. Pins gpio[5] +and gpio[6] connect to switches which allow them to be connected to +the FTDI (UART function) but will normally be in a high-impedence +state. All other GPIO pins connect only to header pins on the +development board. + +Building +-------- + +For instructions on building (hardening) the OpenFrame Example project, +please refer to the [README](./README) containing the build notes. + +This project example was built using locally installed tools and not +with docker. Instructions are specific to my local build environment +but hopefully with enough commentary to be more generally useful. It +should also be possible to build the project in the Efabless-recommended +docker environment. + +Submitting +---------- + +(To be completed) + +Contributing +------------ + +Bug fixes are always welcome. Enhancements will be considered if they +demonstrate some useful technique that can only be achieved with the +Openframe version. Otherwise, this project example is meant to be just +that---an example to learn from and build on for your own Openframe +project. The best way to contribute is to create your own open source +Openframe project for a ChipIgnite shuttle run. + +License +------- + +The Caravel Openframe harness chip design on which this example depends +is distributed under the Apache-2.0 license. This project example is +also distributed under the Apache-2.0 license (see the LICENSE file). diff --git a/check_manager/__init__.py b/check_manager/__init__.py index 5e0ef05..521b248 100644 --- a/check_manager/__init__.py +++ b/check_manager/__init__.py @@ -79,14 +79,14 @@ def __init__(self, precheck_config, project_config): super().__init__(precheck_config, project_config) def run(self): - default_readme_result = defaults_check.has_default_readme(self.precheck_config['input_directory'], self.precheck_config['default_content']) + default_readme_result = defaults_check.has_default_readme(self.precheck_config['input_directory'], self.precheck_config['default_content'], self.project_config['type']) if default_readme_result: logging.info("{{README DEFAULT CHECK PASSED}} Project 'README.md' was modified and is not identical to the default 'README.md'") else: self.result = False logging.warning("{{README DEFAULT CHECK FAILED}} Project 'README.md' was not modified and is identical to the default 'README.md'") - default_content_result = defaults_check.has_default_content(self.precheck_config['input_directory'], self.precheck_config['default_content']) + default_content_result = defaults_check.has_default_content(self.precheck_config['input_directory'], self.precheck_config['default_content'], self.project_config['type']) if default_content_result: logging.info("{{CONTENT DEFAULT CHECK PASSED}} Project 'gds' was modified and is not identical to the default 'gds'") else: diff --git a/checks/defaults_check.py b/checks/defaults_check.py index 1948195..cb48295 100644 --- a/checks/defaults_check.py +++ b/checks/defaults_check.py @@ -41,8 +41,8 @@ def get_updated_view(input_directory, name): return get_view(name, input_directory) -def has_default_readme(input_directory, default_content_path): - default_content_path = default_content_path / 'README.md' +def has_default_readme(input_directory, default_content_path, project_type): + default_content_path = default_content_path / f'README_{project_type}.md' input_directory = input_directory / 'README.md' try: df_readme_content = default_content_path.open(encoding='utf-8').read() @@ -58,7 +58,7 @@ def has_default_readme(input_directory, default_content_path): return True -def has_default_content(input_directory, default_content_path): +def has_default_content(input_directory, default_content_path, project_type): result = True for view in VIEWS: try: @@ -90,14 +90,15 @@ def has_default_content(input_directory, default_content_path): parser = argparse.ArgumentParser(description="Runs a makefile check on a given file (looks for 'Makefile' if a directory is provided).") parser.add_argument('--input_directory', '-i', required=False, default=default_input_directory, help='Input Directory') parser.add_argument('--defaults_path', '-d', required=False, default=default_input_directory, help='Defaults Path') + parser.add_argument('--project_type', '-t', required=False, default=default_input_directory, help='Project type (digital, analog, openframe)') args = parser.parse_args() - if has_default_readme(Path(args.input_directory), Path(args.defaults_path)): + if has_default_readme(Path(args.input_directory), Path(args.defaults_path), args.project_type): logging.info("README Clean") else: logging.info("README Dirty") - if has_default_content(Path(args.input_directory), Path(args.defaults_path)): + if has_default_content(Path(args.input_directory), Path(args.defaults_path), args.project_type): logging.info("Content Clean") else: logging.info("Content Dirty")