diff --git a/.github/actions/setup-patmos/action.yml b/.github/actions/setup-patmos/action.yml new file mode 100644 index 0000000000..7ecc47a67e --- /dev/null +++ b/.github/actions/setup-patmos/action.yml @@ -0,0 +1,34 @@ +name: Install Patmos and dependencies (Linux only) +description: Install Patmos and dependencies (Linux only) +runs: + using: "composite" + steps: + - name: Setup + run: | + # install needed tools + sudo apt install git openjdk-8-jdk cmake make g++ texinfo flex bison \ + subversion libelf-dev graphviz libboost-dev libboost-program-options-dev ruby-full \ + liblpsolve55-dev zlib1g-dev gtkwave gtkterm scala autoconf libfl2 expect verilator curl + + # install sbt + + sudo apt-get update + sudo apt-get install apt-transport-https curl gnupg -yqq + echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list + echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | sudo tee /etc/apt/sources.list.d/sbt_old.list + curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo -H gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/scalasbt-release.gpg --import + sudo chmod 644 /etc/apt/trusted.gpg.d/scalasbt-release.gpg + sudo apt-get update + sudo apt-get install sbt + + # Clone the Patmos repository + export PATH=$PATH:$HOME/t-crest/local/bin + echo "PATH=$PATH:$HOME/t-crest/local/bin" >> "$GITHUB_ENV" + echo $PATH + mkdir ~/t-crest + cd ~/t-crest + git clone https://github.com/t-crest/patmos-misc.git misc + ./misc/build.sh + patmos-clang --version + which patmos-clang + shell: bash diff --git a/.github/workflows/c-embedded.yml b/.github/workflows/c-embedded.yml index df6cfa81c7..ea9b2acf25 100644 --- a/.github/workflows/c-embedded.yml +++ b/.github/workflows/c-embedded.yml @@ -23,3 +23,7 @@ jobs: # # Run the C FlexPRET integration tests. # flexpret: # uses: ./.github/workflows/c-flexpret-tests.yml + + # Run the C Patmos integration tests. + patmos: + uses: ./.github/workflows/c-patmos-tests.yml diff --git a/.github/workflows/c-patmos-tests.yml b/.github/workflows/c-patmos-tests.yml new file mode 100644 index 0000000000..5dedf58682 --- /dev/null +++ b/.github/workflows/c-patmos-tests.yml @@ -0,0 +1,56 @@ +name: C Patmos tests + +on: + workflow_call: + inputs: + compiler-ref: + required: false + type: string + runtime-ref: + required: false + type: string + use-cpp: + required: false + type: boolean + default: false + scheduler: + required: false + type: string + all-platforms: + required: false + default: true + type: boolean + +jobs: + Patmos-tests: + runs-on: ubuntu-latest + steps: + - name: Check out lingua-franca repository + uses: actions/checkout@v3 + with: + repository: lf-lang/lingua-franca + submodules: true + ref: ${{ inputs.compiler-ref }} + fetch-depth: 0 + - name: Prepare build environment + uses: ./.github/actions/prepare-build-env + - name: Setup and build Patmos + uses: ./.github/actions/setup-patmos + - name: Check out specific ref of reactor-c + uses: actions/checkout@v3 + with: + repository: lf-lang/reactor-c + path: core/src/main/resources/lib/c/reactor-c + ref: ${{ inputs.runtime-ref }} + if: ${{ inputs.runtime-ref }} + - name: Run Patmos smoke tests + run: | + ./gradlew core:integrationTest \ + --tests org.lflang.tests.runtime.CPatmosTest.* \ + core:integrationTestCodeCoverageReport + rm -rf test/C/src-gen + - name: Report to CodeCov + uses: ./.github/actions/report-code-coverage + with: + files: core/build/reports/jacoco/integrationTestCodeCoverageReport/integrationTestCodeCoverageReport.xml + if: ${{ github.repository == 'lf-lang/lingua-franca' }} diff --git a/.github/workflows/rti-docker.yml b/.github/workflows/rti-docker.yml index a26b930b87..c5ba1e0620 100644 --- a/.github/workflows/rti-docker.yml +++ b/.github/workflows/rti-docker.yml @@ -30,7 +30,7 @@ jobs: latest: false DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} - if: ${{ endsWith(env.lf_version, '-snapshot') && github.repository_owner == 'lf-lang' }} + if: ${{ endsWith(env.lf_version, '-snapshot') && github.repository_owner == 'lf-lang' }} - name: Update latest (released versions only) uses: ./.github/actions/push-rti-docker @@ -39,4 +39,4 @@ jobs: latest: true DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} - if: ${{ !endsWith(env.lf_version, '-snapshot') && github.repository_owner == 'lf-lang' }} + if: ${{ !endsWith(env.lf_version, '-snapshot') && github.repository_owner == 'lf-lang' }} diff --git a/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java b/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java index 2f170ec488..e35d45f79f 100644 --- a/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java @@ -232,7 +232,7 @@ public static boolean compatibleWithThreadingOff(TestCategory category) { // CONCURRENT, FEDERATED, DOCKER_FEDERATED, DOCKER // are not compatible with single-threaded execution. - // ARDUINO, ZEPHYR and FLEXPRET have their own test suites, so we don't need to rerun. + // ARDUINO, ZEPHYR, FLEXPRET, and PATMOS have their own test suites, so we don't need to rerun. boolean excluded = category == TestCategory.CONCURRENT || category == TestCategory.SERIALIZATION @@ -245,7 +245,8 @@ public static boolean compatibleWithThreadingOff(TestCategory category) { || category == TestCategory.ZEPHYR_UNTHREADED || category == TestCategory.ZEPHYR_BOARDS || category == TestCategory.ZEPHYR_THREADED - || category == TestCategory.FLEXPRET; + || category == TestCategory.FLEXPRET + || category == TestCategory.PATMOS; // SERIALIZATION and TARGET tests are excluded on Windows. excluded |= isWindows() && category == TestCategory.TARGET; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java index cd890517f7..687a12011e 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java @@ -48,6 +48,7 @@ private static boolean isExcludedFromCCpp(TestCategory category) { excluded |= category == TestCategory.ZEPHYR_THREADED; excluded |= category == TestCategory.ZEPHYR_BOARDS; excluded |= category == TestCategory.ARDUINO; + excluded |= category == TestCategory.PATMOS; excluded |= category == TestCategory.NO_INLINING; excluded |= category == TestCategory.VERIFIER; return !excluded; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CPatmosTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CPatmosTest.java new file mode 100644 index 0000000000..8dd7c67e35 --- /dev/null +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CPatmosTest.java @@ -0,0 +1,54 @@ +/************* + * Copyright (c) 2023, The University of California at Berkeley. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************/ +package org.lflang.tests.runtime; + +import java.util.List; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import org.lflang.target.Target; +import org.lflang.tests.Configurators; +import org.lflang.tests.TestBase; +import org.lflang.tests.TestRegistry.TestCategory; +import org.lflang.tests.Transformers; + +public class CPatmosTest extends TestBase { + + public CPatmosTest() { + super(Target.C); + } + + @Test + public void buildPatmosBasicTestsUnthreaded() { + Assumptions.assumeTrue(isLinux(), "Patmos tests only supported on Linux"); + super.runTestsFor( + List.of(Target.C), + "Build basic tests for Patmos in single threaded mode.", + TestCategory.BASIC::equals, + Transformers::noChanges, + Configurators::makePatmosCompatibleUnthreaded, + TestLevel.BUILD, + false); + } +} diff --git a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java index e184faedd6..5931399052 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -225,7 +225,16 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("set(FP_FLASH_DEVICE " + selectedFlashDevice.value() + ")"); cMakeCode.newLine(); } // No FP_FLASH_DEVICE will automatically become /dev/ttyUSB0 - + break; + case PATMOS: + cMakeCode.newLine(); + cMakeCode.pr("# Include toolchain file and set project"); + cMakeCode.pr( + "find_program(CLANG_EXECUTABLE NAMES patmos-clang REQUIRED DOC \"Path to the clang" + + " front-end.\")"); + cMakeCode.pr("set(CMAKE_C_COMPILER ${CLANG_EXECUTABLE})"); + cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); + cMakeCode.newLine(); break; default: cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); @@ -328,6 +337,13 @@ CodeBuilder generateCMakeCode( executableName, Stream.concat(additionalSources.stream(), sources.stream()))); break; + case PATMOS: + cMakeCode.pr( + setUpMainTargetPatmos( + hasMain, + executableName, + Stream.concat(additionalSources.stream(), sources.stream()))); + break; default: cMakeCode.pr( setUpMainTarget.getCmakeCode( @@ -616,4 +632,31 @@ private static String setUpMainTargetFlexPRET( return code.toString(); } + + private static String setUpMainTargetPatmos( + boolean hasMain, String executableName, Stream cSources) { + var code = new CodeBuilder(); + code.pr("add_subdirectory(core)"); + code.newLine(); + + code.pr("set(LF_MAIN_TARGET " + executableName + ")"); + code.newLine(); + + if (hasMain) { + code.pr("# Declare a new executable target and list all its sources"); + code.pr("add_executable("); + } else { + code.pr("# Declare a new library target and list all its sources"); + code.pr("add_library("); + } + code.indent(); + code.pr("${LF_MAIN_TARGET}"); + + cSources.forEach(code::pr); + code.unindent(); + code.pr(")"); + code.newLine(); + + return code.toString(); + } } diff --git a/core/src/main/java/org/lflang/target/property/type/PlatformType.java b/core/src/main/java/org/lflang/target/property/type/PlatformType.java index 4bfc726f9f..650a033b4c 100644 --- a/core/src/main/java/org/lflang/target/property/type/PlatformType.java +++ b/core/src/main/java/org/lflang/target/property/type/PlatformType.java @@ -19,6 +19,7 @@ public enum Platform { MAC("Darwin"), ZEPHYR("Zephyr"), FLEXPRET("FlexPRET"), + PATMOS("Patmos"), WINDOWS("Windows"); final String cMakeName; diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 91522e57bd..aa85b16a90 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -132,6 +132,33 @@ public static boolean makeFlexPRETCompatibleUnthreaded(TargetConfig config) { return makeFlexPRETCompatible(config); } + public static boolean makePatmosCompatible(TargetConfig config) { + /** + * Patmos has a maximum of eight hardware threads; override the chosen number of worker threads + * to be 0 (meaning run-time selects it). + * + *

This is to avoid failing tests that have e.g., `workers: 16`. + */ + WorkersProperty.INSTANCE.override(config, 0); + + var platform = config.get(PlatformProperty.INSTANCE); + PlatformProperty.INSTANCE.override( + config, + new PlatformOptions( + Platform.PATMOS, + new Option(true, "emulator"), + platform.port(), + platform.baudRate(), + new Option(true, false), + platform.userThreads())); + return true; + } + + public static boolean makePatmosCompatibleUnthreaded(TargetConfig config) { + disableThreading(config); + return makePatmosCompatible(config); + } + /** * Make no changes to the configuration. * diff --git a/core/src/testFixtures/java/org/lflang/tests/TestRegistry.java b/core/src/testFixtures/java/org/lflang/tests/TestRegistry.java index ab20848871..fc74f30d76 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestRegistry.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestRegistry.java @@ -337,6 +337,7 @@ public enum TestCategory { ZEPHYR_UNTHREADED(false, "zephyr" + File.separator + "unthreaded", TestLevel.BUILD), ZEPHYR_BOARDS(false, "zephyr" + File.separator + "boards", TestLevel.BUILD), FLEXPRET(false, "flexpret", TestLevel.BUILD), + PATMOS(false, "patmos", TestLevel.BUILD), VERIFIER(false, "verifier", TestLevel.EXECUTION), TARGET(false, "", TestLevel.EXECUTION); diff --git a/test/C/src/patmos/HelloPatmos.lf b/test/C/src/patmos/HelloPatmos.lf new file mode 100644 index 0000000000..48c36c139b --- /dev/null +++ b/test/C/src/patmos/HelloPatmos.lf @@ -0,0 +1,11 @@ +target C { + platform: "Patmos", + single-threaded: true, + build-type: Debug +} + +main reactor { + reaction(startup) {= + printf("Hello World!\n"); + =} +}