diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index abdb74b8a3..6cce0f4c7e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -238,19 +238,20 @@ hello-pk: - when: manual allow_failure: true -iti-test: +it-test: extends: - .synthesis_test variables: - DASHBOARD_JOB_TITLE: "ITI test" - DASHBOARD_JOB_DESCRIPTION: "Short test to challenge the Instruction Trace Interface" + DASHBOARD_JOB_TITLE: "Instruction Trace test" + DASHBOARD_JOB_DESCRIPTION: "Test to Challenge the Hardware flow of the Instruction Tracer" DASHBOARD_SORT_INDEX: 0 DASHBOARD_JOB_CATEGORY: "Basic" DV_SIMULATORS: "vcs-testharness" script: - - bash verif/regress/iti_test.sh - - diff .gitlab-ci/iti_reference.trace .gitlab-ci/iti.trace + - python3 .gitlab-ci/scripts/report_fail.py + - bash verif/regress/Instr_tracing_test.sh ../tests/custom/ITI/test_iti_asm.o - python3 .gitlab-ci/scripts/report_pass.py + - cp -r verif/sim/Instr_tracing_artifact artifacts/ spyglass: extends: diff --git a/.gitlab-ci/iti_reference.trace b/.gitlab-ci/iti_reference.trace deleted file mode 100644 index 7cc59cebbe..0000000000 --- a/.gitlab-ci/iti_reference.trace +++ /dev/null @@ -1,159 +0,0 @@ -i : 1 , val = 1 , iret = 12, ilast = 0x1 , itype = 6 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x00010000 -i : 0 , val = 1 , iret = 39, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80000000 -i : 0 , val = 1 , iret = 19, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80000058 -i : 0 , val = 1 , iret = 76, ilast = 0x0 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000007e -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003f12 -i : 0 , val = 1 , iret = 7, ilast = 0x0 , itype = 6 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003f52 -i : 0 , val = 1 , iret = 35, ilast = 0x0 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003602 -i : 0 , val = 1 , iret = 36, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003fc4 -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 18, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003ffa -i : 0 , val = 1 , iret = 7, ilast = 0x0 , itype = 6 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000401e -i : 0 , val = 1 , iret = 5, ilast = 0x0 , itype = 6 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000362a -i : 0 , val = 1 , iret = 15, ilast = 0x0 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003662 -i : 0 , val = 1 , iret = 5, ilast = 0x0 , itype = 6 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000359e -i : 1 , val = 1 , iret = 17, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000366c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004262 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004266 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426a -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000426e -i : 1 , val = 1 , iret = 7, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004272 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004280 -i : 1 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004284 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004288 -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x8000428c -i : 0 , val = 1 , iret = 2, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004290 -i : 0 , val = 1 , iret = 2, ilast = 0x0 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004294 -i : 0 , val = 1 , iret = 1, ilast = 0x0 , itype = 6 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80004298 -i : 0 , val = 1 , iret = 6, ilast = 0x0 , itype = 6 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003014 -i : 0 , val = 1 , iret = 12, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003672 -i : 0 , val = 1 , iret = 9, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003680 -i : 0 , val = 1 , iret = 10, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x800036d8 -i : 0 , val = 1 , iret = 9, ilast = 0x0 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x80003680 -i : 0 , val = 1 , iret = 10, ilast = 0x1 , itype = 4 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x800036d8 -i : 0 , val = 1 , iret = 4, ilast = 0x1 , itype = 5 , cause = 0x00 , tval= 0x00000000 , priv = 0x3 , iadd= 0x800036ec diff --git a/Makefile b/Makefile index f43516e205..73472b017b 100644 --- a/Makefile +++ b/Makefile @@ -201,17 +201,34 @@ src := $(if $(spike-tandem),verif/tb/core/uvma_core_cntrl_pkg.sv) vendor/pulp-platform/tech_cells_generic/src/deprecated/cluster_clk_cells.sv \ vendor/pulp-platform/tech_cells_generic/src/deprecated/pulp_clk_cells.sv \ vendor/pulp-platform/tech_cells_generic/src/rtl/tc_clk.sv \ - core/include/iti_pkg.sv \ + corev_apu/instr_tracing/ITI/include/iti_pkg.sv \ + corev_apu/instr_tracing/rv_tracer-main/include/te_pkg.sv \ + corev_apu/instr_tracing/rv_encapsulator-main/src/include/encap_pkg.sv \ corev_apu/tb/ariane_testharness.sv \ corev_apu/tb/ariane_peripherals.sv \ corev_apu/tb/rvfi_tracer.sv \ corev_apu/tb/common/uart.sv \ corev_apu/tb/common/SimDTM.sv \ corev_apu/tb/common/SimJTAG.sv \ - core/cva6_iti/instr_to_trace.sv \ - core/cva6_iti/iti.sv \ - core/cva6_iti/itype_detector.sv - + corev_apu/instr_tracing/ITI/cva6_iti/iti.sv \ + corev_apu/instr_tracing/ITI/cva6_iti/block_retirement.sv \ + corev_apu/instr_tracing/ITI/cva6_iti/single_retirement.sv \ + corev_apu/instr_tracing/ITI/cva6_iti/itype_detector.sv \ + vendor/pulp-platform/common_cells/src/counter.sv \ + vendor/pulp-platform/common_cells/src/sync.sv \ + vendor/pulp-platform/common_cells/src/sync_wedge.sv \ + vendor/pulp-platform/common_cells/src/edge_detect.sv \ + corev_apu/instr_tracing/rv_tracer-main/rtl/lzc.sv \ + corev_apu/instr_tracing/rv_tracer-main/rtl/te_branch_map.sv \ + corev_apu/instr_tracing/rv_tracer-main/rtl/te_filter.sv \ + corev_apu/instr_tracing/rv_tracer-main/rtl/te_packet_emitter.sv \ + corev_apu/instr_tracing/rv_tracer-main/rtl/te_priority.sv \ + corev_apu/instr_tracing/rv_tracer-main/rtl/te_reg.sv \ + corev_apu/instr_tracing/rv_tracer-main/rtl/te_resync_counter.sv \ + corev_apu/instr_tracing/rv_tracer-main/rtl/rv_tracer.sv \ + vendor/pulp-platform/common_cells/src/fifo_v3.sv \ + corev_apu/instr_tracing/DPTI/slicer_DPTI.sv \ + corev_apu/instr_tracing/rv_encapsulator-main/src/rtl/encapsulator.sv src := $(addprefix $(root-dir), $(src)) copro_src := core/cvxif_example/include/cvxif_instr_pkg.sv \ @@ -221,6 +238,9 @@ copro_src := $(addprefix $(root-dir), $(copro_src)) uart_src := $(wildcard corev_apu/fpga/src/apb_uart/src/vhdl_orig/*.vhd) uart_src := $(addprefix $(root-dir), $(uart_src)) +dpti_src := $(wildcard corev_apu/instr_tracing/DPTI/*.vhd) +dpti_src := $(addprefix $(root-dir), $(dpti_src)) + uart_src_sv:= corev_apu/fpga/src/apb_uart/src/slib_clock_div.sv \ corev_apu/fpga/src/apb_uart/src/slib_counter.sv \ corev_apu/fpga/src/apb_uart/src/slib_edge_detect.sv \ @@ -316,6 +336,7 @@ incdir := $(CVA6_REPO_DIR)/vendor/pulp-platform/common_cells/include/ $(CVA6_REP $(CVA6_REPO_DIR)/verif/core-v-verif/lib/uvm_agents/uvma_core_cntrl/ \ $(CVA6_REPO_DIR)/verif/tb/core/ \ $(CVA6_REPO_DIR)/core/include/ \ + $(CVA6_REPO_DIR)/corev_apu/instr_tracing/ITI/include \ $(SPIKE_INSTALL_DIR)/include/disasm/ # Compile and sim flags @@ -788,9 +809,10 @@ fpga_filter += $(addprefix $(root-dir), core/cache_subsystem/hpdcache/rtl/src/co $(addprefix $(root-dir), corev_apu/fpga/src/bootrom/bootrom_$(XLEN).sv): $(MAKE) -C corev_apu/fpga/src/bootrom BOARD=$(BOARD) XLEN=$(XLEN) PLATFORM=$(PLATFORM) bootrom_$(XLEN).sv -fpga: $(ariane_pkg) $(src) $(fpga_src) $(uart_src) $(src_flist) +fpga: $(ariane_pkg) $(src) $(fpga_src) $(uart_src) $(dpti_src) $(src_flist) @echo "[FPGA] Generate sources" @echo read_vhdl {$(uart_src)} > corev_apu/fpga/scripts/add_sources.tcl + @echo read_vhdl {$(dpti_src)} >> corev_apu/fpga/scripts/add_sources.tcl @echo read_verilog -sv {$(ariane_pkg)} >> corev_apu/fpga/scripts/add_sources.tcl @echo read_verilog -sv {$(filter-out $(fpga_filter), $(src_flist))} >> corev_apu/fpga/scripts/add_sources.tcl @echo read_verilog -sv {$(filter-out $(fpga_filter), $(src))} >> corev_apu/fpga/scripts/add_sources.tcl diff --git a/README.md b/README.md index 3adca597e7..c7e4ec03fe 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ bash verif/regress/smoke-tests.sh * **[Running Simulations](tutorials/running_sim.md)** * **[ASIC Implementation](tutorials/asic.md)** * **[FPGA Implementation and running an OS](tutorials/fpga.md)** - +* **[Instruction Tracing](corev_apu/instr_tracing/README.md)** # Directory Structure diff --git a/core/cva6_rvfi.sv b/core/cva6_rvfi.sv index ca7881233c..9e4487e99e 100644 --- a/core/cva6_rvfi.sv +++ b/core/cva6_rvfi.sv @@ -164,7 +164,7 @@ module cva6_rvfi assign branch_valid_iti = instr.branch_valid; assign is_taken_iti = instr.is_taken; assign tval_iti = instr.tval; - assign time_iti = rvfi_probes_i.csr.cycle_q; + assign time_iti = csr.cycle_q; assign priv_lvl = instr.priv_lvl; @@ -369,113 +369,109 @@ module cva6_rvfi //---------------------------------------------------------------------------------------------------------- // CSR //---------------------------------------------------------------------------------------------------------- - - `define CONNECT_RVFI_FULL(CSR_ENABLE_COND, CSR_NAME, - CSR_SOURCE_NAME) \ - always_ff @(posedge clk_i) begin \ - if (CSR_ENABLE_COND) begin \ - rvfi_csr_o.``CSR_NAME``.rdata <= {{CVA6Cfg.XLEN - $bits(CSR_SOURCE_NAME)}, CSR_SOURCE_NAME}; \ - end \ - end \ - assign rvfi_csr_o.``CSR_NAME``.wdata = CSR_ENABLE_COND ? { {{CVA6Cfg.XLEN-$bits(CSR_SOURCE_NAME)}, CSR_SOURCE_NAME} } : 0; \ - assign rvfi_csr_o.``CSR_NAME``.rmask = CSR_ENABLE_COND ? 1 : 0; \ - assign rvfi_csr_o.``CSR_NAME``.wmask = (rvfi_csr_o.``CSR_NAME``.rdata != {{CVA6Cfg.XLEN - $bits(CSR_SOURCE_NAME)}, CSR_SOURCE_NAME}) && CSR_ENABLE_COND; + // Changing verible formating to fix vivado synthesis errors and warnings + `define CONNECT_RVFI_FULL(CSR_ENABLE_COND, CSR_NAME, CSR_SOURCE_NAME) \ + always_ff @(posedge clk_i) begin \ + if (CSR_ENABLE_COND) begin \ + rvfi_csr_o.``CSR_NAME``.rdata <= {{CVA6Cfg.XLEN - $bits(CSR_SOURCE_NAME)}, CSR_SOURCE_NAME}; \ + end \ + end \ + assign rvfi_csr_o.``CSR_NAME``.wdata = CSR_ENABLE_COND ? { {{CVA6Cfg.XLEN-$bits(CSR_SOURCE_NAME)}, CSR_SOURCE_NAME} } : 0; \ + assign rvfi_csr_o.``CSR_NAME``.rmask = CSR_ENABLE_COND ? 1 : 0; \ + assign rvfi_csr_o.``CSR_NAME``.wmask = (rvfi_csr_o.``CSR_NAME``.rdata != {{CVA6Cfg.XLEN - $bits(CSR_SOURCE_NAME)}, CSR_SOURCE_NAME}) && CSR_ENABLE_COND; `define CONNECT_RVFI_SAME(CSR_ENABLE_COND, CSR_NAME) \ - `CONNECT_RVFI_FULL(CSR_ENABLE_COND, CSR_NAME, csr.``CSR_NAME``_q) + `CONNECT_RVFI_FULL(CSR_ENABLE_COND, CSR_NAME, csr.``CSR_NAME``_q) - `CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, fflags, csr.fcsr_q.fflags) - `CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, frm, csr.fcsr_q.frm) - `CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, fcsr, {csr.fcsr_q.frm, csr.fcsr_q.fflags}) + if ($bits(rvfi_csr_o) != 1) begin + `CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, fflags, csr.fcsr_q.fflags) + `CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, frm, csr.fcsr_q.frm) + `CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, fcsr, {csr.fcsr_q.frm, csr.fcsr_q.fflags}) - `CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, ftran, csr.fcsr_q.fprec) - `CONNECT_RVFI_SAME(CVA6Cfg.FpPresent, dcsr) + `CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, ftran, csr.fcsr_q.fprec) + `CONNECT_RVFI_SAME(CVA6Cfg.FpPresent, dcsr) - `CONNECT_RVFI_SAME(CVA6Cfg.DebugEn, dpc) + `CONNECT_RVFI_SAME(CVA6Cfg.DebugEn, dpc) - `CONNECT_RVFI_SAME(CVA6Cfg.DebugEn, dscratch0) - `CONNECT_RVFI_SAME(CVA6Cfg.DebugEn, dscratch1) + `CONNECT_RVFI_SAME(CVA6Cfg.DebugEn, dscratch0) + `CONNECT_RVFI_SAME(CVA6Cfg.DebugEn, dscratch1) - `CONNECT_RVFI_FULL(CVA6Cfg.RVS, sstatus, - csr.mstatus_extended & SMODE_STATUS_READ_MASK[CVA6Cfg.XLEN-1:0]) + `CONNECT_RVFI_FULL(CVA6Cfg.RVS, sstatus, csr.mstatus_extended & SMODE_STATUS_READ_MASK[CVA6Cfg.XLEN-1:0]) - `CONNECT_RVFI_FULL(CVA6Cfg.RVS, sie, csr.mie_q & csr.mideleg_q) - `CONNECT_RVFI_FULL(CVA6Cfg.RVS, sip, csr.mip_q & csr.mideleg_q) + `CONNECT_RVFI_FULL(CVA6Cfg.RVS, sie, csr.mie_q & csr.mideleg_q) + `CONNECT_RVFI_FULL(CVA6Cfg.RVS, sip, csr.mip_q & csr.mideleg_q) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, stvec) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, stvec) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, scounteren) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, scounteren) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, sscratch) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, sepc) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, sscratch) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, sepc) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, scause) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, scause) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, stval) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, satp) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, stval) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, satp) - `CONNECT_RVFI_FULL(1'b1, mstatus, csr.mstatus_extended) + `CONNECT_RVFI_FULL(1'b1, mstatus, csr.mstatus_extended) - bit [31:0] mstatush_q; - `CONNECT_RVFI_FULL(1'b1, mstatush, mstatush_q) + bit [31:0] mstatush_q; + `CONNECT_RVFI_FULL(1'b1, mstatush, mstatush_q) - `CONNECT_RVFI_FULL(1'b1, misa, IsaCode) + `CONNECT_RVFI_FULL(1'b1, misa, IsaCode) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, medeleg) - `CONNECT_RVFI_SAME(CVA6Cfg.RVS, mideleg) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, medeleg) + `CONNECT_RVFI_SAME(CVA6Cfg.RVS, mideleg) - `CONNECT_RVFI_SAME(1'b1, mie) - `CONNECT_RVFI_SAME(1'b1, mtvec) - `CONNECT_RVFI_SAME(1'b1, mcounteren) + `CONNECT_RVFI_SAME(1'b1, mie) + `CONNECT_RVFI_SAME(1'b1, mtvec) + `CONNECT_RVFI_SAME(1'b1, mcounteren) - `CONNECT_RVFI_SAME(1'b1, mscratch) + `CONNECT_RVFI_SAME(1'b1, mscratch) - `CONNECT_RVFI_SAME(1'b1, mepc) - `CONNECT_RVFI_SAME(1'b1, mcause) - `CONNECT_RVFI_SAME(1'b1, mtval) - `CONNECT_RVFI_SAME(1'b1, mip) + `CONNECT_RVFI_SAME(1'b1, mepc) + `CONNECT_RVFI_SAME(1'b1, mcause) + `CONNECT_RVFI_SAME(1'b1, mtval) + `CONNECT_RVFI_SAME(1'b1, mip) - `CONNECT_RVFI_FULL(1'b1, menvcfg, csr.fiom_q) + `CONNECT_RVFI_FULL(1'b1, menvcfg, csr.fiom_q) - `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, menvcfgh, 32'h0) + `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, menvcfgh, 32'h0) - `CONNECT_RVFI_FULL(1'b1, mvendorid, OPENHWGROUP_MVENDORID) - `CONNECT_RVFI_FULL(1'b1, marchid, ARIANE_MARCHID) - `CONNECT_RVFI_FULL(1'b1, mhartid, hart_id_i) + `CONNECT_RVFI_FULL(1'b1, mvendorid, OPENHWGROUP_MVENDORID) + `CONNECT_RVFI_FULL(1'b1, marchid, ARIANE_MARCHID) + `CONNECT_RVFI_FULL(1'b1, mhartid, hart_id_i) - `CONNECT_RVFI_SAME(1'b1, mcountinhibit) + `CONNECT_RVFI_SAME(1'b1, mcountinhibit) - `CONNECT_RVFI_FULL(1'b1, mcycle, csr.cycle_q[CVA6Cfg.XLEN-1:0]) - `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, mcycleh, csr.cycle_q[63:32]) + `CONNECT_RVFI_FULL(1'b1, mcycle, csr.cycle_q[CVA6Cfg.XLEN-1:0]) + `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, mcycleh, csr.cycle_q[63:32]) - `CONNECT_RVFI_FULL(1'b1, minstret, csr.instret_q[CVA6Cfg.XLEN-1:0]) - `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, minstreth, csr.instret_q[63:32]) + `CONNECT_RVFI_FULL(1'b1, minstret, csr.instret_q[CVA6Cfg.XLEN-1:0]) + `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, minstreth, csr.instret_q[63:32]) - `CONNECT_RVFI_FULL(1'b1, cycle, csr.cycle_q[CVA6Cfg.XLEN-1:0]) - `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, cycleh, csr.cycle_q[63:32]) + `CONNECT_RVFI_FULL(1'b1, cycle, csr.cycle_q[CVA6Cfg.XLEN-1:0]) + `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, cycleh, csr.cycle_q[63:32]) - `CONNECT_RVFI_FULL(1'b1, instret, csr.instret_q[CVA6Cfg.XLEN-1:0]) - `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, instreth, csr.instret_q[63:32]) + `CONNECT_RVFI_FULL(1'b1, instret, csr.instret_q[CVA6Cfg.XLEN-1:0]) + `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, instreth, csr.instret_q[63:32]) - `CONNECT_RVFI_SAME(1'b1, dcache) - `CONNECT_RVFI_SAME(1'b1, icache) + `CONNECT_RVFI_SAME(1'b1, dcache) + `CONNECT_RVFI_SAME(1'b1, icache) - `CONNECT_RVFI_SAME(CVA6Cfg.EnableAccelerator, acc_cons) - `CONNECT_RVFI_SAME(CVA6Cfg.RVZCMT, jvt) - `CONNECT_RVFI_FULL(1'b1, pmpcfg0, csr.pmpcfg_q[CVA6Cfg.XLEN/8-1:0]) - `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, pmpcfg1, csr.pmpcfg_q[7:4]) + `CONNECT_RVFI_SAME(CVA6Cfg.EnableAccelerator, acc_cons) + `CONNECT_RVFI_SAME(CVA6Cfg.RVZCMT, jvt) + `CONNECT_RVFI_FULL(1'b1, pmpcfg0, csr.pmpcfg_q[CVA6Cfg.XLEN/8-1:0]) + `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, pmpcfg1, csr.pmpcfg_q[7:4]) - `CONNECT_RVFI_FULL(1'b1, pmpcfg2, csr.pmpcfg_q[8+:CVA6Cfg.XLEN/8]) - `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, pmpcfg3, csr.pmpcfg_q[15:12]) + `CONNECT_RVFI_FULL(1'b1, pmpcfg2, csr.pmpcfg_q[8+:CVA6Cfg.XLEN/8]) + `CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, pmpcfg3, csr.pmpcfg_q[15:12]) - bit [CVA6Cfg.XLEN-1:0] pmpaddr_q; - genvar i; - generate + bit [CVA6Cfg.XLEN-1:0] pmpaddr_q; + genvar i; for (i = 0; i < 16; i++) begin - `CONNECT_RVFI_FULL(1'b1, pmpaddr[i], { - csr.pmpaddr_q[i][CVA6Cfg.PLEN-3:1], pmpcfg_q[i].addr_mode[1]}) + `CONNECT_RVFI_FULL(1'b1, pmpaddr[i], {csr.pmpaddr_q[i][CVA6Cfg.PLEN-3:1], pmpcfg_q[i].addr_mode[1]}) end - endgenerate - ; - + ; + end endmodule diff --git a/corev_apu/fpga/Makefile b/corev_apu/fpga/Makefile index 678e224438..370b981a9d 100644 --- a/corev_apu/fpga/Makefile +++ b/corev_apu/fpga/Makefile @@ -12,6 +12,7 @@ ips := xlnx_axi_clock_converter.xci \ xlnx_axi_quad_spi.xci \ xlnx_axi_gpio.xci \ xlnx_clk_gen.xci \ + xlnx_dpti_clk.xci \ xlnx_mig_7_ddr3.xci ips := $(addprefix $(work-dir)/, $(ips)) diff --git a/corev_apu/fpga/constraints/ariane.xdc b/corev_apu/fpga/constraints/ariane.xdc index 714bc451cb..c2b6a13896 100644 --- a/corev_apu/fpga/constraints/ariane.xdc +++ b/corev_apu/fpga/constraints/ariane.xdc @@ -7,7 +7,7 @@ set_input_jitter tck 1.000 set_input_delay -clock tck -clock_fall 5 [get_ports tdi ] set_input_delay -clock tck -clock_fall 5 [get_ports tms ] set_output_delay -clock tck 5 [get_ports tdo ] -set_false_path -from [get_ports trst_n ] +set_false_path -from [get_ports trst_n ] set_max_delay -datapath_only -from [get_pins i_dmi_jtag/i_dmi_cdc/i_cdc_resp/i_src/data_src_q_reg*/C] -to [get_pins i_dmi_jtag/i_dmi_cdc/i_cdc_resp/i_dst/data_dst_q_reg*/D] 20.000 @@ -15,5 +15,30 @@ set_max_delay -datapath_only -from [get_pins i_dmi_jtag/i_dmi_cdc/i_cdc_resp/i_s set_max_delay -datapath_only -from [get_pins i_dmi_jtag/i_dmi_cdc/i_cdc_req/i_dst/ack_dst_q_reg/C] -to [get_pins i_dmi_jtag/i_dmi_cdc/i_cdc_req/i_src/ack_src_q_reg/D] 20.000 # set multicycle path on reset, on the FPGA we do not care about the reset anyway -set_multicycle_path -from [get_pins i_rstgen_main/i_rstgen_bypass/synch_regs_q_reg[3]/C] 4 -set_multicycle_path -from [get_pins i_rstgen_main/i_rstgen_bypass/synch_regs_q_reg[3]/C] 3 -hold +set_multicycle_path -from [get_pins {i_rstgen_main/i_rstgen_bypass/synch_regs_q_reg[3]/C}] 4 +set_multicycle_path -hold -from [get_pins {i_rstgen_main/i_rstgen_bypass/synch_regs_q_reg[3]/C}] 3 + +create_clock -period 16.667 -name prog_clko_pin -waveform {0.000 8.333} [get_ports prog_clko] + +set_input_delay -clock [get_clocks prog_clko_pin] -min -add_delay 1.000 [get_ports {prog_d[*]}] +set_input_delay -clock [get_clocks prog_clko_pin] -max -add_delay 7.150 [get_ports {prog_d[*]}] +set_input_delay -clock [get_clocks prog_clko_pin] -min -add_delay 1.000 [get_ports prog_rxen] +set_input_delay -clock [get_clocks prog_clko_pin] -max -add_delay 7.150 [get_ports prog_rxen] +set_input_delay -clock [get_clocks prog_clko_pin] -min -add_delay 1.000 [get_ports prog_txen] +set_input_delay -clock [get_clocks prog_clko_pin] -max -add_delay 7.150 [get_ports prog_txen] +set_output_delay -clock [get_clocks prog_clko_pin] -min -add_delay 0.400 [get_ports {prog_d[*]}] +set_output_delay -clock [get_clocks prog_clko_pin] -max -add_delay 8.600 [get_ports {prog_d[*]}] +set_output_delay -clock [get_clocks prog_clko_pin] -min -add_delay 0.400 [get_ports prog_oen] +set_output_delay -clock [get_clocks prog_clko_pin] -max -add_delay 8.600 [get_ports prog_oen] +set_output_delay -clock [get_clocks prog_clko_pin] -min -add_delay 0.400 [get_ports prog_rdn] +set_output_delay -clock [get_clocks prog_clko_pin] -max -add_delay 8.600 [get_ports prog_rdn] +set_output_delay -clock [get_clocks prog_clko_pin] -min -add_delay 0.400 [get_ports prog_wrn] +set_output_delay -clock [get_clocks prog_clko_pin] -max -add_delay 8.600 [get_ports prog_wrn] + +set_property IOB TRUE [get_ports {prog_d[*]}] +set_property IOB TRUE [get_ports prog_rxen] +set_property IOB TRUE [get_ports prog_txen] + +set_property DONT_TOUCH true [get_cells i_cva6_rvfi] +set_property DONT_TOUCH true [get_cells i_iti] +set_property DONT_TOUCH true [get_cells i_encapsulator] \ No newline at end of file diff --git a/corev_apu/fpga/constraints/genesys-2.xdc b/corev_apu/fpga/constraints/genesys-2.xdc index 52fd714452..2a99992571 100644 --- a/corev_apu/fpga/constraints/genesys-2.xdc +++ b/corev_apu/fpga/constraints/genesys-2.xdc @@ -8,6 +8,47 @@ set_property -dict { PACKAGE_PIN W27 IOSTANDARD LVCMOS33 } [get_ports { tdi set_property -dict { PACKAGE_PIN W28 IOSTANDARD LVCMOS33 } [get_ports { tdo }]; set_property -dict { PACKAGE_PIN W29 IOSTANDARD LVCMOS33 } [get_ports { tms }]; +#PMOD Header JA +set_property -dict {PACKAGE_PIN U27 IOSTANDARD LVCMOS33} [get_ports prog_clko]; #IO_L13P_T2_MRCC_14 +set_property -dict {PACKAGE_PIN U28 IOSTANDARD LVCMOS33} [get_ports prog_oen] +set_property -dict {PACKAGE_PIN T26 IOSTANDARD LVCMOS33} [get_ports prog_rdn] +set_property -dict {PACKAGE_PIN T27 IOSTANDARD LVCMOS33} [get_ports prog_rxen] +set_property -dict {PACKAGE_PIN T22 IOSTANDARD LVCMOS33} [get_ports prog_siwun] +set_property -dict {PACKAGE_PIN T23 IOSTANDARD LVCMOS33} [get_ports prog_spien] +set_property -dict {PACKAGE_PIN T20 IOSTANDARD LVCMOS33} [get_ports prog_txen] +set_property -dict {PACKAGE_PIN T21 IOSTANDARD LVCMOS33} [get_ports prog_wrn] + +#PMOD Header JB +set_property -dict {PACKAGE_PIN V29 IOSTANDARD LVCMOS33} [get_ports {prog_d[0]}] +set_property -dict {PACKAGE_PIN V30 IOSTANDARD LVCMOS33} [get_ports {prog_d[1]}] +set_property -dict {PACKAGE_PIN V25 IOSTANDARD LVCMOS33} [get_ports {prog_d[2]}] +set_property -dict {PACKAGE_PIN W26 IOSTANDARD LVCMOS33} [get_ports {prog_d[3]}] +set_property -dict {PACKAGE_PIN T25 IOSTANDARD LVCMOS33} [get_ports {prog_d[4]}] +set_property -dict {PACKAGE_PIN U25 IOSTANDARD LVCMOS33} [get_ports {prog_d[5]}] +set_property -dict {PACKAGE_PIN U22 IOSTANDARD LVCMOS33} [get_ports {prog_d[6]}] +set_property -dict {PACKAGE_PIN U23 IOSTANDARD LVCMOS33} [get_ports {prog_d[7]}] + + +#PMOD Header JC +# set_property -dict {PACKAGE_PIN AC26 IOSTANDARD LVCMOS33} [get_ports prog_clko] +# set_property -dict {PACKAGE_PIN AJ27 IOSTANDARD LVCMOS33} [get_ports prog_oen] +# set_property -dict {PACKAGE_PIN AH30 IOSTANDARD LVCMOS33} [get_ports prog_rdn] +# set_property -dict {PACKAGE_PIN AK29 IOSTANDARD LVCMOS33} [get_ports prog_rxen] +# set_property -dict {PACKAGE_PIN AD26 IOSTANDARD LVCMOS33} [get_ports prog_siwun] +# set_property -dict {PACKAGE_PIN AG30 IOSTANDARD LVCMOS33} [get_ports prog_spien] +# set_property -dict {PACKAGE_PIN AK30 IOSTANDARD LVCMOS33} [get_ports prog_txen] +# set_property -dict {PACKAGE_PIN AK28 IOSTANDARD LVCMOS33} [get_ports prog_wrn] + +#PMOD Header JD +# set_property -dict {PACKAGE_PIN V27 IOSTANDARD LVCMOS33} [get_ports {prog_d[0]}] +# set_property -dict {PACKAGE_PIN Y30 IOSTANDARD LVCMOS33} [get_ports {prog_d[1]}] +# set_property -dict {PACKAGE_PIN V24 IOSTANDARD LVCMOS33} [get_ports {prog_d[2]}] +# set_property -dict {PACKAGE_PIN W22 IOSTANDARD LVCMOS33} [get_ports {prog_d[3]}] +# set_property -dict {PACKAGE_PIN U24 IOSTANDARD LVCMOS33} [get_ports {prog_d[4]}] +# set_property -dict {PACKAGE_PIN Y26 IOSTANDARD LVCMOS33} [get_ports {prog_d[5]}] +# set_property -dict {PACKAGE_PIN V22 IOSTANDARD LVCMOS33} [get_ports {prog_d[6]}] +# set_property -dict {PACKAGE_PIN W21 IOSTANDARD LVCMOS33} [get_ports {prog_d[7]}] + ## UART set_property -dict {PACKAGE_PIN Y23 IOSTANDARD LVCMOS33} [get_ports tx] set_property -dict {PACKAGE_PIN Y20 IOSTANDARD LVCMOS33} [get_ports rx] diff --git a/corev_apu/fpga/scripts/run.tcl b/corev_apu/fpga/scripts/run.tcl index 9ba9d4e187..3d6db4f3c9 100644 --- a/corev_apu/fpga/scripts/run.tcl +++ b/corev_apu/fpga/scripts/run.tcl @@ -37,6 +37,7 @@ read_ip { \ "xilinx/xlnx_axi_gpio/xlnx_axi_gpio.srcs/sources_1/ip/xlnx_axi_gpio/xlnx_axi_gpio.xci" \ "xilinx/xlnx_axi_quad_spi/xlnx_axi_quad_spi.srcs/sources_1/ip/xlnx_axi_quad_spi/xlnx_axi_quad_spi.xci" \ "xilinx/xlnx_clk_gen/xlnx_clk_gen.srcs/sources_1/ip/xlnx_clk_gen/xlnx_clk_gen.xci" \ + "xilinx/xlnx_dpti_clk/xlnx_dpti_clk.srcs/sources_1/ip/xlnx_dpti_clk/xlnx_dpti_clk.xci" \ } # read_ip xilinx/xlnx_protocol_checker/ip/xlnx_protocol_checker.xci @@ -46,6 +47,7 @@ set_property include_dirs { \ "../../vendor/pulp-platform/axi/include" \ "../../core/cache_subsystem/hpdcache/rtl/include" \ "../register_interface/include" \ + "../instr_tracing/ITI/include" \ "../../core/include" \ } [current_fileset] diff --git a/corev_apu/fpga/src/ariane_xilinx.sv b/corev_apu/fpga/src/ariane_xilinx.sv index 20e77f77c2..e856caf0c8 100644 --- a/corev_apu/fpga/src/ariane_xilinx.sv +++ b/corev_apu/fpga/src/ariane_xilinx.sv @@ -10,6 +10,9 @@ // Description: Xilinx FPGA top-level // Author: Florian Zaruba +`include "axi/assign.svh" +`include "rvfi_types.svh" +`include "iti_types.svh" module ariane_xilinx ( // WARNING: Do not define input parameters. This causes the FPGA build to fail. @@ -177,11 +180,20 @@ module ariane_xilinx ( output logic spi_ss , output logic spi_clk_o , // common part - // input logic trst_n , + // input logic trst_n , input logic tck , input logic tms , input logic tdi , - output wire tdo , + output wire tdo , + input logic prog_clko , + input logic prog_rxen , + input logic prog_txen , + input logic prog_spien , + output logic prog_rdn , + output logic prog_wrn , + output logic prog_oen , + output logic prog_siwun , + inout logic [7:0] prog_d , input logic rx , output logic tx ); @@ -199,11 +211,17 @@ endfunction // CVA6 Xilinx configuration localparam config_pkg::cva6_cfg_t CVA6Cfg = build_fpga_config(cva6_config_pkg::cva6_cfg); +localparam type rvfi_instr_t = `RVFI_INSTR_T(CVA6Cfg); +//localparam type rvfi_csr_elmt_t = `RVFI_CSR_ELMT_T(CVA6Cfg); +//localparam type rvfi_csr_t = `RVFI_CSR_T(CVA6Cfg, rvfi_csr_elmt_t); +localparam type rvfi_to_iti_t = `RVFI_TO_ITI_T(CVA6Cfg); +localparam type iti_to_encoder_t = `ITI_TO_ENCODER_T(CVA6Cfg); + localparam type rvfi_probes_instr_t = `RVFI_PROBES_INSTR_T(CVA6Cfg); localparam type rvfi_probes_csr_t = `RVFI_PROBES_CSR_T(CVA6Cfg); localparam type rvfi_probes_t = struct packed { logic csr; - logic instr; + rvfi_probes_instr_t instr; }; // 24 MByte in 8 byte words @@ -753,6 +771,11 @@ end // --------------- ariane_axi::req_t axi_ariane_req; ariane_axi::resp_t axi_ariane_resp; +rvfi_probes_t rvfi_probes; + +rvfi_instr_t [CVA6Cfg.NrCommitPorts-1:0] rvfi_instr; +rvfi_to_iti_t rvfi_to_iti; +iti_to_encoder_t iti_to_encoder; ariane #( .CVA6Cfg ( CVA6Cfg ), @@ -767,7 +790,7 @@ ariane #( .irq_i ( irq ), .ipi_i ( ipi ), .time_irq_i ( timer_irq ), - .rvfi_probes_o( /* open */ ), + .rvfi_probes_o( rvfi_probes ), .debug_req_i ( debug_req_irq ), .noc_req_o ( axi_ariane_req ), .noc_resp_i ( axi_ariane_resp ) @@ -776,6 +799,136 @@ ariane #( `AXI_ASSIGN_FROM_REQ(slave[0], axi_ariane_req) `AXI_ASSIGN_TO_RESP(axi_ariane_resp, slave[0]) + cva6_rvfi #( + .CVA6Cfg (CVA6Cfg), + .rvfi_instr_t(rvfi_instr_t), + .rvfi_csr_t(), + .rvfi_probes_instr_t(rvfi_probes_instr_t), + .rvfi_probes_csr_t(rvfi_probes_csr_t), + .rvfi_probes_t(rvfi_probes_t), + .rvfi_to_iti_t(rvfi_to_iti_t) + ) i_cva6_rvfi ( + .clk_i (clk), + .rst_ni (ndmreset_n), + .rvfi_probes_i(rvfi_probes), + .rvfi_instr_o (rvfi_instr), + .rvfi_to_iti_o (rvfi_to_iti), + .rvfi_csr_o () + ); + + + cva6_iti #( + .CVA6Cfg (CVA6Cfg), + .CAUSE_LEN (iti_pkg::CAUSE_LEN), + .ITYPE_LEN (iti_pkg::ITYPE_LEN), + .IRETIRE_LEN (iti_pkg::IRETIRE_LEN), + .block_mode(0), + .rvfi_to_iti_t(rvfi_to_iti_t), + .iti_to_encoder_t(iti_to_encoder_t) + ) i_iti ( + .clk_i (clk), + .rst_ni (ndmreset_n), + // inputs from rvfi + .valid_i(rvfi_to_iti.valid), + .rvfi_to_iti_i(rvfi_to_iti), + // outputs for the encoder module TODO + .valid_o(), + .iti_to_encoder_o(iti_to_encoder) + ); + + logic packet_valid; + te_pkg::it_packet_type_e packet_type; + logic [te_pkg::P_LEN-1:0] packet_length; + logic [te_pkg::PAYLOAD_LEN-1:0] packet_payload; + + rv_tracer #( + .N(1), + .ONLY_BRANCHES(1) + )i_encoder( + .clk_i (clk), + .rst_ni (ndmreset_n), + .valid_i (iti_to_encoder.valid), + .itype_i (iti_to_encoder.itype), + .cause_i (iti_to_encoder.cause), + .tval_i (iti_to_encoder.tval), + .priv_i (iti_to_encoder.priv), + .iaddr_i (iti_to_encoder.iaddr), + .iretire_i (iti_to_encoder.iretire), + .ilastsize_i (iti_to_encoder.ilastsize), + .time_i (iti_to_encoder.cycles), + .tvec_i ('0), + .epc_i ('0), + .encapsulator_ready_i('1), + .paddr_i ('0), + .pwrite_i ('0), + .psel_i ('0), + .penable_i ('0), + .pwdata_i ('0), + .packet_valid_o (packet_valid), + .packet_type_o (packet_type), + .packet_length_o (packet_length), + .packet_payload_o (packet_payload), + .stall_o (), + .pready_o (), + .prdata_o () + ); + + logic encap_valid; + encap_pkg::encap_fifo_entry_s encap_fifo_entry_i; + encap_pkg::encap_fifo_entry_s encap_fifo_entry_o; + logic encap_fifo_full; + logic encap_fifo_empty; + logic encap_fifo_pop; + + encapsulator i_encapsulator ( + .clk_i (clk), + .valid_i (packet_valid), + .packet_length_i (packet_length), + .flow_i ('0), + .timestamp_present_i('1), + //.srcid_i(), + .timestamp_i (rvfi_to_iti.cycles), + //.type_i(), + .trace_payload_i (packet_payload), + .valid_o (encap_valid), + .encap_fifo_entry_o (encap_fifo_entry_i) + ); + + fifo_v3 # ( + .DEPTH(16), + .dtype(encap_pkg::encap_fifo_entry_s) + ) i_fifo_encap ( + .clk_i (clk), + .rst_ni (ndmreset_n), + .flush_i ('0), + .testmode_i('0), + .full_o (encap_fifo_full), + .empty_o (encap_fifo_empty), + .usage_o (), + .data_i (encap_fifo_entry_i), + .push_i (encap_valid), + .data_o (encap_fifo_entry_o), + .pop_i (encap_fifo_pop) + ); + + localparam DATA_LEN = 8; + logic valid_slice; + logic [DATA_LEN-1:0] slice; + logic [$clog2(DATA_LEN)-4:0] valid_bytes; + + slicer_DPTI #( + .SLICE_LEN(DATA_LEN), + .NO_TIME ('0) + ) i_slicer ( + .clk_i (clk), + .rst_ni (ndmreset_n), + .valid_i (!encap_fifo_empty), + .encap_fifo_entry_i(encap_fifo_entry_o), + .fifo_full_i (usrFull), // usrFull DPTI + .valid_o (valid_slice), + .slice_o (slice), + .done_o (encap_fifo_pop) + ); // --------------- // CLINT // --------------- @@ -848,7 +1001,67 @@ end else begin .rdata_o ( rom_rdata ) ); end +// --------------- +// DPTI +// --------------- +logic FifoEn ; +logic usrFull ; +logic usrEmpty ; +logic [7:0] w_data; +logic [7:0] r_data; + +logic [11:0] w_count; +logic [11:0] r_count; + +logic prog_rxen_debug; +logic prog_txen_debug; +logic prog_spien_debug; +logic prog_rdn_debug; +logic prog_wrn_debug; +logic prog_oen_debug; +logic prog_siwun_debug; + +assign prog_rxen_debug = prog_rxen; +assign prog_txen_debug = prog_txen; +assign prog_spien_debug = prog_spien; +assign prog_rdn_debug = prog_rdn; +assign prog_wrn_debug = prog_wrn; +assign prog_oen_debug = prog_oen; +assign prog_siwun_debug = prog_siwun; + +//assign w_data = {iti_to_encoder.itype[0],iti_to_encoder.itype[1],iti_to_encoder.valid} ; + +assign FifoEn = !usrFull && !usrEmpty; + dpti_ctrl i_dpti_ctrl ( + .wr_clk (clk), + .wr_en (valid_slice), + .wr_full(usrFull), + .wr_afull(), + .wr_err(), + .wr_count(w_count), + .wr_di(slice), + + .rd_clk(clk), + .rd_en(FifoEn), + .rd_empty(usrEmpty), + .rd_aempty(), + .rd_err (), + .rd_count(r_count), + .rd_do(r_data), + + .rst(rst), + + .prog_clko(prog_clko), + .prog_rxen(prog_rxen), + .prog_txen(prog_txen), + .prog_spien('0), + .prog_rdn(prog_rdn), + .prog_wrn(prog_wrn), + .prog_oen(prog_oen), + .prog_siwun(prog_siwun), + .prog_d(prog_d) +); // --------------- // Peripherals // --------------- diff --git a/corev_apu/fpga/xilinx/ariane_xlnx_ip.yml b/corev_apu/fpga/xilinx/ariane_xlnx_ip.yml index 2b3c0c1e51..a4ec93211b 100644 --- a/corev_apu/fpga/xilinx/ariane_xlnx_ip.yml +++ b/corev_apu/fpga/xilinx/ariane_xlnx_ip.yml @@ -50,6 +50,17 @@ xlnx_clk_gen: clkout4_requested_out_freq: 50 clkin1_jitter_ps: 50 +xlnx_dpti_clk: + ip: clk_wiz + vendor: xilinx.com + config: + prim_in_freq: 60 + num_out_clks: 2 + clkout2_used: true + clkout1_requested_out_freq: 60 + clkout1_requested_phase: 230 + clkout2_requested_out_freq: 60 + xlnx_ila: ip: ila vendor: xilinx.com diff --git a/corev_apu/fpga/xilinx/xlnx_dpti_clk/Makefile b/corev_apu/fpga/xilinx/xlnx_dpti_clk/Makefile new file mode 100644 index 0000000000..d1acb462e2 --- /dev/null +++ b/corev_apu/fpga/xilinx/xlnx_dpti_clk/Makefile @@ -0,0 +1,2 @@ +PROJECT:=xlnx_dpti_clk +include ../common.mk \ No newline at end of file diff --git a/corev_apu/fpga/xilinx/xlnx_dpti_clk/tcl/run.tcl b/corev_apu/fpga/xilinx/xlnx_dpti_clk/tcl/run.tcl new file mode 100644 index 0000000000..d836651eab --- /dev/null +++ b/corev_apu/fpga/xilinx/xlnx_dpti_clk/tcl/run.tcl @@ -0,0 +1,26 @@ +set partNumber $::env(XILINX_PART) +set boardName $::env(XILINX_BOARD) + +set ipName xlnx_dpti_clk + +create_project $ipName . -force -part $partNumber +set_property board_part $boardName [current_project] + +create_ip -name clk_wiz -vendor xilinx.com -library ip -module_name $ipName + +set_property -dict [list CONFIG.PRIM_IN_FREQ {60.000} \ + CONFIG.NUM_OUT_CLKS {2} \ + CONFIG.CLKOUT2_USED {true} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {60} \ + CONFIG.CLKOUT1_REQUESTED_PHASE {230.000} \ + CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {60} \ + CONFIG.USE_RESET {false} \ + ] [get_ips $ipName] + + +generate_target {instantiation_template} [get_files ./$ipName.srcs/sources_1/ip/$ipName/$ipName.xci] +generate_target all [get_files ./$ipName.srcs/sources_1/ip/$ipName/$ipName.xci] +create_ip_run [get_files -of_objects [get_fileset sources_1] ./$ipName.srcs/sources_1/ip/$ipName/$ipName.xci] +launch_run -jobs 8 ${ipName}_synth_1 +wait_on_run ${ipName}_synth_1 + diff --git a/corev_apu/instr_tracing/DPTI/Digilent.licence b/corev_apu/instr_tracing/DPTI/Digilent.licence new file mode 100644 index 0000000000..124159423d --- /dev/null +++ b/corev_apu/instr_tracing/DPTI/Digilent.licence @@ -0,0 +1,40 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software including rights to use, copy, redistribute, and/or sublicense the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The Software is only to be used with Digilent Inc. hardware directly or with +Digilent Inc. hardware included in an OEM device. + +The Software may be used for the development of custom programs by the +licensee, for use ONLY with Digilent Inc. hardware. This includes, but is not +limited to, all Dynamic Link Libraries (DLLs), Shared Libraries, documentation, +header files, and Applications Programming Interfaces (APIs). + +You agree that you will not modify, adapt, decompile, reverse engineer, +translate, or otherwise attempt to discover the source code for the Software. + +Digilent Inc. maintains all its rights under all applicable laws, including but +not limited to pertinent intellectual property laws. + +The above copyright notice and this permission notice shall be included in all +copies of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Copyright (c) 2022 Digilent Inc. + +Contact: +1300 NE Henley Ct. Suite 3 +Pullman, WA 99163 +United States of America + +digilent.com/support + \ No newline at end of file diff --git a/corev_apu/instr_tracing/DPTI/dpti_ctrl.vhd b/corev_apu/instr_tracing/DPTI/dpti_ctrl.vhd new file mode 100755 index 0000000000..7395fdab8f --- /dev/null +++ b/corev_apu/instr_tracing/DPTI/dpti_ctrl.vhd @@ -0,0 +1,399 @@ +---------------------------------------------------------------------------------- +-- Company: Digilent Inc. +-- Engineer: +-- +-- Create Date: 16:16:24 10/26/2011 +-- Design Name: +-- Module Name: dpti_ctrl - Behavioral +-- Project Name: +-- Target Devices: +-- Tool versions: +-- Description: This module implements a synchronous DPTI interface. It includes +-- two local FIFOs that allow the data to be moved from the DPTI clock domain +-- to another clock domain in the FPGA. +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- 5/30/2016(sjb) -- Prepared for public release +---------------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; + +-- Uncomment the following library declaration if using +-- arithmetic functions with Signed or Unsigned values +--use IEEE.NUMERIC_STD.ALL; + +-- Uncomment the following library declaration if instantiating +-- any Xilinx primitives in this code. +library UNISIM; +use UNISIM.VComponents.all; + +Library UNIMACRO; +use UNIMACRO.vcomponents.all; + +entity dpti_ctrl is + Port ( + --User Write FIFO signals + wr_clk : in std_logic; + wr_en : in std_logic; + wr_full : out std_logic; + wr_afull : out std_logic; + wr_err : out std_logic; + wr_count : out std_logic_vector(11 downto 0); + wr_di : in std_logic_vector(7 downto 0); + + --User Read FIFO signals + rd_clk : in std_logic; + rd_en : in std_logic; + rd_empty : out std_logic; + rd_aempty : out std_logic; + rd_err : out std_logic; + rd_count : out std_logic_vector(11 downto 0); + rd_do : out std_logic_vector(7 downto 0); + + --misc. signals + rst : in std_logic; --Asynchronously resets the entire component. Must be held high for at least 100ns, or 6 clock cycles of the slowest fifo clock if that is longer + + --DPTI Port signals + prog_clko : in STD_LOGIC; + prog_rxen : in STD_LOGIC; + prog_txen : in STD_LOGIC; + prog_spien : in STD_LOGIC; --called jtagen on some platforms + prog_rdn : out STD_LOGIC; + prog_wrn : out STD_LOGIC; + prog_oen : out STD_LOGIC; + prog_siwun : out STD_LOGIC; + prog_d : inout STD_LOGIC_VECTOR (7 downto 0)); +end dpti_ctrl; + +architecture Behavioral of dpti_ctrl is + + + + + +------------------------------------------------------------------------------- +-- Component Declarations +------------------------------------------------------------------------------- + +component xlnx_dpti_clk is +port + ( + CLK_IN1 : in std_logic; + CLK_OUT1 : out std_logic; + CLK_OUT2 : out std_logic; + LOCKED : out std_logic + ); +end component; + +------------------------------------------------------------------------------- +-- Local Type Declarations +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Constant Declarations +------------------------------------------------------------------------------- + +-- The following constants define state codes for the Synchronous PTI port +-- state machine. The high order bits of the state number provide a unique +-- state identifier for each state. The low order bits are the state machine +-- outputs for that state. This type of state machine implementation uses no +-- combinational logic to generate the outputs, which should result in glitch +-- free outputs. + + +constant stPtiRdy : std_logic_vector(6 downto 0):= "0" & "00" & "1111"; +constant stPtiInOut0 : std_logic_vector(6 downto 0):= "1" & "00" & "1111"; +constant stPtiInOut1 : std_logic_vector(6 downto 0):= "1" & "00" & "1011"; +constant stPtiInOut2 : std_logic_vector(6 downto 0):= "1" & "01" & "1010"; +constant stPtiInOut3 : std_logic_vector(6 downto 0):= "1" & "10" & "0101"; + +------------------------------------------------------------------------------- +-- Signal Declarations +------------------------------------------------------------------------------- + +signal stPtiCur : std_logic_vector(6 downto 0) := stPtiRdy; +signal stPtiNext : std_logic_vector(6 downto 0); + +signal clkPti : std_logic; +signal clkIOB : std_logic; +signal locked : std_logic; + +--user fifo signals +signal usrWrClk : std_logic; +signal usrWrEn : std_logic; +signal usrFull : std_logic; +signal usrAFull : std_logic; +signal usrWrErr : std_logic; +signal usrRdClk : std_logic; +signal usrRdEn : std_logic; +signal usrEmpty : std_logic; +signal usrAEmpty : std_logic; +signal usrRdErr : std_logic; +signal usrRdCnt : std_logic_vector(11 downto 0); +signal usrDO : std_logic_vector(7 downto 0); +signal usrWrCnt : std_logic_vector(11 downto 0); +signal usrDI : std_logic_vector(7 downto 0); + +-- Internal control signals +signal ctlRd : std_logic; +signal ctlWr : std_logic; +signal ctlOe : std_logic; +signal ctlDir : std_logic; + +signal ctlRxf : std_logic; +signal ctlTxe : std_logic; +signal ctlRst : std_logic; + +signal ctlFull : std_logic; +signal ctlAFull : std_logic; +signal ctlEmpty : std_logic; +signal ctlFwr : std_logic; +signal ctlFrd : std_logic; + +signal dummyWrCnt : std_logic_vector(11 downto 0); +signal dummyRdCnt : std_logic_vector(11 downto 0); + +signal busPtiTris : std_logic; +signal busPtiOut : std_logic_vector(7 downto 0); + +signal busPtiIn : std_logic_vector(7 downto 0); +signal busPtiInReg : std_logic_vector(7 downto 0); +signal busFifoOut : std_logic_vector(7 downto 0); + +------------------------------------------------------------------------------- +-- Module Implementation +------------------------------------------------------------------------------- + +begin + +--This clocking wizard is used to sychronize the clock used throughout this design +--with the prog_clko input. It reduces delays introduced by the global clocking +--network (~4ns in post-route simulation on Artix 200t). It is also used to generate +--a phase shifted clock for latching input data/flags +clkwiz_inst : xlnx_dpti_clk + port map + ( + CLK_IN1 => prog_clko, + CLK_OUT1 => clkIOB, + CLK_OUT2 => clkPti, + LOCKED => locked); + +--This process latches the inputs from the FTDI part at IOB flip-flops. They are latched +--using a phaseshifted clock about ~11ns after the rising edge of the input clock. This +--makes meeting the input delay timing constraints possible. Additional contstraints for +--traveling from the clkIOB domain to clkPti are automatically inferred by the tools +--because they have a known phase relationship (signals will need to settle in <~5ns). +--If the design fails interclock timing analysis with clkIOB, first ensure that IOB flip +--flops are being instantiated for the registers in this process. Then you can try reducing +--the phase shift by a few degrees (too much will cause the inputdelay constraints to fail). Last +--resort is to modify the design so that these flags are all immediately latched to the clkPti +--domain. +--@sjb: I recently came across this code and began questioning if it is necessary. At first thought, it seems +-- that latching the input signals would add to needed setup times vs. just letting them thru +-- asynchronously. It took me awhile, but I believe I understand why this is needed, so I have decided +-- to document my reasoning further for the next time someone comes across this. +-- I believe I inserted these because the FTDI part only holds the data on the bus valid for 1 ns +-- after a prog_clk edge, and I was concerned that the databus/ctrl signals might +-- beat the clock due to delays introduced by the clocking infrastructure. The IOBs treat this situation +-- by ensuring the data/ctrl gets latched internally the moment it is guarenteed to be valid. This seems like +-- the most architecture independent way to treat the problem, because it only requires three things, all of which +-- are very likely to be present in future FPGA architectures/devices: +-- 1) Ability to generate a clock with minimum input delay (~<3ns) +-- 2) IOB flip-flops with minimum setup requirement (~<3ns) +-- 3) Ability to generate a clock with a 230 degree phase shift relative to the generated clock with minimum input delay. +-- Last note, I think the input_delay constraints with the -min option in timing.xdc describe this requirement +-- to the tools. I'm pretty sure removing these flip-flops will cause the design to fail meeting those constraints. + +process(ctlRst, clkIOB) +begin + if (ctlRst = '1') then + busPtiInReg <= (others =>'0'); + ctlRxf <= '0'; + ctlTxe <= '0'; + elsif (rising_edge(clkIOB)) then + busPtiInReg <= busPtiIn; + ctlRxf <= prog_rxen; + ctlTxe <= prog_txen; + end if; +end process; + +------------------------------------------------------------------------------- +-- Map basic status and control signals +------------------------------------------------------------------------------- + +--Asynchronous reset signal +ctlRst <= (prog_spien or rst) or not(locked); + + +--Top level output mapping +prog_siwun <= '1'; +prog_wrn <= ctlWr; +prog_rdn <= ctlRd; +prog_oen <= ctlOe; + +-- Data bus direction and control. +IOBUF_gen : for index in 0 to 7 generate + IOBUF_inst : IOBUF + generic map ( + DRIVE => 16, + SLEW => "FAST") + port map ( + O => busPtiIn(index), -- Buffer output + IO => prog_d(index), -- Buffer inout port (connect directly to top-level port) + I => busPtiOut(index), -- Buffer input + T => busPtiTris -- 3-state enable input, high=input, low=output + ); +end generate; + +busPtiTris <= ctlDir or ctlRst; + +------------------------------------------------------------------------------- +-- PTI State Machine +------------------------------------------------------------------------------- + +-- Map glitch-less control signals from the current state +ctlRd <= stPtiCur(0); --keep in mind: active low +ctlWr <= stPtiCur(1) or ctlEmpty; --keep in mind: active low +ctlOe <= stPtiCur(2); +ctlDir <= stPtiCur(3); + +--Map additional control signals from the current state +ctlFwr <= stPtiCur(4) and not ctlRxf; +ctlFrd <= stPtiCur(5) and ((not ctlTxe) and (not ctlEmpty)); + +-- This process moves the state machine to the next state on each clock. +process (clkPti, ctlRst) +begin + if ctlRst = '1' then + stPtiCur <= stPtiRdy; + elsif clkPti = '1' and clkPti'Event then + stPtiCur <= stPtiNext; + end if; +end process; + +-- This process determines the next state based on the current state and the +-- state machine inputs. +-- TODO: It appears the bandwidth is very limited when the FTDI->FPGA FPGA side FIFO +-- gets almost filled (4080 out of 4096). Almost full seems to take a very long time +-- to deassert, regardless of how fast the user is reading data. This causes the state machine +-- to continuosly receive a single byte at a time (1/3 bandwidth) until the FIFO is full, or until +-- the FIFO has been read by the user past the almost fill point and no data has been available on +-- the DPTI bus for a long time (~50 us). Need to fix this because it will lower bandwidth of designs that involve +-- continuously sending large amounts of data to the FPGA. +process (stPtiCur, stPtiNext, ctlRxf, ctlTxe, ctlFull, ctlAFull, ctlEmpty) +begin + case stPtiCur is + when stPtiRdy => + stPtiNext <= stPtiInOut0; + + when stPtiInOut0 => --Start any pending transactions + if ctlRxf = '0' and ctlFull = '0' then --Receive data from FTDI (gets priority) + stPtiNext <= stPtiInOut1; + elsif ctlTxe = '0' and ctlEmpty = '0' then --send data to FTDI + stPtiNext <= stPtiInOut3; + else --no transaction yet + stPtiNext <= stPtiInOut0; + end if; + + when stPtiInOut1 => --Initiate read transaction (FTDI->FPGA) + stPtiNext <= stPtiInOut2; + + when stPtiInOut2 => --Continue Read transaction + if ctlRxf = '0' and ctlAFull = '0' then + stPtiNext <= stPtiInOut2; + else --if no data available, or FPGA-side FIFO is almost full, stop transaction + stPtiNext <= stPtiInOut0; + end if; + + when stPtiInOut3 => --Start/Continue write transaction (FPGA->FTDI) + if ctlTxe = '0' and ctlEmpty = '0' then --note almost empty is used because the FIFO is first-word fall thru + stPtiNext <= stPtiInOut3; + else --if FTDI FIFO is full, or we are on the last byte being sent, stop transaction + stPtiNext <= stPtiInOut0; + end if; + + when others => + stPtiNext <= stPtiRdy; + end case; +end process; + +------------------------------------------------------------------------------- +-- Input/Output Fifos for data +------------------------------------------------------------------------------- + +--Output Fifo +usr2dpti_fifo : FIFO_DUALCLOCK_MACRO +generic map ( + DEVICE => "7SERIES", -- Target Device: "VIRTEX5", "VIRTEX6", "7SERIES" + ALMOST_FULL_OFFSET => X"0FF0", -- Sets almost full threshold + ALMOST_EMPTY_OFFSET => X"000F", -- Sets the almost empty threshold + DATA_WIDTH => 8, -- Valid values are 1-72 (37-72 only valid when FIFO_SIZE="36Kb") + FIFO_SIZE => "36Kb", -- Target BRAM, "18Kb" or "36Kb" + FIRST_WORD_FALL_THROUGH => TRUE) -- Sets the FIFO FWFT to TRUE or FALSE +port map ( + ALMOSTEMPTY => open, -- 1-bit output almost empty + ALMOSTFULL => usrAFull, -- 1-bit output almost full + DO => busPtiOut, -- Output data, width defined by DATA_WIDTH parameter + EMPTY => ctlEmpty, -- 1-bit output empty + FULL => usrFull, -- 1-bit output full + RDCOUNT => dummyRdCnt, -- Output read count, width determined by FIFO depth + RDERR => open, -- 1-bit output read error + WRCOUNT => usrWrCnt, -- Output write count, width determined by FIFO depth + WRERR => usrWrErr, -- 1-bit output write error + DI => usrDI, -- Input data, width defined by DATA_WIDTH parameter + RDCLK => clkPti, -- 1-bit input read clock + RDEN => ctlFrd, -- 1-bit input read enable + RST => ctlRst, -- 1-bit input reset + WRCLK => usrWrClk, -- 1-bit input write clock + WREN => usrWrEn -- 1-bit input write enable +); + +usrWrClk <= wr_clk; +usrWrEn <= wr_en; +wr_full <= usrFull; +wr_afull <= usrAFull; +wr_err <= usrWrErr; +wr_count <= usrWrCnt; +usrDI <= wr_di; + +--Input Fifo +dpti2usr_fifo : FIFO_DUALCLOCK_MACRO +generic map ( + DEVICE => "7SERIES", -- Target Device: "VIRTEX5", "VIRTEX6", "7SERIES" + ALMOST_FULL_OFFSET => X"0FF0", -- Sets almost full threshold + ALMOST_EMPTY_OFFSET => X"000F", -- Sets the almost empty threshold + DATA_WIDTH => 8, -- Valid values are 1-72 (37-72 only valid when FIFO_SIZE="36Kb") + FIFO_SIZE => "36Kb", -- Target BRAM, "18Kb" or "36Kb" + FIRST_WORD_FALL_THROUGH => TRUE) -- Sets the FIFO FWFT to TRUE or FALSE +port map ( + ALMOSTEMPTY => usrAEmpty, -- 1-bit output almost empty + ALMOSTFULL => ctlAFull, -- 1-bit output almost full + DO => usrDO, -- Output data, width defined by DATA_WIDTH parameter + EMPTY => usrEmpty, -- 1-bit output empty + FULL => ctlFull, -- 1-bit output full + RDCOUNT => usrRdCnt, -- Output read count, width determined by FIFO depth + RDERR => usrRdErr, -- 1-bit output read error + WRCOUNT => dummyWrCnt, -- Output write count, width determined by FIFO depth + WRERR => open, -- 1-bit output write error + DI => busPtiInReg, -- Input data, width defined by DATA_WIDTH parameter + RDCLK => usrRdClk, -- 1-bit input read clock + RDEN => usrRdEn, -- 1-bit input read enable + RST => ctlRst, -- 1-bit input reset + WRCLK => clkPti, -- 1-bit input write clock + WREN => ctlFwr -- 1-bit input write enable +); + +usrRdClk <= rd_clk; +usrRdEn <= rd_en; +rd_empty <= usrEmpty; +rd_aempty <= usrAEmpty; +rd_err <= usrRdErr; +rd_count <= usrRdCnt; +rd_do <= usrDO; + +end Behavioral; + diff --git a/corev_apu/instr_tracing/DPTI/slicer_DPTI.sv b/corev_apu/instr_tracing/DPTI/slicer_DPTI.sv new file mode 100644 index 0000000000..7a80687cc3 --- /dev/null +++ b/corev_apu/instr_tracing/DPTI/slicer_DPTI.sv @@ -0,0 +1,66 @@ +// Copyright (c) 2025 Thales DIS design services SAS +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// Author: Maxime Colson - Thales +// Date: 21/05/2025 +module slicer_DPTI #( + parameter SLICE_LEN = 32, + parameter NO_TIME = 0 // 0 : include time ; 1 : exclude time +) ( + input logic clk_i, + input logic rst_ni, + + input logic valid_i, + input encap_pkg::encap_fifo_entry_s encap_fifo_entry_i, + input logic fifo_full_i, + + output logic valid_o, + output logic [SLICE_LEN-1:0] slice_o, + output logic done_o +); + localparam DATA_LEN = encap_pkg::H_LEN + (NO_TIME ? 0 : encap_pkg::T_LEN) + encap_pkg::PAYLOAD_LEN; + localparam NUM_SLICES = DATA_LEN / SLICE_LEN; + localparam COUNT_LEN = $clog2(NUM_SLICES); + + logic [DATA_LEN-1 : 0] data_to_slice_q, data_to_slice_d; + logic [COUNT_LEN-1:0] slice_index_d, slice_index_q; + logic running_q, running_d; + + assign slice_o = data_to_slice_q[DATA_LEN-1:DATA_LEN-SLICE_LEN]; + assign valid_o = running_q && !fifo_full_i; + assign done_o = running_q && (slice_index_q == NUM_SLICES - 1) && !fifo_full_i; + + always_comb begin + data_to_slice_d = data_to_slice_q; + slice_index_d = slice_index_q; + running_d = running_q; + + if (valid_i && !running_q) begin + //new data to slice + data_to_slice_d = NO_TIME ? {encap_fifo_entry_i.header,encap_fifo_entry_i.payload} : + {encap_fifo_entry_i.header,encap_fifo_entry_i.timestamp,encap_fifo_entry_i.payload}; + slice_index_d = 0; + running_d = 1; + end else if (running_q && !fifo_full_i) begin // Stall if fifo is full + //Slicing + data_to_slice_d = data_to_slice_q << SLICE_LEN; + slice_index_d = slice_index_q + 1; + if (slice_index_q == NUM_SLICES - 1) begin + running_d = 0; + end + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + data_to_slice_q <= '0; + slice_index_q <= '0; + running_q <= '0; + end else begin + data_to_slice_q <= data_to_slice_d; + slice_index_q <= slice_index_d; + running_q <= running_d; + end + end + + +endmodule diff --git a/corev_apu/instr_tracing/Decapsuler/Decapsuler.cpp b/corev_apu/instr_tracing/Decapsuler/Decapsuler.cpp new file mode 100644 index 0000000000..fea1d5aba7 --- /dev/null +++ b/corev_apu/instr_tracing/Decapsuler/Decapsuler.cpp @@ -0,0 +1,311 @@ +// Copyright (c) 2025 Thales DIS design services SAS +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// Author: Maxime Colson - Thales +// Date: 17/06/2025 +// Contributors: +// Côme Allart - Thales + +// This code is designed to decapsulate a RAW format into a csv Trace. It is used to convert them in a human readable format for CI diff. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +const size_t NR_PKT = 20; +const size_t PACKET_SIZE = 40; +const size_t BLOCK_SIZE = NR_PKT * PACKET_SIZE; +typedef unsigned char BYTE; +using packet_t = std::array; +typedef std::array sample_t; + +uint64_t extract_bits(const packet_t &packet, std::size_t bit_offset, + std::size_t bit_length) { // FIXME add assertion to prevent desynchro segfault + uint64_t result = 0xdead; // We use 'dead' as an indicator to quickly detect if a desynchro happened during the aquisition (without stoping decapsulation) + if (bit_length <= 64) { + result = 0; + for (std::size_t i = 0; i < bit_length; ++i) { + std::size_t global_bit = bit_offset + i; + std::size_t byte_index = global_bit / 8; + std::size_t bit_index = 7 - (global_bit % 8); + uint64_t bit = (packet[byte_index] >> bit_index) & 0x1; + result = (result << 1) | bit; + } + } + return result; +} + +template struct PrintableOption : public std::optional { + PrintableOption(std::optional &o) : std::optional(o) {} + PrintableOption(T &v) : std::optional(v) {} + PrintableOption(uint64_t v) : std::optional(v) {} + PrintableOption() : std::optional() {} + + friend std::ostream &operator<<(std::ostream &s, const PrintableOption &o) { + if (o.has_value()) + s << unsigned(*o); + else + s << "_"; + + return s; + } +}; + +struct BitExtractor { + const packet_t &packet; + bool is_backward; + size_t i; + + BitExtractor(const packet_t &packet, bool backward) + : packet(packet), is_backward(backward), + i(backward ? PACKET_SIZE * 8 : 0) {} + + uint64_t operator()(size_t bits) { return extract(bits); } + uint64_t to(size_t bit) { return extract_to(bit); } + + uint64_t extract_to(size_t bit) { return extract(i - bit); } + uint64_t extract(size_t bits) { + if (is_backward) + i -= bits; + + uint64_t result = extract_bits(packet, i, bits); + + if (!is_backward) + i += bits; + + return result; + } +}; + +struct Trace { + bool P_Time; // MSB + uint8_t P_ID; // 2 bits after MSB + uint8_t P_Size; // 5bits after P_ID + uint64_t P_Timestamp; // 64 bits after P_Size + PrintableOption format; // 2bits LSB + PrintableOption subformat; // 2bits before LSB if format=3 + PrintableOption address; // start of payload + PrintableOption branch; // F3SF0 (5) F3SF1 (5) else NDF + PrintableOption branches; // F1 (3) + PrintableOption branch_map; // F1 (4 : branches) + PrintableOption branch_count; // NDF + PrintableOption branch_fmt; // NDF + PrintableOption context; // NDF + PrintableOption ecause; //F3SF1 (8) F3SF1T (70) + PrintableOption ienable; //F3SF3 (5) + PrintableOption encoder_mode;//F3SF3 (6) + PrintableOption interrupt; // F3SF1(9) F3SF1T(71) + PrintableOption irreport; // F2 (5) F1(5) + PrintableOption irdepth; //if call/ret F2(6:2^cal) F1(6:2^cal) else NDF + PrintableOption notify; // F2(3) F1(3) + PrintableOption ioptions; //F3SF3 (8:15) + PrintableOption privilege; // F3SF0 (6) F3SF1 (6) F3SF2 (5) + PrintableOption qual_status;// F3SF3(7) + PrintableOption time; //if time F3SF0(8:72) F3SF1(8:72) F3SF2(7:71) //FIXME encoder could have time in last position + PrintableOption thaddr; // F3SF1(40) F3SF1_t(104) + PrintableOption tval; //F3SF1 (41:73) F3SF1_t(105:137) + PrintableOption updiscon;// F2(4) + PrintableOption denable;// NDF here + PrintableOption dloss;// NDF here + PrintableOption doptions;// NDF here + uint8_t size_branch_map; + + Trace(const packet_t &packet, bool time_flag, bool call_flag) { + size_branch_map = 0; + + BitExtractor header_extractor(packet, false); + BitExtractor payload_extractor(packet, true); + + // Header of encapsulated packet : + P_Time = header_extractor(1); + P_ID = header_extractor(2); + P_Size = header_extractor(5); + size_t P_Start = (PACKET_SIZE - P_Size) * 8; + P_Timestamp = header_extractor(64); + + // Extraction of fields contained in the payload : + format = payload_extractor(2); + if (format == 3) { + subformat = payload_extractor(2); + } + + if (format == 3 && subformat.has_value()) { + switch (subformat.value()) { + case 0: { // F3SF0 + branch = payload_extractor(1); + privilege = payload_extractor(2); + if (time_flag) { + time = payload_extractor(64); + } + address = payload_extractor.to(P_Start); + break; + } + case 1: { // F3SF1 + branch = payload_extractor(1); + privilege = payload_extractor(2); + if (time_flag) { + time = payload_extractor(64); + } + ecause = payload_extractor(32); + interrupt = payload_extractor(1); + thaddr = payload_extractor(1); + tval = payload_extractor(32); + address = payload_extractor.to(P_Start); + break; + } + case 2: { // F3SF2 + privilege = payload_extractor(2); + if (time_flag) { + time = payload_extractor(64); + } + break; + } + case 3: { // F3SF3 + ienable = payload_extractor(1); + encoder_mode = payload_extractor(1); + qual_status = payload_extractor(2); + ioptions = payload_extractor(7); + break; + } + } + } + + // F2 + if (format == 2) { + notify = payload_extractor(1); + updiscon = payload_extractor(1); + irreport = payload_extractor(1); + if (call_flag) { // FIXME addapt to call_counter_size + irdepth = payload_extractor(1); // if = 0 else 2^call_counter_size + } + address = payload_extractor.to(P_Start); + } + + // F1 + if (format == 1) { + branches = payload_extractor(5); + if (branches == 0) { + size_branch_map = 31; + } else if (branches == 1) { + size_branch_map = 1; + } else if (branches <= 3) { + size_branch_map = 3; + } else if (branches <= 7) { + size_branch_map = 7; + } else if (branches <= 15) { + size_branch_map = 15; + } else { + size_branch_map = 31; + } + branch_map = payload_extractor(size_branch_map); + + if (branches != 0) { + notify = payload_extractor(1); + updiscon = payload_extractor(1); + irreport = payload_extractor(1); + if (call_flag) { // FIXME addapt to call_counter_size + irdepth = payload_extractor(1); // if = 0 else 2^call_counter_size + } + address = payload_extractor.to(P_Start); + } + } + } + + static std::string csvHeader() { + return std::string( + "format,subformat,address,branch,branches,branch_map,branch_count," + "branch_fmt,context,ecause,ienable,encoder_mode,interrupt,irreport," + "irdepth,notify,ioptions,privilege,qual_status,time,thaddr,tval," + "updiscon,denable,dloss,doptions"); + } + + friend std::ostream &operator<<(std::ostream &s, Trace const &trace) { + trace.put_str(s); + return s; + } + + std::ostream &put_str(std::ostream &s) const { + s << format << "," << subformat << ","; + + s << std::hex << std::nouppercase << address << std::dec << ","; + + s << branch << "," << branches << "," << branch_map << "," << branch_count + << "," << branch_fmt << ","; + + s << context << "," << ecause << "," << ienable << "," << encoder_mode + << "," << interrupt << ","; + + s << irreport << "," << irdepth << "," << notify << "," << ioptions << "," + << privilege << "," << qual_status << ","; + + s << std::hex << std::nouppercase << time << std::dec << ","; + + s << thaddr << "," << tval << "," << updiscon << "," << denable << "," + << dloss << "," << doptions; + + return s; + } + + std::string toCSVLine() { + std::ostringstream oss; + oss << *this; + return oss.str(); + } +}; + + packet_t hexstr_to_packet(const std::string &hexstr){ + unsigned int byte; + packet_t packet; + for (int i=0; i< 40; i++){ + std::sscanf(hexstr.c_str() + 2*i, "%2x",&byte); + packet[i] = (BYTE) byte; + } + return packet; + } + + std::filesystem::path ext_csv(const std::filesystem::path &pi) { + auto po = pi ; + po.replace_extension(".csv"); + return po; + } + +int main(int argc, char* argv[]) { + if (argc <2){ + std::cerr << "Usage: "<< argv[0] <<" Filepath \n"; + return 1; + } + + const bool TIME_FLAG = 1; + const bool CALL_FLAG = 0; + std::filesystem::path nameFile_i = argv[1]; + std::filesystem::path nameFile_o = ext_csv(nameFile_i); + + std::vector all_packets; + std::ifstream file_to_extract(nameFile_i); + std::ofstream csvFile(nameFile_o); + std::string line; + + while(std::getline(file_to_extract,line)){ + packet_t packet; + packet=hexstr_to_packet(line); + all_packets.push_back(packet); + } + + std::cout << "Number packet read :" << all_packets.size() << std::endl; + csvFile << Trace::csvHeader() << "\n"; + for (packet_t &packet : all_packets){ + Trace trace(packet, TIME_FLAG, CALL_FLAG); + csvFile << trace.toCSVLine() << "\n"; + } + + return 0; +} \ No newline at end of file diff --git a/corev_apu/instr_tracing/Decapsuler/Makefile b/corev_apu/instr_tracing/Decapsuler/Makefile new file mode 100644 index 0000000000..5de6887a2a --- /dev/null +++ b/corev_apu/instr_tracing/Decapsuler/Makefile @@ -0,0 +1,29 @@ +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales + +# Makefile to build the Decapsuler executable + +CC = $(GCC_11_5_PATH)/g++ +TARGETS = Decapsuler +CFLAGS = -Wall -Wextra -g + +all: $(TARGETS) + +Decapsuler: Decapsuler.cpp + $(CC) --version + $(CC) -o Decapsuler Decapsuler.cpp $(CFLAGS) + +.PHONY: clean + +clean: + rm -f $(TARGETS) + +clean_all: + rm -f $(TARGETS) + rm -rf receiver_data diff --git a/corev_apu/instr_tracing/Decapsuler/affiche_csv.py b/corev_apu/instr_tracing/Decapsuler/affiche_csv.py new file mode 100644 index 0000000000..5d29ce00f2 --- /dev/null +++ b/corev_apu/instr_tracing/Decapsuler/affiche_csv.py @@ -0,0 +1,34 @@ +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales +# Script used to print a csv file in a more readable way +import pandas as pd +import argparse +import os + +pd.set_option('display.max_columns',None) +pd.set_option('display.max_rows',None) +pd.set_option("display.width",220) + +parser = argparse.ArgumentParser(description="Print the CSV file in a more readable format") +parser.add_argument("--file","-f",required=True, help="CSV file path") +args = parser.parse_args() + +csv_path = args.file + +if not os.path.isfile(csv_path): + print(f"Error '{csv_path}' does not exist") + exit(1) + +df = pd.read_csv(csv_path) + +#print(df) + +output_filename = os.path.splitext(os.path.basename(csv_path))[0] + "_output.txt" +with open(output_filename, "w",encoding="utf-8") as f: + f.write(df.to_string(index=False)) \ No newline at end of file diff --git a/corev_apu/instr_tracing/Decapsuler/compare_encoder.sh b/corev_apu/instr_tracing/Decapsuler/compare_encoder.sh new file mode 100755 index 0000000000..823ba3408d --- /dev/null +++ b/corev_apu/instr_tracing/Decapsuler/compare_encoder.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales + +set -euo pipefail + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 " + exit 2 +fi + +dir_work="encoder_log" +rm -rf "$dir_work" +mkdir -p "$dir_work" + +trace_raw_path="$1" +trace_ref_path="$2" + + +base_raw=$(basename "$trace_raw_path") +base_ref=$(basename "$trace_ref_path") + + +for trace in "$trace_raw_path" "$trace_ref_path"; do + if [ ! -f "$trace" ]; then + echo "ERROR file '$trace' does not exist" + exit 1 + fi + base=$(basename "$trace") + cp "$trace" "$dir_work/$base" +done + +trace_raw="$dir_work/$base_raw" +trace_ref="$dir_work/$base_ref" + +./Decapsuler "$trace_raw" + +python3 affiche_csv.py -f "$dir_work/${base_raw%.txt}.csv" +mv "${base_raw%.txt}_output.txt" "$dir_work" +python3 affiche_csv.py -f "$trace_ref" +mv "${base_ref%.te_inst}_output.txt" "$dir_work" + + +python3 diff_color.py "$dir_work/${base_raw%.txt}.csv" "$trace_ref" + + \ No newline at end of file diff --git a/corev_apu/instr_tracing/Decapsuler/debug_encoder_diff.sh b/corev_apu/instr_tracing/Decapsuler/debug_encoder_diff.sh new file mode 100644 index 0000000000..85afb5745b --- /dev/null +++ b/corev_apu/instr_tracing/Decapsuler/debug_encoder_diff.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales + +exit_error() { + echo "$1" >&2 + exit ${2:-1} +} + +if [ "$#" -ne 1 ]; then + exit_error "Usage: $0 " 2 +fi + +exe="$1" +base=$(basename "$exe" .o) + +#TODO \ No newline at end of file diff --git a/corev_apu/instr_tracing/Decapsuler/diff_color.py b/corev_apu/instr_tracing/Decapsuler/diff_color.py new file mode 100644 index 0000000000..be107c9974 --- /dev/null +++ b/corev_apu/instr_tracing/Decapsuler/diff_color.py @@ -0,0 +1,104 @@ +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales + + +import csv +import sys +import re + +def gray(s): return f"\033[90m{s}\033[0m" +def red(s): return f"\033[91m{s}\033[0m" +def green(s): return f"\033[92m{s}\033[0m" +def white(s): return f"\033[97m{s}\033[0m" + +ANSI_ESCAPE= re.compile + +def strip(text): + return re.sub(r'\x1b\[[0-9;]*m','',text) + +def read_csv_to_matrix(filepath): + with open(filepath,newline='') as csvfile: + reader = csv.reader(csvfile,delimiter=',') + rows = list(reader) + header = rows[0] + data = rows[1:] + return header,data + + + +def format_value(val_gen, val_ref): + if val_gen is None: + return f"{red('NDF')}{white(' -> ')}{green(val_ref)}" + elif val_gen == val_ref: + return gray(val_gen) + else: + return f"{red(val_gen)}{white(' -> ')}{green(val_ref)}" + +def compare_matrices(header,gen_data,ref_data): + max_rows = max(len(gen_data),len(ref_data)) + num_cols = len(header) + result_matrix = [[None for _ in range (num_cols)] for _ in range(max_rows)] + + for row_idx in range(max_rows): + for col_idx in range(num_cols): + try: + val_ref = ref_data[row_idx][col_idx] + except IndexError: + val_ref="" + try: + val_gen = gen_data[row_idx][col_idx] + except IndexError: + val_gen=None + result_matrix[row_idx][col_idx] = format_value(val_gen,val_ref) + + return result_matrix + +def print_column_by_column(header,matrix,cols_per_block=8): + num_cols = len(header) + num_rows = len(matrix) + + for block_start in range(0,num_cols, cols_per_block): + block_end = min(block_start + cols_per_block,num_cols) + block_indices = range(block_start,block_end) + + col_widths =[] + for i in block_indices: + max_len = max(len(strip(matrix[r][i])) for r in range(num_rows)) + max_len = max(max_len, len(header[i])) + col_widths.append(max_len + 2) + header_line ="" + for i,w in zip(block_indices,col_widths): + header_line += header[i].center(w) + " " + print(header_line) + + for r in range(num_rows): + row_line = "" + for i,w in zip(block_indices,col_widths): + content = matrix[r][i] + pad_len = w - len(strip(content)) + left_pad = pad_len // 2 + right_pad = pad_len - left_pad + row_line += " "*left_pad + content + " "*right_pad + " " + print(row_line) + + print("\n") + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("usage : diff.py ") + sys.exit(1) + + gen_path = sys.argv[1] + ref_path = sys.argv[2] + + gen_header, gen_data = read_csv_to_matrix(gen_path) + ref_header , ref_data = read_csv_to_matrix(ref_path) + + matrix = compare_matrices(ref_header,gen_data,ref_data) + print_column_by_column(ref_header,matrix,cols_per_block=14) diff --git a/core/cva6_iti/instr_to_trace.sv b/corev_apu/instr_tracing/ITI/cva6_iti/block_retirement.sv similarity index 94% rename from core/cva6_iti/instr_to_trace.sv rename to corev_apu/instr_tracing/ITI/cva6_iti/block_retirement.sv index 6542c060a8..aaa2e0d115 100644 --- a/core/cva6_iti/instr_to_trace.sv +++ b/corev_apu/instr_tracing/ITI/cva6_iti/block_retirement.sv @@ -9,7 +9,7 @@ //Systolic module used to determines the iaddr, ilastsize, iretire for Encoder Module -module instr_to_trace #( +module block_retirement #( parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, parameter type uop_entry_t = logic, parameter type itt_out_t = logic, @@ -44,7 +44,6 @@ module instr_to_trace #( itt_out_o = '0; if (uop_entry_i.valid) begin - counter_o = uop_entry_i.compressed ? counter_i + 1 : counter_i + 2; if (was_special_i) begin counter_o = 0; @@ -52,9 +51,11 @@ module instr_to_trace #( is_special_o = 1'b0; end + counter_o = uop_entry_i.compressed ? counter_o + 1 : counter_o + 2; + if (special_inst) begin itt_out_o.valid = 1'b1; - itt_out_o.iretire = uop_entry_i.compressed ? counter_o + 1 : counter_o + 2; + itt_out_o.iretire = counter_o; itt_out_o.itype = uop_entry_i.itype; itt_out_o.ilastsize = ~uop_entry_i.compressed; itt_out_o.iaddr = iaddr_o; diff --git a/core/cva6_iti/iti.sv b/corev_apu/instr_tracing/ITI/cva6_iti/iti.sv similarity index 67% rename from core/cva6_iti/iti.sv rename to corev_apu/instr_tracing/ITI/cva6_iti/iti.sv index ce45c61998..83c8bf4abf 100644 --- a/core/cva6_iti/iti.sv +++ b/corev_apu/instr_tracing/ITI/cva6_iti/iti.sv @@ -14,6 +14,7 @@ module cva6_iti #( parameter CAUSE_LEN = 5, //Size is ecause_width_p in the E-Trace SPEC parameter ITYPE_LEN = 3, //Size is itype_width_p in the E-Trace SPEC (3 or 4) parameter IRETIRE_LEN = 32, //Size is iretire_width_p in the E-Trace SPEC + parameter block_mode = 0, parameter type rvfi_to_iti_t = logic, parameter type iti_to_encoder_t = logic ) ( @@ -30,7 +31,8 @@ module cva6_iti #( // pragma translate_off int f; initial begin - f = $fopen("iti.trace", "w"); + f = $fopen("iti.traces", "w"); + $fwrite(f, "itype_0,cause,tval,priv,iaddr_0,context,ctype,iretire_0,ilastsize_0\n"); end final $fclose(f); // pragma translate_on @@ -95,37 +97,58 @@ module cva6_iti #( // Adding this to ensure that interrupt/exception happen only in commit port 0 of cva6 assign cause_itt[i] = i == 0 ? rvfi_to_iti_i.cause[CAUSE_LEN-1:0] : '0; - assign tval_itt[i] = i == 0 ? rvfi_to_iti_i.tval : '0; - // Systolic logic (First itt is connected to D Flip-Flop to continue computation if needed) - assign counter_itt[i] = i == 0 ? counter_q : counter[i-1]; - assign addr_itt[i] = i == 0 ? addr_q : addr[i-1]; - assign special_itt[i] = i == 0 ? special_q : special[i-1]; - - instr_to_trace #( - .CVA6Cfg(CVA6Cfg), - .uop_entry_t(uop_entry_t), - .itt_out_t(itt_out_t), - .CAUSE_LEN(CAUSE_LEN), - .ITYPE_LEN(ITYPE_LEN), - .IRETIRE_LEN(IRETIRE_LEN) - ) i_instr_to_trace ( - .uop_entry_i(uop_entry[i]), - .cause_i(cause_itt[i]), - .tval_i(tval_itt[i]), - .counter_i(counter_itt[i]), - .iaddr_i(addr_itt[i]), - .was_special_i(special_itt[i]), - .itt_out_o(itt_out[i]), - .counter_o(counter[i]), - .iaddr_o(addr[i]), - .is_special_o(special[i]) - ); + assign tval_itt[i] = i == 0 ? rvfi_to_iti_i.tval : '0; + + if (block_mode) begin + // Systolic logic (First block_retirement is connected to D Flip-Flop to continue computation if needed) + assign counter_itt[i] = i == 0 ? counter_q : counter[i-1]; + assign addr_itt[i] = i == 0 ? addr_q : addr[i-1]; + assign special_itt[i] = i == 0 ? special_q : special[i-1]; + + block_retirement #( + .CVA6Cfg(CVA6Cfg), + .uop_entry_t(uop_entry_t), + .itt_out_t(itt_out_t), + .CAUSE_LEN(CAUSE_LEN), + .ITYPE_LEN(ITYPE_LEN), + .IRETIRE_LEN(IRETIRE_LEN) + ) i_block_retirement ( + .uop_entry_i(uop_entry[i]), + .cause_i(cause_itt[i]), + .tval_i(tval_itt[i]), + .counter_i(counter_itt[i]), + .iaddr_i(addr_itt[i]), + .was_special_i(special_itt[i]), + .itt_out_o(itt_out[i]), + .counter_o(counter[i]), + .iaddr_o(addr[i]), + .is_special_o(special[i]) + ); + + end else begin + single_retirement #( + .CVA6Cfg(CVA6Cfg), + .uop_entry_t(uop_entry_t), + .itt_out_t(itt_out_t), + .CAUSE_LEN(CAUSE_LEN), + .ITYPE_LEN(ITYPE_LEN), + .IRETIRE_LEN(IRETIRE_LEN) + ) i_single_retirement ( + .uop_entry_i(uop_entry[i]), + .cause_i(cause_itt[i]), + .tval_i(tval_itt[i]), + .itt_out_o(itt_out[i]) + ); + + end end always_comb begin - iti_to_encoder_o.cause = '0; - iti_to_encoder_o.tval = '0; + iti_to_encoder_o.cause = '0; + iti_to_encoder_o.tval = '0; + iti_to_encoder_o.priv = riscv::PRIV_LVL_U; + iti_to_encoder_o.cycles = '0; for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin uop_entry[i].valid = valid_i[i]; uop_entry[i].pc = rvfi_to_iti_i.pc[i]; @@ -137,8 +160,9 @@ module cva6_iti #( iti_to_encoder_o.valid[i] = 1'b0; iti_to_encoder_o.iretire[i] = '0; iti_to_encoder_o.ilastsize[i] = '0; - iti_to_encoder_o.itype[i] = '0; + iti_to_encoder_o.itype[i] = iti_pkg::STANDARD; iti_to_encoder_o.iaddr[i] = '0; + valid_o[i] = '0; if (itt_out[i].valid) begin valid_o[i] = itt_out[i].valid; iti_to_encoder_o.valid[i] = itt_out[i].valid; @@ -155,29 +179,30 @@ module cva6_iti #( iti_to_encoder_o.tval = itt_out[0].tval; end end - - assign counter_d = counter[CVA6Cfg.NrCommitPorts-1]; - assign addr_d = addr[CVA6Cfg.NrCommitPorts-1]; - assign special_d = special[CVA6Cfg.NrCommitPorts-1]; + if (block_mode) begin + assign counter_d = counter[CVA6Cfg.NrCommitPorts-1]; + assign addr_d = addr[CVA6Cfg.NrCommitPorts-1]; + assign special_d = special[CVA6Cfg.NrCommitPorts-1]; + end always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) begin - counter_q <= '0; - addr_q <= '0; - special_q <= 1'b1; - end else begin - counter_q <= counter_d; - addr_q <= addr_d; - special_q <= special_d; + if (block_mode) begin + if (!rst_ni) begin + counter_q <= '0; + addr_q <= '0; + special_q <= 1'b1; + end else begin + counter_q <= counter_d; + addr_q <= addr_d; + special_q <= special_d; + end end //pragma translate_off for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin if (itt_out[i].valid) begin - $fwrite( - f, - "i :%d , val = %d , iret = %d, ilast = 0x%d , itype = %d , cause = 0x%h , tval= 0x%h , priv = 0x%d , iadd= 0x%h \n", - i, itt_out[i].valid, itt_out[i].iretire, itt_out[i].ilastsize, itt_out[i].itype, - itt_out[i].cause, itt_out[i].tval, itt_out[i].priv, itt_out[i].iaddr); + $fwrite(f, "%d,%0d,%0d,%d,%h,0,0,%0d,%0d\n", itt_out[i].itype, itt_out[i].cause, + itt_out[i].tval, itt_out[i].priv, itt_out[i].iaddr, itt_out[i].iretire, + itt_out[i].ilastsize); end end //pragma translate_on diff --git a/core/cva6_iti/itype_detector.sv b/corev_apu/instr_tracing/ITI/cva6_iti/itype_detector.sv similarity index 100% rename from core/cva6_iti/itype_detector.sv rename to corev_apu/instr_tracing/ITI/cva6_iti/itype_detector.sv diff --git a/corev_apu/instr_tracing/ITI/cva6_iti/single_retirement.sv b/corev_apu/instr_tracing/ITI/cva6_iti/single_retirement.sv new file mode 100644 index 0000000000..a9d4a668be --- /dev/null +++ b/corev_apu/instr_tracing/ITI/cva6_iti/single_retirement.sv @@ -0,0 +1,56 @@ +// Copyright (c) 2025 Thales DIS design services SAS +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// Author: Maxime Colson - Thales +// Date: 20/03/2025 + +//Module used to determines the iaddr, ilastsize, iretire in single retirement for Encoder Module + + +module single_retirement #( + parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, + parameter type uop_entry_t = logic, + parameter type itt_out_t = logic, + parameter CAUSE_LEN = 5, //Size is ecause_width_p in the E-Trace SPEC + parameter ITYPE_LEN = 3, //Size is itype_width_p in the E-Trace SPEC (3 or 4) + parameter IRETIRE_LEN = 32 //Size is iretire_width_p in the E-Trace SPEC +) ( + input uop_entry_t uop_entry_i, + input logic [ CAUSE_LEN-1:0] cause_i, + input logic [CVA6Cfg.XLEN-1:0] tval_i, + output itt_out_t itt_out_o +); + + + logic exception; + logic interrupt; + assign exception = (uop_entry_i.itype == iti_pkg::EXC) ? 1'b1 : 1'b0; + assign interrupt = (uop_entry_i.itype == iti_pkg::INT) ? 1'b1 : 1'b0; + + always_comb begin + itt_out_o = '0; + + if (uop_entry_i.valid) begin + + itt_out_o.valid = 1'b1; + itt_out_o.iretire = 1; + itt_out_o.itype = uop_entry_i.itype; + itt_out_o.ilastsize = ~uop_entry_i.compressed; + itt_out_o.iaddr = uop_entry_i.pc; + itt_out_o.priv = uop_entry_i.priv; + itt_out_o.cycles = uop_entry_i.cycles; + itt_out_o.cause = '0; + itt_out_o.tval = '0; + + if (interrupt) begin + itt_out_o.cause = cause_i; + itt_out_o.tval = '0; + end + + if (exception) begin + itt_out_o.cause = cause_i; + itt_out_o.tval = tval_i; + end + + end + end +endmodule diff --git a/core/include/iti_pkg.sv b/corev_apu/instr_tracing/ITI/include/iti_pkg.sv similarity index 100% rename from core/include/iti_pkg.sv rename to corev_apu/instr_tracing/ITI/include/iti_pkg.sv diff --git a/core/include/iti_types.svh b/corev_apu/instr_tracing/ITI/include/iti_types.svh similarity index 90% rename from core/include/iti_types.svh rename to corev_apu/instr_tracing/ITI/include/iti_types.svh index d18a604e5b..d8519ee996 100644 --- a/core/include/iti_types.svh +++ b/corev_apu/instr_tracing/ITI/include/iti_types.svh @@ -13,7 +13,7 @@ logic [Cfg.NrCommitPorts-1:0] valid; \ logic [Cfg.NrCommitPorts-1:0][iti_pkg::IRETIRE_LEN-1:0] iretire; \ logic [Cfg.NrCommitPorts-1:0] ilastsize; \ - iti_pkg::itype_t [Cfg.NrCommitPorts-1:0][iti_pkg::ITYPE_LEN-1:0] itype; \ + iti_pkg::itype_t [Cfg.NrCommitPorts-1:0] itype; \ logic [iti_pkg::CAUSE_LEN-1:0] cause; \ logic [Cfg.XLEN-1:0] tval; \ riscv::priv_lvl_t priv; \ diff --git a/corev_apu/instr_tracing/Pictures/Branch_example_dark.svg b/corev_apu/instr_tracing/Pictures/Branch_example_dark.svg new file mode 100644 index 0000000000..eb3a61cea7 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Branch_example_dark.svg @@ -0,0 +1,3 @@ + + +
0000000080001100 <Proc_6>  :
.... ... 
  80001112: c080 {sw s0,0(s1)}
  80001114: 4785 {li a5,1}
  80001116: 02f40463 {beq s0,a5,8000113e }
8000111a:      c81d {beqz s0,80001150 }
> Not Taken ; branches = 1(10)  branche_map = 1(2)
 Not Taken ; branches = 2(10)  branche_map = 11(2)
 8000111c: 4709 {li a4,2}
 8000111e: 04e40063 {beq s0,a4,8000115e }
> Taken ; branches = 3(10)  branche_map = 011(2)
8000115e: 60e2 {ld ra,24(sp)}
80001160: 6442 {ld s0,16(sp)}
80001162: c09c {sw a5,0(s1)}
80001164: 64a2 {ld s1,8(sp)}
80001166: 6105 {addi sp,sp,32}
80001168: 8082 {ret}
> Uninferable ; packet is sent with : branches = 3(10)  branche_map = 011(2)
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Branch_example_light.svg b/corev_apu/instr_tracing/Pictures/Branch_example_light.svg new file mode 100644 index 0000000000..329d0d46c0 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Branch_example_light.svg @@ -0,0 +1,3 @@ + + +
0000000080001100 <Proc_6>  :
.... ... 
  80001112: c080 {sw s0,0(s1)}
  80001114: 4785 {li a5,1}
  80001116: 02f40463 {beq s0,a5,8000113e }
8000111a:      c81d {beqz s0,80001150 }
> Not Taken ; branches = 1(10)  branche_map = 1(2)
 Not Taken ; branches = 2(10)  branche_map = 11(2)
 8000111c: 4709 {li a4,2}
 8000111e: 04e40063 {beq s0,a4,8000115e }
> Taken ; branches = 3(10)  branche_map = 011(2)
8000115e: 60e2 {ld ra,24(sp)}
80001160: 6442 {ld s0,16(sp)}
80001162: c09c {sw a5,0(s1)}
80001164: 64a2 {ld s1,8(sp)}
80001166: 6105 {addi sp,sp,32}
80001168: 8082 {ret}
> Uninferable ; packet is sent with : branches = 3(10)  branche_map = 011(2)
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Branch_map_dark.svg b/corev_apu/instr_tracing/Pictures/Branch_map_dark.svg new file mode 100644 index 0000000000..167a10467e --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Branch_map_dark.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid
empty
Branch
Map
flush
branch_taken
branch_map
branches
full
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Branch_map_light.svg b/corev_apu/instr_tracing/Pictures/Branch_map_light.svg new file mode 100644 index 0000000000..8b440e73ca --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Branch_map_light.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid
empty
Branch
Map
flush
branch_taken
branch_map
branches
full
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/EEPROM.PNG b/corev_apu/instr_tracing/Pictures/EEPROM.PNG new file mode 100644 index 0000000000..5aa9091488 Binary files /dev/null and b/corev_apu/instr_tracing/Pictures/EEPROM.PNG differ diff --git a/corev_apu/instr_tracing/Pictures/Emmiter_dark.svg b/corev_apu/instr_tracing/Pictures/Emmiter_dark.svg new file mode 100644 index 0000000000..06c13f0817 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Emmiter_dark.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid
packet_valid_o
packet_length_o
Packet
Emmiter
lc_cause
lc_tval
lc_interrupt
tc_cause
tc_tval
tc_interrupt
tc_priv
tc_time
tc_address
branches
branch_map
nc_exc_only
nc_ppccd
tc_ienable
lc_updiscon
packet_payload_o
branch_map_flush
nocontext
notime
qual_status
ioptions
packet_format
packet_subformat
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Emmiter_light.svg b/corev_apu/instr_tracing/Pictures/Emmiter_light.svg new file mode 100644 index 0000000000..987de87216 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Emmiter_light.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid
packet_valid_o
packet_length_o
Packet
Emmiter
lc_cause
lc_tval
lc_interrupt
tc_cause
tc_tval
tc_interrupt
tc_priv
tc_time
tc_address
branches
branch_map
nc_exc_only
nc_ppccd
tc_ienable
lc_updiscon
packet_payload_o
branch_map_flush
nocontext
notime
qual_status
ioptions
packet_format
packet_subformat
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Encapsulated_Packet_dark.svg b/corev_apu/instr_tracing/Pictures/Encapsulated_Packet_dark.svg new file mode 100644 index 0000000000..0822cb05b0 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Encapsulated_Packet_dark.svg @@ -0,0 +1,3 @@ + + +
Header
Time
Payload
1 Byte
8 Bytes
1    31 Bytes
P_Length
flow
T?
1 bit
2 bits
5 bits
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Encapsulated_Packet_light.svg b/corev_apu/instr_tracing/Pictures/Encapsulated_Packet_light.svg new file mode 100644 index 0000000000..fa085eceb7 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Encapsulated_Packet_light.svg @@ -0,0 +1,3 @@ + + +
Header
Time
Payload
1 Byte
8 Bytes
1    31 Bytes
P_Length
flow
T?
1 bit
2 bits
5 bits
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Encoder_dark.svg b/corev_apu/instr_tracing/Pictures/Encoder_dark.svg new file mode 100644 index 0000000000..489d9ddc87 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Encoder_dark.svg @@ -0,0 +1,3 @@ + + +
Control
Register
Filter
Priority
Resync
Packet
Emmiter
APB
Branch
map
iti_to_encoder 
iretire [N:0][IRET_LEN-1:0];
ilastsize[N:0];
itype [N:0][2:0];
cause [XLEN-1:0];
tval [XLEN-1:0];
priv [1:0];
iaddr [N:0][XLEN-1:0];
cycles [63:0];
valid_i
packet_valid_o
packet_length_o
packet_payload_o
ENCODER
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Encoder_light.svg b/corev_apu/instr_tracing/Pictures/Encoder_light.svg new file mode 100644 index 0000000000..edb997026f --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Encoder_light.svg @@ -0,0 +1,3 @@ + + +
Control
Register
Filter
Priority
Resync
Packet
Emmiter
APB
Branch
map
iti_to_encoder 
iretire [N:0][IRET_LEN-1:0];
ilastsize[N:0];
itype [N:0][2:0];
cause [XLEN-1:0];
tval [XLEN-1:0];
priv [1:0];
iaddr [N:0][XLEN-1:0];
cycles [63:0];
valid_i
packet_valid_o
packet_length_o
packet_payload_o
ENCODER
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Filter_dark.svg b/corev_apu/instr_tracing/Pictures/Filter_dark.svg new file mode 100644 index 0000000000..db6c3f763e --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Filter_dark.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid
nc_qualified
Filter
Other 
Events
priv_filter
upper_priv
lower_priv
match_priv
priv_mode
priv_lvl_i
iaddr_filter
upper_iaddr
match_iaddr
iaddr_mode
iaddr_i
lower_iaddr
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Filter_light.svg b/corev_apu/instr_tracing/Pictures/Filter_light.svg new file mode 100644 index 0000000000..2e04cf1a26 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Filter_light.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid
nc_qualified
Filter
Other 
Events
priv_filter
upper_priv
lower_priv
match_priv
priv_mode
priv_lvl_i
iaddr_filter
upper_iaddr
match_iaddr
iaddr_mode
iaddr_i
lower_iaddr
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Gen2_wired.png b/corev_apu/instr_tracing/Pictures/Gen2_wired.png new file mode 100644 index 0000000000..fead93f9fb Binary files /dev/null and b/corev_apu/instr_tracing/Pictures/Gen2_wired.png differ diff --git a/corev_apu/instr_tracing/Pictures/ITI_diagram_dark.svg b/corev_apu/instr_tracing/Pictures/ITI_diagram_dark.svg new file mode 100644 index 0000000000..c0d441c077 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/ITI_diagram_dark.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid_i [N:0]
rvfi_to_iti [N:0] * 
valid_o [N:0]
iti_to_encoder [N:0] * 
ITI
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/ITI_diagram_detailed_dark.svg b/corev_apu/instr_tracing/Pictures/ITI_diagram_detailed_dark.svg new file mode 100644 index 0000000000..3c3b1b6e95 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/ITI_diagram_detailed_dark.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid_i [N:0]
rvfi_to_iti 
valid_o [N:0]
iti_to_encoder 
pc [N:0][XLEN-1:0];
op [N:0][7:0];
is_compressed [N:0];
branch_valid [N:0];
is_taken [N:0];
ex_valid ;
tval [XLEN-1:0];
cause [XLEN-1:0];
priv_Ivl [1:0];
cycles [63:0];
iretire[N:0][IRET_LEN-1:0];
ilastsize[N:0];
itype [N:0][2:0];
cause [XLEN-1:0];
tval [XLEN-1:0];
priv [1:0];
iaddr [N:0][XLEN-1:0];
cycles [63:0];
ITI
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/ITI_diagram_detailed_light.svg b/corev_apu/instr_tracing/Pictures/ITI_diagram_detailed_light.svg new file mode 100644 index 0000000000..677f5ee169 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/ITI_diagram_detailed_light.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid_i [N:0]
rvfi_to_iti 
valid_o [N:0]
iti_to_encoder 
pc [N:0][XLEN-1:0];
op [N:0][7:0];
is_compressed [N:0];
branch_valid [N:0];
is_taken [N:0];
ex_valid ;
tval [XLEN-1:0];
cause [XLEN-1:0];
priv_Ivl [1:0];
cycles [63:0];
iretire[N:0][IRET_LEN-1:0];
ilastsize[N:0];
itype [N:0][2:0];
cause [XLEN-1:0];
tval [XLEN-1:0];
priv [1:0];
iaddr [N:0][XLEN-1:0];
cycles [63:0];
ITI
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_block_mode_dark.svg b/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_block_mode_dark.svg new file mode 100644 index 0000000000..5e7c938e20 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_block_mode_dark.svg @@ -0,0 +1,3 @@ + + +
itype_detector
itype_detector
itype_detector
itype
clk
rst
valid_i [N:0]
rvfi_to_iti [0]
rvfi_to_iti [1]
rvfi_to_iti [N]
valid_o [N:0]
iti_to_encoder [0]
iti_to_encoder [1]
iti_to_encoder [N]
ITI multiple retirement mode (block) 
Block
Retirement
Block
Retirement
Block
Retirement
special
iret
addr
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_block_mode_light.svg b/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_block_mode_light.svg new file mode 100644 index 0000000000..a543bf353f --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_block_mode_light.svg @@ -0,0 +1,3 @@ + + +
itype_detector
itype_detector
itype_detector
itype
clk
rst
valid_i [N:0]
rvfi_to_iti [0]
rvfi_to_iti [1]
rvfi_to_iti [N]
valid_o [N:0]
iti_to_encoder [0]
iti_to_encoder [1]
iti_to_encoder [N]
ITI multiple retirement mode (block) 
Block
Retirement
Block
Retirement
Block
Retirement
special
iret
addr
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_single_mode_dark.svg b/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_single_mode_dark.svg new file mode 100644 index 0000000000..0aca033e7c --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_single_mode_dark.svg @@ -0,0 +1,3 @@ + + +
Single 
Retirement
Single 
Retirement
Single 
Retirement
itype_detector
itype_detector
itype_detector
itype
clk
rst
valid_i [N:0]
rvfi_to_iti [0]
rvfi_to_iti [1]
rvfi_to_iti [N]
valid_o [N:0]
iti_to_encoder [0]
iti_to_encoder [1]
iti_to_encoder [N]
ITI single retirement mode 
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_single_mode_light.svg b/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_single_mode_light.svg new file mode 100644 index 0000000000..ed16f45d69 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/ITI_diagram_inside_single_mode_light.svg @@ -0,0 +1,3 @@ + + +
Single 
Retirement
Single 
Retirement
Single 
Retirement
itype_detector
itype_detector
itype_detector
itype
clk
rst
valid_i [N:0]
rvfi_to_iti [0]
rvfi_to_iti [1]
rvfi_to_iti [N]
valid_o [N:0]
iti_to_encoder [0]
iti_to_encoder [1]
iti_to_encoder [N]
ITI single retirement mode 
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/ITI_diagram_light.svg b/corev_apu/instr_tracing/Pictures/ITI_diagram_light.svg new file mode 100644 index 0000000000..00f0773da3 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/ITI_diagram_light.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid_i [N:0]
rvfi_to_iti [N:0] * 
valid_o [N:0]
iti_to_encoder [N:0] * 
ITI
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/JA_dark.svg b/corev_apu/instr_tracing/Pictures/JA_dark.svg new file mode 100644 index 0000000000..407ef39bf9 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/JA_dark.svg @@ -0,0 +1,3 @@ + + +
VDD
GND
VDD
GND
rxen
rdn
wrn
txen
oen
clko
spien
siwun
PMOD JA
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/JA_light.svg b/corev_apu/instr_tracing/Pictures/JA_light.svg new file mode 100644 index 0000000000..2242b11d9a --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/JA_light.svg @@ -0,0 +1,3 @@ + + +
VDD
GND
VDD
GND
rxen
rdn
wrn
txen
oen
clko
spien
siwun
PMOD JA
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/JB_dark.svg b/corev_apu/instr_tracing/Pictures/JB_dark.svg new file mode 100644 index 0000000000..dd322aa9a3 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/JB_dark.svg @@ -0,0 +1,3 @@ + + +
VDD
GND
VDD
GND
d[3]
d[2]
d[7]
d[6]
d[1]
d[0]
d[5]
d[4]
PMOD JB
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/JB_light.svg b/corev_apu/instr_tracing/Pictures/JB_light.svg new file mode 100644 index 0000000000..a58e8ebb93 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/JB_light.svg @@ -0,0 +1,3 @@ + + +
VDD
GND
VDD
GND
d[3]
d[2]
d[7]
d[6]
d[1]
d[0]
d[5]
d[4]
PMOD JB
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Main_tracer_dark.svg b/corev_apu/instr_tracing/Pictures/Main_tracer_dark.svg new file mode 100644 index 0000000000..c5dd875103 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Main_tracer_dark.svg @@ -0,0 +1,3 @@ + + +
CVA6
RVFI
ITI

TRACER

rvfi_to_iti
iti_to_encoder
ENCODER
TC
0100
1101
DECODER
Encapsulated 
Packets
[Protocol] 
Packets
HARDWARE
SOFTWARE
program binary
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Main_tracer_light.svg b/corev_apu/instr_tracing/Pictures/Main_tracer_light.svg new file mode 100644 index 0000000000..1a4691ae32 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Main_tracer_light.svg @@ -0,0 +1,3 @@ + + +
CVA6
RVFI
ITI

TRACER

rvfi_to_iti
iti_to_encoder
ENCODER
TC
0100
1101
DECODER
Encapsulated 
Packets
[Protocol] 
Packets
HARDWARE
SOFTWARE
program binary
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Priority_dark.svg b/corev_apu/instr_tracing/Pictures/Priority_dark.svg new file mode 100644 index 0000000000..c1d8b7b587 --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Priority_dark.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid_i
valid_o 
packet_format
Priority
lc_exception
lc_updiscon
lc_final_qualified
tc_exception
tc_updiscon
tc_retired
tc_privchange
tc_enc_enabled
tc_enc_disabled
tc_branchmap_empty
tc_branchmap_full
nc_exception
nc_updiscon
nc_retired
nc_privchange
max_resync
tc_first_qualified
tc_qualified
nc_qualified
nc_branchmap_empty
packet_subformat
qual_status
resync_rst
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/Priority_light.svg b/corev_apu/instr_tracing/Pictures/Priority_light.svg new file mode 100644 index 0000000000..d4eae6ec3d --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/Priority_light.svg @@ -0,0 +1,3 @@ + + +
clk
rst
valid_i
valid_o 
packet_format
Priority
lc_exception
lc_updiscon
lc_final_qualified
tc_exception
tc_updiscon
tc_retired
tc_privchange
tc_enc_enabled
tc_enc_disabled
tc_branchmap_empty
tc_branchmap_full
nc_exception
nc_updiscon
nc_retired
nc_privchange
max_resync
tc_first_qualified
tc_qualified
nc_qualified
nc_branchmap_empty
packet_subformat
qual_status
resync_rst
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/TC_dark.svg b/corev_apu/instr_tracing/Pictures/TC_dark.svg new file mode 100644 index 0000000000..a4e86c2dce --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/TC_dark.svg @@ -0,0 +1,3 @@ + + +
SLICER

Transmission Channel

0100
1101
DECODER
Encapsulated 
Packets
DPTI
Frames
HARDWARE
SOFTWARE
RECEIVER
F2232H
USB
Bridge
DPTI
CTRL
ENCAPS
Packet
Slices
Packets
Decapsulated 
Packets
RAW
Packets
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/TC_light.svg b/corev_apu/instr_tracing/Pictures/TC_light.svg new file mode 100644 index 0000000000..6d2bbcaf9b --- /dev/null +++ b/corev_apu/instr_tracing/Pictures/TC_light.svg @@ -0,0 +1,3 @@ + + +
SLICER

Transmission Channel

0100
1101
DECODER
Encapsulated 
Packets
DPTI
Frames
HARDWARE
SOFTWARE
RECEIVER
F2232H
USB
Bridge
DPTI
CTRL
ENCAPS
Packet
Slices
Packets
Decapsulated 
Packets
RAW
Packets
\ No newline at end of file diff --git a/corev_apu/instr_tracing/Pictures/decoded_trace.png b/corev_apu/instr_tracing/Pictures/decoded_trace.png new file mode 100644 index 0000000000..3d400c6986 Binary files /dev/null and b/corev_apu/instr_tracing/Pictures/decoded_trace.png differ diff --git a/corev_apu/instr_tracing/Pictures/genesys-2.png b/corev_apu/instr_tracing/Pictures/genesys-2.png new file mode 100644 index 0000000000..8c0db43dba Binary files /dev/null and b/corev_apu/instr_tracing/Pictures/genesys-2.png differ diff --git a/corev_apu/instr_tracing/Pictures/genesys2_DPTI.png b/corev_apu/instr_tracing/Pictures/genesys2_DPTI.png new file mode 100644 index 0000000000..81ea39c2c3 Binary files /dev/null and b/corev_apu/instr_tracing/Pictures/genesys2_DPTI.png differ diff --git a/corev_apu/instr_tracing/Pictures/receiver.png b/corev_apu/instr_tracing/Pictures/receiver.png new file mode 100644 index 0000000000..05bfd12d56 Binary files /dev/null and b/corev_apu/instr_tracing/Pictures/receiver.png differ diff --git a/corev_apu/instr_tracing/README.md b/corev_apu/instr_tracing/README.md new file mode 100644 index 0000000000..4e89698f03 --- /dev/null +++ b/corev_apu/instr_tracing/README.md @@ -0,0 +1,721 @@ + + + +# Instruction Tracing + +## Introduction + +Instruction tracing is a crucial feature in modern processor design, particularly when it comes to **certification**, **debugging**, and **formal verification**. It allows engineers to **track the exact sequence of executed instructions**, providing a ground truth that can be compared against expected behavior. + +### Why Instruction Tracing? + +There are several scenarios where instruction tracing is essential: + +* **Certification and Compliance**: In safety-critical systems (e.g., avionics, automotive), it may be necessary to prove that instructions executed **exactly** as specified. +* **Debugging**: When an execution does not behave as expected, a trace can help **reconstruct** the execution flow and understand where and why things went wrong. + +### How Does It Work? + +In this project, we implemented an instruction tracer that uses the **E-TRACE encoding format** (as specified in the [E-Trace specification](https://github.com/riscv-non-isa/riscv-trace-spec)). + + E‑Trace implements a branch‑trace algorithm: it only emits control‑flow "deltas" (branches taken/not‑taken, indirect jumps/calls/returns, interrupts/exceptions) along with PC deltas, assumes sequential instructions implicitly, and can pack multiple retirements into compact packet, achieving a high compression rates while minimizing off‑chip bandwidth and interface complexity. + +There exist other encoding formats such as [N‑Trace](https://github.com/riscv-non-isa/tg-nexus-trace), which is built on the IEEE‑5001 Nexus standard. + +### System Overview + +The tracing system we built is composed of four main elements, illustrated in the block diagram below: + + + + + + + + + +## 1. Instruction Trace Interface (ITI) + +The **Instruction Trace Interface (ITI)** module is implemented in accordance with the [E-Trace specification](https://github.com/riscv-non-isa/riscv-trace-spec) (2025), specifically section 4.2 concerning the Instruction Trace Interface. It sits between the **cva6\_rvfi** (RISC-V Formal Interface) and the **encoder**, and plays a role in collecting and formatting instruction trace data. + +The ITI currently supports **two operating modes**: + +* **Multiple-retirement mode**(`block_mode = 1`): the trace data for several instructions is grouped together and sent to the encoder as a block. +* **Single-retirement mode**(`block_mode = 0`): the trace data are sent to the encoder instructions by instructions. + +At the moment, the ITI only supports the 3-bit itype format (`itype_len = 3`) for classifying instruction types. This is sufficient to distinguish key instruction categories such as branches, uninferable jumps, exceptions, and interrupts. While the E-Trace specification also defines a 4-bit format (`itype_len = 4`) for finer-grained classification, this is not yet implemented in the current design. Support for the 4-bit version could be added later if needed and if compatible with the encoder. + +> For more details about the `itype` field, refer to Table 7 of the [E-Trace specification](https://github.com/riscv-non-isa/riscv-trace-spec), as well as the field description provided just below. + +### Input Interface + + + + + + + +

+The module receives a structured input named **`rvfi_to_iti`**, which encapsulates all the necessary signals to: + +* determine the **instruction type (`itype`)** using fields such as `opcode`, `branch_valid`, etc., +* supply relevant metadata to the encoder like `cycle`, `privilege level`, `pc`, etc. + +Changes were also made to the `cva6_rvfi` module to collect the signals required by the ITI and to properly resynchronize them, since they may originate from different stages of the processor pipeline. This justifies the use of a structured interface to ensure reliable and consistent data transfer to the ITI. + +--- + +### Multiple-Retirement Mode + +In **multiple-retirement mode**, the ITI groups instructions into **blocks**, based on the occurrence of *special* instructions , typically those altering the control flow (e.g., jumps, exceptions, interrupts). + +The ITI outputs the following signals to the encoder in this mode: + +* `iret`: number of half-words for the retired instructions in the current block, +* `iaddr`: address of the first instruction in the block, +* `ilastsize`: size of the last instruction in the block. + +To support this, the ITI adopts a **systolic-like architecture** made up of `block_retirement` submodules. There are `Nr_commit_ports` such submodules, each able to: + +* detect special instructions independently, +* initiate a new block if necessary, +* propagate control and data signals (like `special`, `iaddr`, and incremented `iret`) along a chain. + +This design enables the generation of **multiple blocks in a single cycle** when several special instructions retire simultaneously. + + + + + + + + +--- +### Single-Retirement Mode + +In **single-retirement mode**, the ITI module forwards the trace information **instruction by instruction**, without grouping them into blocks. + +In this configuration: + +* There is no need to track special instructions or segment blocks. +* The encoder receives a simple feed of retired instructions, making this mode well-suited for simpler architectures. + + + + + + + + +--- +### Full System Overview + +The overall role of the ITI module in the trace infrastructure is summarized in the following diagram: + + + + + + +--- +### Continuous Integration for ITI + +The CI (Continuous Integration) test for the ITI is contained in Instr_tracing_test.sh and consist of running a simulation on ariane_testharness with the previous test iti_test.sh and extracting the iti.trace. Then it run the regressionFlow from the [E-Trace specification](https://github.com/riscv-non-isa/riscv-trace-spec) and compare both files. +We cleaned both file to compare what is comparable ,we exclude the start and the end because it's not matching based spike version + + +## 2. Encoder + Encapsulator + +### Collaboration and Reference Design + +For this module, we collaborate with the University of Bologna by integrating their version of the encoder, available +[here](https://github.com/pulp-platform/rv_tracer) + +Their repository is well-documented and serves as a solid foundation. The encoder design is aligned with the **E-Trace specification** and leverages an ITI running in **multiple-retirement mode** to emit **trace packets**. These packets are structured according to the **instruction delta trace algorithm** described in the [E-Trace specification](https://github.com/riscv-non-isa/riscv-trace-spec) (Figure 1), which provides a model for encoding deltas (non-linearities) in the control flow. + +Each data trace outputed by the ITI, whether block-based or instruction-based, is interpreted to identify these deltas and transmit them in the form of trace packets. These packets vary in format and size depending on the instruction type and control flow transitions. + +--- + +### Custom Implementation and Simplification + +While their encoder provides a baseline, it remains under active development. In its current state, its behavior (in terms of number of packets emitted, their contents, or supported options) differs from the Reference Flow. + +As a result, we opted to build a simplified version derived from the original architecture. This internal encoder: + +* Expects **instruction-by-instruction traces** as input, +* Supports only **Nr\_commit\_ports = 1** (single commit port), +* Implements only a **basic subset** of the E-Trace functionality. + +This choice facilitates initial validation and integration, though we remain open to switching back to a mature multiple-retirement encoder once available. + +Below is a high-level architectural diagram of the current encoder setup (here `N=1`): + + + + + + +--- + +### Submodules Description + +The encoder is composed of several key submodules: + +### Submodules Description + +The encoder is composed of several key submodules: + +* **Priority**: + This submodule constitutes the core of the *Instruction Delta Trace Algorithm*. It is responsible for analyzing control flow transitions across instructions and determining the format and/or subformat of trace packets to be emitted. + + + + + + + + The logic is driven by three categories of input signals that represent the state of the instruction stream at different points in time: + - **lc**: *Last Cycle* - information from the previous retired instruction, + - **tc**: *This Cycle* - information from the currently retiring instruction, + - **nc**: *Next Cycle* - information from the next instruction. + + > Some signals are intentionally absent for the sake of understanding + + Using these signals, the `Priority` module identifies the relevant **deltas** (e.g., taken branches, jumps, exceptions) and selects the appropriate **packet format and/or subformat**, which will subsequently guide the `Packet_Emitter`. + +
+ + | Format | Subformat | Description | + | :------: | :-------: | :------------------ | + | 3 | 3 | Support | + | | 2 | Context | + | | 1 | Trap | + | | 0 | Synchronisation | + | 2 | | Address Only | + | 1 | | Branch | + | 0 | | Optional extensions | +
+ + > For more details, refer to [Chapter 7 (Instruction Trace Encoder Output Packet)](https://github.com/riscv-non-isa/riscv-trace-spec) (2025), or consult the corresponding encoder section in the [University of Bologna's implementation](https://github.com/pulp-platform/rv_tracer). + + +* **Packet_Emitter**: + This submodule is responsible for **constructing and filling the trace packet** to be emitted. It plays a central role in materializing the output of the delta trace algorithm into a well-structured packet format compliant with the E-Trace specification. + + + + + + + + Similar to the `Priority` module, it receives multiple input signals that span across different time domains (*lc*,*tc*,*nc*). + + However, the most important **inputs** for this submodule is the **packet format and/or subformat**, which is deteminated by the `Priority` module. This format/subformat dictates the structure and contents of the packet's payload. Also **ppccd** means privilege change, precise context change or context change with discontinuity. + + Based on this, the `Packet_Emitter` output: + - The **payload** which contains all the fields expected for this packet, + - The **packet length** (in bytes), depending on the format/subformat and data, + - A **branch_map_flush** signal that is used to flush the `branch_map` field. This ensures the `branch_map` is ready to accurately track future branches for the next packet. + + > For a complete description of each packet type and its associated payload content, refer to [Chapter 7 (Instruction Trace Encoder Output Packet)](https://github.com/riscv-non-isa/riscv-trace-spec) of the E-Trace specification (2025). + +* **Filter**: + The `Filter` submodule is responsible for **selectively enabling or disabling instruction tracing** (with the qualified signal) based on configurable events defined through **Control Registers**. By filtering out irrelevant or redundant instructions, it can significantly improves trace analysis efficiency and bandwidth usage. + + + + + + + + The filtering mechanism supports a variety of events, including: + + - **Range Address**: Enables tracing **only when the instruction address (`iaddr`) falls within a specified address window**, defined by a `lower_addr` and a `higher_addr` boundary. + - **Stop Event**: Immediately halts instruction tracing when triggered. + - **Selected Privilege Level**: Enables or disables tracing depending on the **current privilege level** (e.g., user, supervisor, machine mode). + - **Other Events**: Filtering can also be triggered by **exceptions**, **interrupts**, or other **context-specific conditions**. + + +* **Branch\_Map**: + The `Branch_Map` submodule acts as a **history buffer** for recently executed branch instructions. It plays a crucial role in the generation of compressed trace packets by allowing the encoder to **reconstruct control-flow paths** through a compact representation. + + + + + + + This module maintains two key outputs: + + - **`branch_map`**: a **bitfield** representing the history of up to 31 conditional branches. For each branch, a **bit is added to the right**: + - `0` if the branch was **taken**, + - `1` if the branch was **not taken**. + + - **`branches`**: an **integer count** of how many branches are currently stored in the map (max: **31**). This counter helps determine the valid width of the `branch_map` field and guides packet formatting/decoding. + + The branch_map is updated as instructions retire. Once the maximum depth is reached or a flush is triggered (e.g., via `branch_map_flush` from the `Packet_Emitter`), the map is cleared to allow tracking of the next sequence. + + Here is an illustrative example, taken from [E-Trace Specification – Chapter 12, Example 4](https://github.com/riscv-non-isa/riscv-trace-spec). + + + + + + + + +--- + +### Encapsulation Module + +This module was developed by the **University of Bologna**, and we reused the `encapsulator.sv` module **as-is**, without any modifications. We chose **not to integrate the other submodules** provided in the original repository, as they are designed for the **ATB (Advanced Trace Bus)** protocol. In our case, we rely on a different trace output interface, named **DPTI (Digilent Parallel Transfer Interface)**, making the use of those ATB-specific modules unnecessary. [Here](https://github.com/pulp-platform/rv_encapsulator) is the repository of the encapsulator from the **University of Bologna**. + +The **encapsulator** is placed directly after the encoder and is responsible for wrapping each trace packet into a **standardized encapsulation format** as defined by the [encapsulation specification](https://github.com/riscv-non-isa/e-trace-encap). + +This format ensures **interoperability**, provides **framing rules**, and facilitates **packet-level synchronization** in the *transmission channel* interface. Each encapsulated packet in this implementation is **fixed at 320 bits (40 bytes)** and includes this field groups: + +- **Header (8 bits)**: + Includes a `length` field (5 bits) specifying the payload size in bytes, a `flow` field (2 bits) which is currently set to `00` (no multi-sink used yet), and an `extend` bit (1 bit) which is set to `1`, indicating the presence of a timestamp (T ? in the figure bellow). + +- **Timestamp (`T * 8` bits)**: + The timestamp is included in our packets and is **fixed at 8 bytes (64 bits)**. Its presence is governed by the `extend` bit in the header. + +- **Payload (1–248 bits)**: + Contains the actual trace packet, emmited by the encoder with `packet_payload_o`. + +An illustration of the encapsulation structure is shown below: + + + + + + +

+ +Once encapsulated, the packets are written into a **FIFO buffer**, where they await transmission through the trace communication channel. + +This design enables modular evolution: improvements or full spec-compliance in the encoder can be adopted later without altering the overall encapsulation and transmission stages. +

+ +> While the [encapsulation specification](https://github.com/riscv-non-isa/e-trace-encap) also defines support for **source IDs** , **null packets** (e.g., `null.idle`, `null.alignment`), and **synchronization sequences**, these features are **not yet implemented** in the current prototype. + +### Continuous Integration for Encoder + Encapsulator + +The CI (Continuous Integration) test for the Encoder and Encapsulator is also contained in Instr_tracing_test.sh and consists in running a simulation on ariane_testharness with the previous test iti_test.sh and extracting the `encoded.trace`, it will convert them in decaspulated csv format with the Decapsuler. Then it runs the regressionFlow from the [E-Trace specification](https://github.com/riscv-non-isa/riscv-trace-spec) and compare both files. +We cleaned both file to compare what is comparable, again we exclude the start and the end because it's not matching based spike version. + + +--- + + +## 3. Transmission Channel (TC) via DPTI + +
+ +

Figure: Digilent Genesys2 development board

+
+ +Picture from [Digilent Reference Manual](digilent.com/reference/programmable-logic/genesys-2/reference-manual) +

+Since most onboard peripherals (UART, SPI, etc.) are already used by the `ariane_xilinx` platform, we use the **FTDI FT2232H**'s DPTI interface exposed on the **USB-JTAG bridge (J17)**: + +
+ +

Figure: USB-JTAG bridge

+
+ +Picture from [Digilent Reference Manual](digilent.com/reference/programmable-logic/genesys-2/reference-manual) + +- **DPTI/DSPI header** on J17 provides: + - A **Digilent Parallel Transfer Interface (DPTI)** channel + - A generic SPI channel (not used here due to limited bandwidth) + +We selected **DPTI** because it is a **mature, out‑of‑the‑box solution** full driver support from Digilent Adept ([Adept Drivers & Utilities](https://digilent.com/reference/software/adept/)). + +--- + +### FT2232H Ports in Genesys 2 + +The FT2232H chip offers two independent channels but in the Top platform `ariane_xilinx` both of them are used : + +| Port | Default Use in `ariane_xilinx`| +|-------|-------------------------------| +| Port A| Bitstream injection | +| Port B| Debug Module interface | + +Because both channels are occupied, we have two deployment options: + +1. **Re-purpose Port B** + - **Disconnect the Debug Module** in `ariane_xilinx.sv`. + - Update `genesys.xdc` to add DPTI pin constraints (e.g., check the [default constraint file](https://github.com/Digilent/digilent-xdc/blob/master/Genesys-2-Master.xdc) section DPTI). + - Inject your program via the on‑chip **bootrom**, modify the Makefile in `corev_apu/fpga/src/bootrom` accordingly. + +2. **Add an FT2232H MiniModule** + - Use a standard [FT2232H Mini Module](https://ftdichip.com/products/ft2232h-mini-module/) connected to two PMOD headers. + - This gives you two **additional** FT2232H channels without touching the existing Port A/B setup. + +
+ +

Figure: FT2232H MiniModule wired to Genesys2 PMODs

+
+

+
+ + + + + + + + + + + +
+

+ +> For more details on the wiring, check these resources: +> - [FT2232H Datasheet](https://ftdichip.com/wp-content/uploads/2024/09/DS_FT2232H.pdf), Table 3.1 +> - [FT2232H Mini Module Datasheet](https://ftdichip.com/wp-content/uploads/2020/07/DS_FT2232H_Mini_Module.pdf), Table 3.1 and Table 3.2 and USB Bus-powered section. + +--- + +### Platform Modifications + + + + + + + + +1. **DPTI Controller** + - Add `dpti_ctrl.vhd` to handle **frame send/receive** over DPTI. This module is provided by Digilent and can be found in the [**Digilent Adept SDK**](https://lp.digilent.com/complete-adept-runtime-download), under `samples/dpti/DptiDemo/logic/dpti_ctrl.vhd`. + - Protocol: **8-bit parallel**, synchronous/asynchronous, running at **60 MHz**, allowing for up to **480 Mbps** throughput. + - The controller requires a clock. It is instantiated in the platform using `xlnx_dpti_clk` located in `cva6/corev_apu/fpga/xilinx/xlnx_dpti_clk`. Alternatively, it can be added to the Vivado project using a Clock Wizard. An example configuration is available in `samples/dpti/DptiDemo/logic/clk_wiz_0.v`. + +2. **Packet Slicer** + - Our trace packets are **320 bits** (40 bytes). + - Insert `slicer_DPTI.sv` to segment each packet into **40 eight‑bit frames** for DPTI transport. + +3. **PMOD Pin Mapping & Constraints** + - PMOD pins used must support external clock (C‑capable). Follow [UG472](https://docs.amd.com/v/u/en-US/ug472_7Series_Clocking) (Vivado) guidelines. + - Example excerpt from `genesys2.xdc`: + ```xdc + ## PMOD Header JA + #set_property -dict { PACKAGE_PIN U27 IOSTANDARD LVCMOS33 } [get_ports prog_clko]; #IO_L13P_T2_MRCC_14 Sch=ja_p[1] + #set_property -dict { PACKAGE_PIN U28 IOSTANDARD LVCMOS33 } [get_ports prog_oen]; #IO_L13N_T2_MRCC_14 Sch=ja_n[1] + #set_property -dict { PACKAGE_PIN T26 IOSTANDARD LVCMOS33 } [get_ports prog_rdn]; #IO_L12P_T1_MRCC_14 Sch=ja_p[2] + #set_property -dict { PACKAGE_PIN T27 IOSTANDARD LVCMOS33 } [get_ports prog_rxen]; #IO_L12N_T1_MRCC_14 Sch=ja_n[2] + #set_property -dict { PACKAGE_PIN T22 IOSTANDARD LVCMOS33 } [get_ports prog_siwun]; #IO_L5P_T0_D06_14 Sch=ja_p[3] + #set_property -dict { PACKAGE_PIN T23 IOSTANDARD LVCMOS33 } [get_ports prog_spien]; #IO_L5N_T0_D07_14 Sch=ja_n[3] // Not needed here + #set_property -dict { PACKAGE_PIN T20 IOSTANDARD LVCMOS33 } [get_ports prog_txen]; #IO_L4P_T0_D04_14 Sch=ja_p[4] + #set_property -dict { PACKAGE_PIN T21 IOSTANDARD LVCMOS33 } [get_ports prog_wrn]; #IO_L4N_T0_D05_14 Sch=ja_n[4] + + ## PMOD Header JB + #set_property -dict { PACKAGE_PIN V29 IOSTANDARD LVCMOS33 } [get_ports { prog_d[0] }]; #IO_L17P_T2_A14_D30_14 Sch=jb_p[1] + #set_property -dict { PACKAGE_PIN V30 IOSTANDARD LVCMOS33 } [get_ports { prog_d[1] }]; #IO_L17N_T2_A13_D29_14 Sch=jb_n[1] + #set_property -dict { PACKAGE_PIN V25 IOSTANDARD LVCMOS33 } [get_ports { prog_d[2] }]; #IO_L18P_T2_A12_D28_14 Sch=jb_p[2] + #set_property -dict { PACKAGE_PIN W26 IOSTANDARD LVCMOS33 } [get_ports { prog_d[3] }]; #IO_L18N_T2_A11_D27_14 Sch=jb_n[2] + #set_property -dict { PACKAGE_PIN T25 IOSTANDARD LVCMOS33 } [get_ports { prog_d[4] }]; #IO_L14P_T2_SRCC_14 Sch=jb_p[3] + #set_property -dict { PACKAGE_PIN U25 IOSTANDARD LVCMOS33 } [get_ports { prog_d[5] }]; #IO_L14N_T2_SRCC_14 Sch=jb_n[3] + #set_property -dict { PACKAGE_PIN U22 IOSTANDARD LVCMOS33 } [get_ports { prog_d[6] }]; #IO_L21P_T3_DQS_14 Sch=jb_p[4] + #set_property -dict { PACKAGE_PIN U23 IOSTANDARD LVCMOS33 } [get_ports { prog_d[7] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=jb_n[4] + ``` + - Ensure **V3V3** pins are tied to **VIO** in the MiniModule. + +4. **FT2232H Configuration** + - Use **FT_Prog** (or equivalent) to set the MiniModule into **USB FIFO mode**. + - ⚠️ Digilent Adept drivers validate a protected EEPROM region not writable via FT_Prog. + - Either use Digilent reprogramming executable + - Or adapt the C++ receiver to be compatible with the FTDI drivers. + +
+ +

Figure: Valid EEPROM for DPTI

+
+ +--- + +### Bitstream Build & Deployment + +Once hardware wiring and constraints are in place with ITI, Encoder, Encapsulator, etc. : +> We used Vivado version: 2018.2 +```bash +make clean +make fpga TARGET=cv32a6_imac_sv32 +``` + +Then upload the generated ariane_xilinx.bit via Vivado Lab or your preferred hardware manager. + +--- +## 4. Software-Side Reception + +The trace reception is handled on a **Linux-based host PC**, which is connected either to the **FTDI MiniModule** or directly to the **Genesys2 board via port J17**. + +To enable communication via **DPTI (Digilent Parallel Trace Interface)**, you must first install the [**Digilent Adept SDK**](https://lp.digilent.com/complete-adept-runtime-download), specifically version `2.4.2`. This provides the required runtime libraries and development headers. The receiver code needs a C++17 version for `std::optional`. + +--- + +### Setup Instructions + +1. **Install Adept SDK** + + * Ensure the Digilent API is installed and correctly configured. + * The official Digilent SDK and documentation provide a guide. + +2. **Configure and Compile the Receiver** + + * The receiver code is located in `Receiver_DPTI.cpp`. + * You must **edit the `Makefile`** to match the paths to the Adept libraries and headers. + + * Refer to the README files in `digilent.adept.sdk_2.4.2/samples` for more informations . + * Then compile the program with: + + ```bash + make clean + make + ``` + +3. **Device Detection and Debugging** + + * The receiver includes debug function, such as `Scan_Device`, which: + + * Lists connected FTDI devices + * Displays their names + +4. **Configure BOARD\_NAME** + + * You must update the `BOARD_NAME` field in `Receiver_DPTI.cpp` to match the actual serial string of your connected device. + * Example: + + ```cpp + char* BOARD_NAME = (char*) "#tpt_0001#ptc_0002#210300075227"; + ``` + * After editing the file, recompile: + + ```bash + make clean + make + ``` + +5. **Running the Receiver** + + * Launch the receiver with: + + ```bash + ./Receiver_DPTI + ``` + * The program proceeds in **two phases**: + + * **Acquisition Phase**: Data is streamed and stored in raw format. Stop the acquisition with `SIGINT` (Ctrl+C). + * **Decapsulation Phase**: The raw binary packets are parsed and converted into human-readable CSV format. + + +
+ +

Figure: Valid execution ./Receiver_DPTI

+
+ +--- + +### Output Files + +Two output files are generated in the `receiver_data/` directory: + +* `YYYYMMDD_hhmm_raw_file.txt` - the raw encapsulated packets +* `YYYYMMDD_hhmm_data.csv` - the decoded content in CSV format + +These CSV files can be supplied to a decoder for further analysis. + +>Currently, no custom decoder is implemented. We use the reference decoder provided in the Reference Flow repository to interpret the trace contents. The University of Bologna released a version of their decoder on 3rd July 2025, but we have not evaluated it yet. + +--- + +## 5. Decoder + +At this stage, we have **not yet implemented** our own decoder. Instead, we rely on the **Reference Flow decoder** provided by the E‑Trace specification. + +#### Running the Reference Flow + +To perform decoding, you first need to run the full reference flow regression so that it can generate the files from the program binary required by its version of Spike(in the `referenceFlow`). In addition, your compiled program must be renamed with a `.riscv` extension so that the flow recognizes it as RISC‑V input and it need to be place in `referenceFlow/tests/test_files`. + +1. **Prepare your binary** + ```bash + cp path/to/your_program.elf referenceFlow/tests/test_files/your_program.riscv + ``` +2. **Execute the full reference flow** +```bash +cd referenceFlow +./scripts/run_regression.sh \ + -t itype3_debug \ + --annotate \ + --debug\ + tests/test_files/your_program.riscv +``` + + * `-t`: Specify the test suite used, here we choose `itype3_debug` to match our encoder and `_debug` to add more information in packets like `full_address mode` + * `--annotate`: This flag is optionnal and using it create annotated version of output files , usefull for understanding/debugging + * `--debug`: This flag is optionnal and using it will print in the terminal more informations about each stage + +### Decoding the Trace +Once the reference flow regression has run successfully (and generated the files needed), you can invoke the decoder step: + +```bash +cd referenceFlow +./scripts/decoder_model.py \ + -u regression_YYYYMMDD_hhmmss/itype3_debug/your_program.decoder.ucf \ + -c regression_YYYYMMDD_hhmmss/itype3_debug/hardware.scf \ + -i TRACE_OUTPUT + +``` + * `-u`: user_config, this file is generated with the first regression, inside there are information about debug flags, object-files, encoder configuration, etc + * `-c`: static_config, this file is also generated but correspond to test suite you choose, inside there are informations about default values (size of fields, encoder options, etc) + * `-i`: This file is the output of the encoder by default :`regression_YYYYMMDD_hhmmss/itype3_debug/your_program.te_inst_raw` but you can use the trace from the receiver, it support CSV format and raw format (needs to be a real binary in this case) + + If everything matches, meaning there are no difference between the captured trace and the reference Trace, you will obtain an output file like this: + +
+ +

Figure: Excerpt from decoded trace

+
+ +

+⚠️ Mismatches can occur if, for example: + +* The platform's address map (CrossBar) doesn't align with your binary's load addresses + +* The encoder fails to emit a packet (e.g., due to a bug in the encoder) + +* There is receiver desynchronization or signal glitches during trace capture + +### Current Limitations & Future Work +When we load the program via the onboard Debug Module, you will notice "trace pollution" : extra instructions corresponding to debug and JTAG activity appear in the trace. One way to mitigate this is to use the Filter submodule in the encoder to suppress unwanted instructions. However: + +**Problem:** We have not yet exposed the APB path needed to drive the Filter's control registers at runtime. + +**Next Steps:** Extend the encoder to include an APB interface for the Filter module, allowing dynamic trace filtering before encapsulation. + + +## 6. Debug Automation & VSCode Setup + +This section presents a set of **automation tools and configurations** developed to streamline the debug process using **Visual Studio Code (VSCode)**. The goal is to make it easy to: + +* **Compile user programs** into a binary format compatible with the **CV32A6** core +* **Launch OpenOCD** using the expected configuration (`ariane.cfg`) +* **Start GDB** in **remote debug mode**, attached to the target via OpenOCD + +--- + +### VSCode Integration + +To integrate these operations directly within the VSCode interface, we make use of two special configuration files: + +* `.vscode/launch.json` - defines how to start a debugging session +* `.vscode/tasks.json` - defines custom build and terminal commands + +With this setup, you can use the built-in **debug pane** of VSCode to: + +* Upload and connect to the board +* Step through code using breakpoints and GDB integration + +These files must be placed inside a `.vscode/` directory at the root of the project. + +--- + +### File Overview + +**launch.json** + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug FPGA via OpenOCD", + "type": "cppdbg", + "targetArchitecture": "x86_64", + "request": "launch", + "program": "${workspaceFolder}/Prog_compiled", + "miDebuggerServerAddress": "localhost:3333", + "useExtendedRemote": true, + "miDebuggerPath": "toolchain/bin/riscv-none-elf-gdb", + "stopAtEntry": true, + "stopAtConnect": true, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "preLaunchTask": "build-and-start-openocd", + "postRemoteConnectCommands": [ + { + "text": "source ${workspaceFolder}/gdb_init.txt" + } + ] + } + ] + } +``` + +**tasks.json** + +```json +{ + "version": "2.0.0", + "tasks": [ + + { + "label": "build-exec", + "type": "shell", + "command": "riscv-none-elf-gcc", + "args": [ + "-g", "-T", "custom_linker.ld", + "-march=rv32imac_zicsr", + "-lgcc", "-fvisibility=hidden", + "-mcmodel=medany", "-mabi=ilp32", + "-nostartfiles", "crt.S", "syscalls.c", "test.c", + "-o", "Prog_compiled" + ], + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "start openocd", + "type": "shell", + "command": "bash", + "args": [ + "-c", + "nohup gnome-terminal -- bash -c \"openocd -f ariane.cfg; exec bash\"" + ], + "problemMatcher": [] + }, + { + "label": "build-and-start-openocd", + "dependsOn": ["build-exec", "start openocd"] + } + ] + } + + +``` + +These configurations are adaptable to your own build system or directory structure. + +--- + +### Additional Resources + +* [VSCode Debugging Documentation](https://code.visualstudio.com/docs/debugtest/debugging) +* [VSCode Task Configuration](https://code.visualstudio.com/docs/debugtest/tasks) diff --git a/corev_apu/instr_tracing/SW/Receiver_DPTI/Makefile b/corev_apu/instr_tracing/SW/Receiver_DPTI/Makefile new file mode 100644 index 0000000000..50517ba22e --- /dev/null +++ b/corev_apu/instr_tracing/SW/Receiver_DPTI/Makefile @@ -0,0 +1,30 @@ +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales + +# Makefile to build the receiver executable +# You need to properly install Digilent Adept and correctly link adept sdk lib +CC = g++ +INC ?= $(HOME)/runtime_adept/digilent.adept.sdk_2.4.2 +LIBDIR = /usr/lib64/digilent/adept +TARGETS = Receiver_DPTI +CFLAGS = -I $(INC) -L $(LIBDIR) -ldpti -ldmgr -Wall -Wextra -g + +all: $(TARGETS) + +Receiver_DPTI: Receiver_DPTI.cpp + $(CC) -o Receiver_DPTI Receiver_DPTI.cpp $(CFLAGS) + +.PHONY: clean + +clean: + rm -f $(TARGETS) + +clean_all: + rm -f $(TARGETS) + rm -rf receiver_data diff --git a/corev_apu/instr_tracing/SW/Receiver_DPTI/Receiver_DPTI.cpp b/corev_apu/instr_tracing/SW/Receiver_DPTI/Receiver_DPTI.cpp new file mode 100644 index 0000000000..51290d38d6 --- /dev/null +++ b/corev_apu/instr_tracing/SW/Receiver_DPTI/Receiver_DPTI.cpp @@ -0,0 +1,455 @@ +// Copyright (c) 2025 Thales DIS design services SAS +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// Author: Maxime Colson - Thales +// Date: 17/06/2025 +// Contributors: +// Côme Allart - Thales + +// This code is designed to receive encapsulated packets emitted by an instruction encoder (See e-trace-encap). +// It captures them in two formats: raw and decapsulated (.csv). +// These files can then be passed to a decoder (e.g., riscv-trace-spec/referenceFlow/scripts/decoder_model.py). + +// To properly use this receiver, you need a Digilent FPGA board using the DPTI module from the Adept SDK. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dpcdecl.h" +#include "dmgr.h" +#include "dpti.h" + +volatile sig_atomic_t stop = 0; + +void handle_sigint(int) { stop = 1; } + +const size_t NR_PKT = 20; +const size_t PACKET_SIZE = 40; +const size_t BLOCK_SIZE = NR_PKT * PACKET_SIZE; + +typedef BYTE packet_t[PACKET_SIZE]; +typedef std::array sample_t; + +uint64_t extract_bits(const packet_t &packet, std::size_t bit_offset, + std::size_t bit_length) { // FIXME add assertion to prevent desynchro segfault + uint64_t result = 0xdead; // We use 'dead' as an indicator to quickly detect if a desynchro happened during the aquisition (without stoping decapsulation) + if (bit_length <= 64) { + result = 0; + for (std::size_t i = 0; i < bit_length; ++i) { + std::size_t global_bit = bit_offset + i; + std::size_t byte_index = global_bit / 8; + std::size_t bit_index = 7 - (global_bit % 8); + uint64_t bit = (packet[byte_index] >> bit_index) & 0x1; + result = (result << 1) | bit; + } + } + return result; +} + +template struct PrintableOption : public std::optional { + PrintableOption(std::optional &o) : std::optional(o) {} + PrintableOption(T &v) : std::optional(v) {} + PrintableOption(uint64_t v) : std::optional(v) {} + PrintableOption() : std::optional() {} + + friend std::ostream &operator<<(std::ostream &s, const PrintableOption &o) { + if (o.has_value()) + s << unsigned(*o); + else + s << "_"; + + return s; + } +}; + +struct BitExtractor { + const packet_t &packet; + bool is_backward; + size_t i; + + BitExtractor(const packet_t &packet, bool backward) + : packet(packet), is_backward(backward), + i(backward ? PACKET_SIZE * 8 : 0) {} + + uint64_t operator()(size_t bits) { return extract(bits); } + uint64_t to(size_t bit) { return extract_to(bit); } + + uint64_t extract_to(size_t bit) { return extract(i - bit); } + uint64_t extract(size_t bits) { + if (is_backward) + i -= bits; + + uint64_t result = extract_bits(packet, i, bits); + + if (!is_backward) + i += bits; + + return result; + } +}; + +struct Trace { + bool P_Time; // MSB + uint8_t P_ID; // 2 bits after MSB + uint8_t P_Size; // 5bits after P_ID + uint64_t P_Timestamp; // 64 bits after P_Size + PrintableOption format; // 2bits LSB + PrintableOption subformat; // 2bits before LSB if format=3 + PrintableOption address; // start of payload + PrintableOption branch; // F3SF0 (5) F3SF1 (5) else NDF + PrintableOption branches; // F1 (3) + PrintableOption branch_map; // F1 (4 : branches) + PrintableOption branch_count; // NDF + PrintableOption branch_fmt; // NDF + PrintableOption context; // NDF + PrintableOption ecause; //F3SF1 (8) F3SF1T (70) + PrintableOption ienable; //F3SF3 (5) + PrintableOption encoder_mode;//F3SF3 (6) + PrintableOption interrupt; // F3SF1(9) F3SF1T(71) + PrintableOption irreport; // F2 (5) F1(5) + PrintableOption irdepth; //if call/ret F2(6:2^cal) F1(6:2^cal) else NDF + PrintableOption notify; // F2(3) F1(3) + PrintableOption ioptions; //F3SF3 (8:15) + PrintableOption privilege; // F3SF0 (6) F3SF1 (6) F3SF2 (5) + PrintableOption qual_status;// F3SF3(7) + PrintableOption time; //if time F3SF0(8:72) F3SF1(8:72) F3SF2(7:71) //FIXME encoder could have time in last position + PrintableOption thaddr; // F3SF1(40) F3SF1_t(104) + PrintableOption tval; //F3SF1 (41:73) F3SF1_t(105:137) + PrintableOption updiscon;// F2(4) + PrintableOption denable;// NDF here + PrintableOption dloss;// NDF here + PrintableOption doptions;// NDF here + uint8_t size_branch_map; + + Trace(const packet_t &packet, bool time_flag, bool call_flag) { + size_branch_map = 0; + + BitExtractor header_extractor(packet, false); + BitExtractor payload_extractor(packet, true); + + // Header of encapsulated packet : + P_Time = header_extractor(1); + P_ID = header_extractor(2); + P_Size = header_extractor(5); + size_t P_Start = (PACKET_SIZE - P_Size) * 8; + P_Timestamp = header_extractor(64); + + // Extraction of fields contained in the payload : + format = payload_extractor(2); + if (format == 3) { + subformat = payload_extractor(2); + } + + if (format == 3 && subformat.has_value()) { + switch (subformat.value()) { + case 0: { // F3SF0 + branch = payload_extractor(1); + privilege = payload_extractor(2); + if (time_flag) { + time = payload_extractor(64); + } + address = payload_extractor.to(P_Start); + break; + } + case 1: { // F3SF1 + branch = payload_extractor(1); + privilege = payload_extractor(2); + if (time_flag) { + time = payload_extractor(64); + } + ecause = payload_extractor(32); + interrupt = payload_extractor(1); + thaddr = payload_extractor(1); + tval = payload_extractor(32); + address = payload_extractor.to(P_Start); + break; + } + case 2: { // F3SF2 + privilege = payload_extractor(2); + if (time_flag) { + time = payload_extractor(64); + } + break; + } + case 3: { // F3SF3 + ienable = payload_extractor(1); + encoder_mode = payload_extractor(1); + qual_status = payload_extractor(2); + ioptions = payload_extractor(7); + break; + } + } + } + + // F2 + if (format == 2) { + notify = payload_extractor(1); + updiscon = payload_extractor(1); + irreport = payload_extractor(1); + if (call_flag) { // FIXME addapt to call_counter_size + irdepth = payload_extractor(1); // if = 0 else 2^call_counter_size + } + address = payload_extractor.to(P_Start); + } + + // F1 + if (format == 1) { + branches = payload_extractor(5); + if(branches==0) { + size_branch_map = 31; + } else if (branches == 1) { + size_branch_map = 1; + } else if (branches <= 3) { + size_branch_map = 3; + } else if (branches <= 7) { + size_branch_map = 7; + } else if (branches <= 15) { + size_branch_map = 15; + } else { + size_branch_map = 31; + } + + branch_map = payload_extractor(size_branch_map); + + if (branches != 0) { + notify = payload_extractor(1); + updiscon = payload_extractor(1); + irreport = payload_extractor(1); + if (call_flag) { // FIXME addapt to call_counter_size + irdepth = payload_extractor(1); // if = 0 else 2^call_counter_size + } + address = payload_extractor.to(P_Start); + } + } + } + + static std::string csvHeader() { + return std::string( + "format,subformat,address,branch,branches,branch_map,branch_count," + "branch_fmt,context,ecause,ienable,encoder_mode,interrupt,irreport," + "irdepth,notify,ioptions,privilege,qual_status,time,thaddr,tval," + "updiscon,denable,dloss,doptions"); + } + + friend std::ostream &operator<<(std::ostream &s, Trace const &trace) { + trace.put_str(s); + return s; + } + + std::ostream &put_str(std::ostream &s) const { + s << format << "," << subformat << ","; + + s << std::hex << std::nouppercase << address << std::dec << ","; + + s << branch << "," << branches << "," << branch_map << "," << branch_count + << "," << branch_fmt << ","; + + s << context << "," << ecause << "," << ienable << "," << encoder_mode + << "," << interrupt << ","; + + s << irreport << "," << irdepth << "," << notify << "," << ioptions << "," + << privilege << "," << qual_status << ","; + + s << std::hex << std::nouppercase << time << std::dec << ","; + + s << thaddr << "," << tval << "," << updiscon << "," << denable << "," + << dloss << "," << doptions ; + + return s; + } + + std::string toCSVLine() { + std::ostringstream oss; + oss << *this; + return oss.str(); + } +}; + +std::string getTime () { + auto now = std::chrono::system_clock::now(); + std::time_t t = std::chrono::system_clock::to_time_t(now); + std::tm tm = *std::localtime(&t); + std::ostringstream ts; + ts << std::put_time(&tm, "%Y%m%d_%H%M"); + std::string timestamp = ts.str(); + + return timestamp; +} + +void Scan_Device (){ + int indexmax; + DmgrEnumDevices(&indexmax); + std::cout << indexmax < transaction_DPTI(uint32_t peripheral_handle) { + bool Transaction; + int error; + auto sample_ptr = std::make_unique(); + Transaction = DptiIO(peripheral_handle, NULL, 0, (BYTE *) sample_ptr.get(), BLOCK_SIZE, false); + + if (!Transaction) { + error = DmgrGetLastError(); + if (error == ercTransferCancelled) { + throw std::runtime_error("data transfer timed out"); + } else { + throw std::runtime_error("data transfer failed code : " + std::to_string(error)); + } + } + return sample_ptr; +} + +int main() { + // Change this field according to your board / encoder + char *BOARD_NAME = (char*)"#tpt_0001#ptc_0002#210300075227"; + const int32_t PORT = 1; // 0 or 1 + const bool TIME_FLAG = 1; + const bool CALL_FLAG = 0; + + uint32_t peripheral_handle; + peripheral_handle = hifInvalid; + size_t counter = 0; + std::vector> all_data; + //Scan_Device(); + const std::string out_dir = "receiver_data"; + + if (!std::filesystem::exists(out_dir)) { + std::filesystem::create_directory(out_dir); + } + + std::string timestamp= getTime(); + + // File paths + std::string raw_path = out_dir + "/" + timestamp + "_raw_file.txt"; + std::string csv_path = out_dir + "/" + timestamp + "_data.csv"; + + std::ofstream raw_file(raw_path); + std::ofstream csvFile(csv_path); + + + + // Initialisation of the DPTI Channel + try { + peripheral_handle = init_DPTI(BOARD_NAME, PORT); + } catch (const std::exception &e) { + if (peripheral_handle != hifInvalid) { + DptiDisable(peripheral_handle); + DmgrClose(peripheral_handle); + } + std::cerr << "ERROR Init : " << e.what() << std::endl; + return 1; + } + + + // Capture loop + signal(SIGINT, handle_sigint); + std::cout << "\nLoop (Ctrl+C to exit)\n\n"; + auto capture_start = std::chrono::high_resolution_clock::now(); + while (!stop) { + try { + auto sample_ptr = transaction_DPTI(peripheral_handle); + all_data.push_back(std::move(sample_ptr)); + + std::cout << "\rIteration : " << counter << " " << std::flush; + counter += NR_PKT; + } catch (const std::exception &e) { + std::cerr << "ERROR Transaction : " << e.what() << std::endl; + break; + } + } + auto capture_end = std::chrono::high_resolution_clock::now(); + + std::chrono::duration capture_delta_time = + capture_end - capture_start; + double capture_delta_time_sec = capture_delta_time.count(); + double throughput = (counter * PACKET_SIZE * 8) / capture_delta_time_sec; + if (throughput < 1e6) { + std::cout << "\n\nThroughput : " << std::fixed << std::setprecision(2) + << throughput / 1e3 << " Kb/s"; + } else { + std::cout << "\n\nThroughput : " << std::fixed << std::setprecision(2) + << throughput / 1e6 << " Mb/s"; + } + std::cout << "\t\tCapturing took :" << capture_delta_time_sec << "s\n"; + + // Writing output : Raw / Decapsulated csv + auto write_start = std::chrono::high_resolution_clock::now(); + if (csvFile.is_open() && raw_file.is_open()) { + csvFile << Trace::csvHeader() << "\n"; + for (const auto &sample_ptr : all_data) { + for (const packet_t &packet : *sample_ptr) { + Trace trace(packet, TIME_FLAG, CALL_FLAG); + csvFile << trace.toCSVLine() << "\n"; + for (size_t k = 0; k < PACKET_SIZE; ++k) { + raw_file << std::uppercase << std::hex << std::setw(2) + << std::setfill('0') << (unsigned)packet[k]; + } + raw_file << "\n"; + } + } + std::cout + << "\n========================SUCCESS_WRITE========================\n"; + } + auto write_end = std::chrono::high_resolution_clock::now(); + std::chrono::duration write_delta_time = write_end - write_start; + double write_delta_time_sec = write_delta_time.count(); + std::cout << "\nWriting Took : " << write_delta_time_sec << "s\n"; + + auto raw_size = std::filesystem::file_size(raw_path); + auto csv_size = std::filesystem::file_size(csv_path); + std::cout << "\nRaw file size: " << raw_size / 1e6 << " Mbytes\t"; + std::cout << "CSV file size: " << csv_size / 1e6 << " Mbytes\n"; + + DptiDisable(peripheral_handle); + DmgrClose(peripheral_handle); + + std::cout + << "\n========================SUCCESS_CLOSE========================\n\n"; + + return 0; +} \ No newline at end of file diff --git a/corev_apu/instr_tracing/SW/Receiver_DPTI/clean_csv.sh b/corev_apu/instr_tracing/SW/Receiver_DPTI/clean_csv.sh new file mode 100644 index 0000000000..0bbd3ed316 --- /dev/null +++ b/corev_apu/instr_tracing/SW/Receiver_DPTI/clean_csv.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales +# THis script remove lines above the start packet 3.3 + +if [ $# -ne 1 ]; then + echo "Usage!: $0 file/to/clean.csv" + exit 1 +fi +# This script will clean the csv trace by starting the trace at the first packet after reset +input_file="$1" +output_file="${input_file%.csv}_cleaned.csv" +temp_file=$(mktemp) + +awk 'found || /^3,3,_,_,/ {found=1; print}' "$input_file" > "$temp_file" + +{ + printf "format,subformat,address,branch,branches,branch_map,branch_count," + printf "branch_fmt,context,ecause,ienable,encoder_mode,interrupt,irreport," + printf "irdepth,notify,ioptions,privilege,qual_status,time,thaddr,tval," + printf "updiscon,denable,dloss,doptions\n" + + cat "$temp_file" +} > "$output_file" + +rm "$temp_file" + +echo "File Cleaned : $output_file" \ No newline at end of file diff --git a/corev_apu/instr_tracing/SW/Receiver_DPTI/run_timeout.sh b/corev_apu/instr_tracing/SW/Receiver_DPTI/run_timeout.sh new file mode 100644 index 0000000000..68355bf883 --- /dev/null +++ b/corev_apu/instr_tracing/SW/Receiver_DPTI/run_timeout.sh @@ -0,0 +1,39 @@ +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales + +#Script to automate the aquisition process for the receiver + +NR_PKTS=(1 2 10 20 50 100 200) +DURATION=5 + +LOG_FILE="log_$(date +'%Y%m%d_%H%M%S').txt" +echo "Fichier de log : $LOG_FILE" + +echo -e "NR_PKT\tThroughput (Mb/s)" > "$LOG_FILE" + +capture_fct() { + ./Receiver_DPTI & + PID=$! + sleep "$DURATION" + kill -SIGINT "$PID" + sleep 2 +} + +for i in "${NR_PKTS[@]}"; do + echo "=== NR_PKT = $i ===" + sed -i "s/const int NR_PKT = [0-9]\+;/const int NR_PKT = $i;/" Receiver_DPTI.cpp + make > /dev/null || { echo "Compilation échouée à $i"; exit 1; } + + OUTPUT=$(capture_fct | grep -oP 'Throughput\s*:\s*\K[0-9.]+' ) + echo "$i : $OUTPUT" | tee -a "$LOG_FILE" + +done + +python3 script.py "$LOG_FILE" + diff --git a/corev_apu/instr_tracing/SW/Receiver_DPTI/script.py b/corev_apu/instr_tracing/SW/Receiver_DPTI/script.py new file mode 100644 index 0000000000..2b3f1ef61e --- /dev/null +++ b/corev_apu/instr_tracing/SW/Receiver_DPTI/script.py @@ -0,0 +1,59 @@ +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales + +#Script to plot data from run_timeout.sh aquisition with receiver + +import sys +import matplotlib.pyplot as plt + +def parse_log(file_path): + nr_pkts = [] + throughputs = [] + with open(file_path) as f: + for line in f: + line = line.strip() + if not line or ':' not in line or line.startswith('NR_PKT'): + continue + try: + pkt_str, tp_str = line.split(':') + pkt = int(pkt_str.strip()) + tp = float(tp_str.strip()) + nr_pkts.append(pkt) + throughputs.append(tp) + except ValueError: + continue + return nr_pkts, throughputs + +def main(): + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + log_file = sys.argv[1] + nr_pkts, throughputs = parse_log(log_file) + + if not nr_pkts: + print("Aucune donnée valide trouvée dans le fichier.") + sys.exit(1) + + print("\nNR_PKT\tThroughput (Mb/s)") + for pkt, tp in zip(nr_pkts, throughputs): + print(f"{pkt}\t{tp}") + + plt.figure() + plt.plot(nr_pkts, throughputs, marker='o') + plt.xlabel("Nombre de paquets (NR_PKT)") + plt.ylabel("Throughput (Mb/s)") + plt.title("NR_PKT vs Throughput") + plt.grid(True) + plt.tight_layout() + plt.show() + +if __name__ == "__main__": + main() diff --git a/corev_apu/instr_tracing/SW/Receiver_DPTI/to_script.sh b/corev_apu/instr_tracing/SW/Receiver_DPTI/to_script.sh new file mode 100644 index 0000000000..3dcaa82005 --- /dev/null +++ b/corev_apu/instr_tracing/SW/Receiver_DPTI/to_script.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales +capture_fct() { + ./Receiver_DPTI & + PID=$! + sleep 5 + kill -SIGINT "$PID" + sleep 2 +} + +NR_PKTS=(10 20 50 100 200) + +for i in "${NR_PKTS[@]}"; do + echo "=== $i ===" + + sed -i "s/const int NR_PKT = [0-9]\+;/const int NR_PKT = $i;/" Receiver_DPTI.cpp + make -s + capture_fct >> log2.txt + +done diff --git a/corev_apu/instr_tracing/rv_encapsulator-main/LICENSE b/corev_apu/instr_tracing/rv_encapsulator-main/LICENSE new file mode 100644 index 0000000000..3931d9e54f --- /dev/null +++ b/corev_apu/instr_tracing/rv_encapsulator-main/LICENSE @@ -0,0 +1,176 @@ +SOLDERPAD HARDWARE LICENSE version 0.51 + +This license is based closely on the Apache License Version 2.0, but is not +approved or endorsed by the Apache Foundation. A copy of the non-modified +Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. + +As this license is not currently OSI or FSF approved, the Licensor permits any +Work licensed under this License, at the option of the Licensee, to be treated +as licensed under the Apache License Version 2.0 (which is so approved). + +This License is licensed under the terms of this License and in particular +clause 7 below (Disclaimer of Warranties) applies in relation to its use. + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the Rights owner or entity authorized by the Rights owner +that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Rights" means copyright and any similar right including design right (whether +registered or unregistered), semiconductor topography (mask) rights and +database rights (but excluding Patents and Trademarks). + +"Source" form shall mean the preferred form for making modifications, including +but not limited to source code, net lists, board layouts, CAD files, +documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object +code, generated documentation, the instantiation of a hardware design and +conversions to other media types, including intermediate forms such as +bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask +works). + +"Work" shall mean the work of authorship, whether in Source form or other +Object form, made available under the License, as indicated by a Rights notice +that is included in or attached to the work (an example is provided in the +Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) or physically connect to or interoperate with the interfaces of, the Work +and Derivative Works thereof. + +"Contribution" shall mean any design or work of authorship, including the +original version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the Rights owner or by an individual or Legal Entity +authorized to submit on behalf of the Rights owner. For the purposes of this +definition, "submitted" means any form of electronic, verbal, or written +communication sent to the Licensor or its representatives, including but not +limited to communication on electronic mailing lists, source code control +systems, and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated in writing +by the Rights owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable license under the Rights to reproduce, +prepare Derivative Works of, publicly display, publicly perform, sublicense, +and distribute the Work and such Derivative Works in Source or Object form and +do anything in relation to the Work as if the Rights did not exist. + +3. Grant of Patent License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this +section) patent license to make, have made, use, offer to sell, sell, import, +and otherwise transfer the Work, where such license applies only to those +patent claims licensable by such Contributor that are necessarily infringed by +their Contribution(s) alone or by combination of their Contribution(s) with the +Work to which such Contribution(s) was submitted. If You institute patent +litigation against any entity (including a cross-claim or counterclaim in a +lawsuit) alleging that the Work or a Contribution incorporated within the Work +constitutes direct or contributory patent infringement, then any patent +licenses granted to You under this License for that Work shall terminate as of +the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or +Derivative Works thereof in any medium, with or without modifications, and in +Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy + of this License; and + + You must cause any modified files to carry prominent notices stating that + You changed the files; and + + You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices from + the Source form of the Work, excluding those notices that do not pertain to + any part of the Derivative Works; and + + If the Work includes a "NOTICE" text file as part of its distribution, then + any Derivative Works that You distribute must include a readable copy of + the attribution notices contained within such NOTICE file, excluding those + notices that do not pertain to any part of the Derivative Works, in at + least one of the following places: within a NOTICE text file distributed as + part of the Derivative Works; within the Source form or documentation, if + provided along with the Derivative Works; or, within a display generated by + the Derivative Works, if and wherever such third-party notices normally + appear. The contents of the NOTICE file are for informational purposes only + and do not modify the License. You may add Your own attribution notices + within Derivative Works that You distribute, alongside or as an addendum to + the NOTICE text from the Work, provided that such additional attribution + notices cannot be construed as modifying the License. You may add Your own + copyright statement to Your modifications and may provide additional or + different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works as a + whole, provided Your use, reproduction, and distribution of the Work + otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any +Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without any +additional terms or conditions. Notwithstanding the above, nothing herein shall +supersede or modify the terms of any separate license agreement you may have +executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in +writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied, including, without limitation, any warranties +or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in +tort (including negligence), contract, or otherwise, unless required by +applicable law (such as deliberate and grossly negligent acts) or agreed to in +writing, shall any Contributor be liable to You for damages, including any +direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of the use or inability to +use the Work (including but not limited to damages for loss of goodwill, work +stoppage, computer failure or malfunction, or any and all other commercial +damages or losses), even if such Contributor has been advised of the +possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or +Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations +and/or rights consistent with this License. However, in accepting such +obligations, You may act only on Your own behalf and on Your sole +responsibility, not on behalf of any other Contributor, and only if You agree +to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_encapsulator-main/README.md b/corev_apu/instr_tracing/rv_encapsulator-main/README.md new file mode 100644 index 0000000000..6668722375 --- /dev/null +++ b/corev_apu/instr_tracing/rv_encapsulator-main/README.md @@ -0,0 +1,2 @@ +The encapsulator is a modified version of https://github.com/pulp-platform/rv_encapsulator +This directory (`rv_encapsulator-main`) is temporary and will soon be replaced by a submodule. \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_encapsulator-main/src/include/encap_pkg.sv b/corev_apu/instr_tracing/rv_encapsulator-main/src/include/encap_pkg.sv new file mode 100644 index 0000000000..32af59527f --- /dev/null +++ b/corev_apu/instr_tracing/rv_encapsulator-main/src/include/encap_pkg.sv @@ -0,0 +1,50 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/* +all the type associated params are commented because the type is not required for trace encoders +supporting only instruction tracing +*/ + +package encap_pkg; + + localparam H_LEN = 8; // header length + //localparam SRCID_LEN = 7; // not used because only one source in system + //localparam TYPE_LEN = 8; + localparam PAYLOAD_LEN = 248 /*- TYPE_LEN - (SRCID_LEN % 8)*/; // trace_payload_len + localparam T_LEN = 64; // timestamp length: mcycle length is always 64 + localparam FLOW_LEN = 2; + localparam P_LEN = 5; + localparam MAX_LEN = 264; // max length for payload to slice + + typedef struct packed { + logic extend; + logic [FLOW_LEN-1:0] flow; + logic [P_LEN-1:0] length; + } header_s; + + typedef struct packed { + //logic [TYPE_LEN-1:0] type; // omitted because only instruction trace available + logic [PAYLOAD_LEN-1:0] trace_payload; + } payload_s; + + typedef struct packed { + header_s header; + //logic [SRCID_LEN-1:0] srcid; + logic [T_LEN-1:0] timestamp; + payload_s payload; + } encap_fifo_entry_s; + +endpackage \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_encapsulator-main/src/rtl/encapsulator.sv b/corev_apu/instr_tracing/rv_encapsulator-main/src/rtl/encapsulator.sv new file mode 100644 index 0000000000..e93c8ba864 --- /dev/null +++ b/corev_apu/instr_tracing/rv_encapsulator-main/src/rtl/encapsulator.sv @@ -0,0 +1,75 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/* ENCAPSULATOR */ +/* +this module generates the header and payload necessary based on the protocol used +*/ + +module encapsulator ( + // inputs + input logic clk_i, + input logic valid_i, + input logic [encap_pkg::P_LEN-1:0] packet_length_i, + input logic [encap_pkg::FLOW_LEN-1:0] flow_i, + input logic timestamp_present_i, + //input logic srcid_i, + input logic [encap_pkg::T_LEN-1:0] timestamp_i, + //input logic [encap_pkg::TYPE_LEN-1:0] type_i, + input logic [encap_pkg::PAYLOAD_LEN-1:0] trace_payload_i, + + // outputs + output logic valid_o, + output encap_pkg::encap_fifo_entry_s encap_fifo_entry_o +); + // pragma translate_off + int f; + initial begin + f = $fopen("encaps.traces", "w"); + end + final $fclose(f); + // pragma translate_on + +always_comb begin + // initialization + valid_o = '0; + encap_fifo_entry_o = '0; + + // assignments + if (valid_i) begin + valid_o = '1; + // header + encap_fifo_entry_o.header.length = packet_length_i; + encap_fifo_entry_o.header.flow = flow_i; + encap_fifo_entry_o.header.extend = timestamp_present_i; + // srcID + //encap_fifo_entry_o.srcid = srcid_i; + // timestamp + encap_fifo_entry_o.timestamp = timestamp_i; + // payload + encap_fifo_entry_o.payload.trace_payload = trace_payload_i; + end +end +// pragma translate_off +always_ff @(posedge clk_i) begin + if (valid_o) begin + $fwrite( + f, + "%h\n",encap_fifo_entry_o); + end +end +// pragma translate_on + +endmodule \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/LICENSE b/corev_apu/instr_tracing/rv_tracer-main/LICENSE new file mode 100644 index 0000000000..3931d9e54f --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/LICENSE @@ -0,0 +1,176 @@ +SOLDERPAD HARDWARE LICENSE version 0.51 + +This license is based closely on the Apache License Version 2.0, but is not +approved or endorsed by the Apache Foundation. A copy of the non-modified +Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. + +As this license is not currently OSI or FSF approved, the Licensor permits any +Work licensed under this License, at the option of the Licensee, to be treated +as licensed under the Apache License Version 2.0 (which is so approved). + +This License is licensed under the terms of this License and in particular +clause 7 below (Disclaimer of Warranties) applies in relation to its use. + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the Rights owner or entity authorized by the Rights owner +that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Rights" means copyright and any similar right including design right (whether +registered or unregistered), semiconductor topography (mask) rights and +database rights (but excluding Patents and Trademarks). + +"Source" form shall mean the preferred form for making modifications, including +but not limited to source code, net lists, board layouts, CAD files, +documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object +code, generated documentation, the instantiation of a hardware design and +conversions to other media types, including intermediate forms such as +bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask +works). + +"Work" shall mean the work of authorship, whether in Source form or other +Object form, made available under the License, as indicated by a Rights notice +that is included in or attached to the work (an example is provided in the +Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) or physically connect to or interoperate with the interfaces of, the Work +and Derivative Works thereof. + +"Contribution" shall mean any design or work of authorship, including the +original version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the Rights owner or by an individual or Legal Entity +authorized to submit on behalf of the Rights owner. For the purposes of this +definition, "submitted" means any form of electronic, verbal, or written +communication sent to the Licensor or its representatives, including but not +limited to communication on electronic mailing lists, source code control +systems, and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated in writing +by the Rights owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable license under the Rights to reproduce, +prepare Derivative Works of, publicly display, publicly perform, sublicense, +and distribute the Work and such Derivative Works in Source or Object form and +do anything in relation to the Work as if the Rights did not exist. + +3. Grant of Patent License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this +section) patent license to make, have made, use, offer to sell, sell, import, +and otherwise transfer the Work, where such license applies only to those +patent claims licensable by such Contributor that are necessarily infringed by +their Contribution(s) alone or by combination of their Contribution(s) with the +Work to which such Contribution(s) was submitted. If You institute patent +litigation against any entity (including a cross-claim or counterclaim in a +lawsuit) alleging that the Work or a Contribution incorporated within the Work +constitutes direct or contributory patent infringement, then any patent +licenses granted to You under this License for that Work shall terminate as of +the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or +Derivative Works thereof in any medium, with or without modifications, and in +Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy + of this License; and + + You must cause any modified files to carry prominent notices stating that + You changed the files; and + + You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices from + the Source form of the Work, excluding those notices that do not pertain to + any part of the Derivative Works; and + + If the Work includes a "NOTICE" text file as part of its distribution, then + any Derivative Works that You distribute must include a readable copy of + the attribution notices contained within such NOTICE file, excluding those + notices that do not pertain to any part of the Derivative Works, in at + least one of the following places: within a NOTICE text file distributed as + part of the Derivative Works; within the Source form or documentation, if + provided along with the Derivative Works; or, within a display generated by + the Derivative Works, if and wherever such third-party notices normally + appear. The contents of the NOTICE file are for informational purposes only + and do not modify the License. You may add Your own attribution notices + within Derivative Works that You distribute, alongside or as an addendum to + the NOTICE text from the Work, provided that such additional attribution + notices cannot be construed as modifying the License. You may add Your own + copyright statement to Your modifications and may provide additional or + different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works as a + whole, provided Your use, reproduction, and distribution of the Work + otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any +Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without any +additional terms or conditions. Notwithstanding the above, nothing herein shall +supersede or modify the terms of any separate license agreement you may have +executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in +writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied, including, without limitation, any warranties +or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in +tort (including negligence), contract, or otherwise, unless required by +applicable law (such as deliberate and grossly negligent acts) or agreed to in +writing, shall any Contributor be liable to You for damages, including any +direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of the use or inability to +use the Work (including but not limited to damages for loss of goodwill, work +stoppage, computer failure or malfunction, or any and all other commercial +damages or losses), even if such Contributor has been advised of the +possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or +Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations +and/or rights consistent with this License. However, in accepting such +obligations, You may act only on Your own behalf and on Your sole +responsibility, not on behalf of any other Contributor, and only if You agree +to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/README.md b/corev_apu/instr_tracing/rv_tracer-main/README.md new file mode 100644 index 0000000000..b9a88a29eb --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/README.md @@ -0,0 +1,2 @@ +The encoder is a modified version of https://github.com/pulp-platform/rv_tracer +This directory (`rv_tracer-main`) is temporary and will soon be replaced by a submodule. \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/include/te_pkg.sv b/corev_apu/instr_tracing/rv_tracer-main/include/te_pkg.sv new file mode 100644 index 0000000000..fefb0053a6 --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/include/te_pkg.sv @@ -0,0 +1,187 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +// uncomment to enable 64bits arch support +// `define TE_ARCH64 + +package te_pkg; + localparam PRIV_LEN = 2; // depends on CPU implementation + localparam INST_LEN = 32; + localparam PTYPE_LEN = 4; // is it F + SF? spec not clear + localparam P_LEN = 5; + localparam PAYLOAD_LEN = 248; + localparam TRIGGER_LEN = 4; + localparam CTYPE_LEN = 2; +`ifdef TE_ARCH64 // 64bit arch specific parameters + localparam XLEN = 64; + // APB addresses to access registers + // the value is added to the peripheral address + /* FILTER */ + // cause + localparam CAUSE_UPPER = 8'h5; + localparam CAUSE_LOWER = 8'h6; + localparam CAUSE_MATCH = 8'h7; + // tvec + localparam TVEC_UPPER_L = 8'h8; // least significant bits + localparam TVEC_UPPER_M = 8'h9; // most significant bits + localparam TVEC_LOWER_L = 8'ha; // least significant bits + localparam TVEC_LOWER_M = 8'hb; // most significant bits + localparam TVEC_MATCH_L = 8'hc; // least significant bits + localparam TVEC_MATCH_M = 8'hd; // most significant bits + // tval + localparam TVAL_UPPER_L = 8'he; // least significant bits + localparam TVAL_UPPER_M = 8'hf; // most significant bits + localparam TVAL_LOWER_L = 8'h10; // least significant bits + localparam TVAL_LOWER_M = 8'h11; // most significant bits + localparam TVAL_MATCH_L = 8'h12; // least significant bits + localparam TVAL_MATCH_M = 8'h13; // most significant bits + // iaddr + localparam IADDR_UPPER_L = 8'h16; // least significant bits + localparam IADDR_UPPER_M = 8'h17; // most significant bits + localparam IADDR_LOWER_L = 8'h18; // least significant bits + localparam IADDR_LOWER_M = 8'h19; // most significant bits + localparam IADDR_MATCH_L = 8'h1a; // least significant bits + localparam IADDR_MATCH_M = 8'h1b; // most significant bits +`else // 32bit arch + localparam XLEN = 32; + // APB addresses to access registers + // APB addresses to access registers + // the value is added to the peripheral address + /* FILTER */ + // cause + localparam CAUSE_UPPER = 8'h5; + localparam CAUSE_LOWER = 8'h6; + localparam CAUSE_MATCH = 8'h7; + // tvec + localparam TVEC_UPPER = 8'h8; + localparam TVEC_LOWER = 8'ha; + localparam TVEC_MATCH = 8'hc; + // tval + localparam TVAL_UPPER = 8'he; + localparam TVAL_LOWER = 8'h10; + localparam TVAL_MATCH = 8'h12; + // iaddr + localparam IADDR_UPPER = 8'h16; + localparam IADDR_LOWER = 8'h18; + localparam IADDR_MATCH = 8'h1a; +`endif + /* both archs parameters */ + // localparams for resync counter + localparam CYCLE_MODE = 0; + localparam PACKET_MODE = 1; + // localparams for irreport and irdepth + localparam CALL_COUNTER_SIZE = '0; + localparam RETURN_STACK_SIZE = '0; + // localparams for branch map - defined by spec + localparam BRANCH_MAP_LEN = 31; + localparam BRANCH_COUNT_LEN = 5; + // localparams for filter mode + localparam RANGE_MODE = 1'b0; + localparam EQUAL_MODE = 1'b1; + // localparam for time signal + localparam TIME_LEN = 64; + // localparam for itype + localparam ITYPE_LEN = 3; + // localparam for iretire + localparam IRETIRE_LEN = 32; + + // common APB addresses to access registers + /* FILTER */ + // input and mode + localparam CAUSE_ENABLE_MODE = 8'h0; + localparam TVEC_ENABLE_MODE = 8'h1; + localparam TVAL_ENABLE_MODE = 8'h2; + localparam PRIV_ENABLE_MODE = 8'h3; + localparam IADDR_ENABLE_MODE = 8'h4; + // priv + localparam PRIV_RANGE = 8'h14; + localparam PRIV_MATCH = 8'h15; + /* TRACE MANAGEMENT */ + localparam TRACE_STATE = 8'h1c; + localparam LOSSLESS_TRACE = 8'h1d; + localparam SHALLOW_TRACE = 8'h1e; + /* PACKET EMITTER */ + localparam NO_TIME = 8'h1f; + localparam NO_CONTEXT = 8'h20; + localparam DELTA_ADDRESS = 8'h21; + localparam FULL_ADDRESS = 8'h22; + localparam IMPLICIT_EXCEPTION = 8'h23; + localparam SIJUMP = 8'h24; + localparam IMPLICIT_RETURN = 8'h25; + localparam BRANCH_PREDICTION = 8'h26; + localparam JUMP_TARGET_CACHE = 8'h27; + +// packet types +typedef enum logic[1:0] { + F_OPT_EXT = 2'h0, + F_DIFF_DELTA = 2'h1, + F_ADDR_ONLY = 2'h2, + F_SYNC = 2'h3 +} format_e; + +// subformats available for type 3 packets (F_SYNC) +typedef enum logic[1:0] { + SF_START = 2'h0, + SF_TRAP = 2'h1, + SF_CONTEXT = 2'h2, + SF_SUPPORT = 2'h3 +} f_sync_subformat_e; + +// subformats available for type 0 packets (F_OPT_EXT) +// used a struct for future extensions +typedef enum logic[0:0] { + SF_PBC = 1'h0, // correctly predicted branches + SF_JTC = 1'h1 // jump target cache in spec +} f_opt_ext_subformat_e; + +// qual_status values necessary for format 3 subformat 3 +// packet payload +typedef enum logic[1:0] { + NO_CHANGE = 2'h0, + ENDED_REP = 2'h1, + TRACE_LOST = 2'h2, + ENDED_NTR = 2'h3 +} qual_status_e; + +// struct to determine the ioptions enabled/disabled +// for format 3 subformat 3 packets +typedef struct packed { + logic delta_address_en; + logic full_address_en; + logic implicit_exception_en; + logic sijump_en; + logic implicit_return_en; + logic branch_prediction_en; + logic jump_target_cache_en; +} ioptions_s; + +// enum that expresses the packet format and +// subformat to better readability +typedef enum logic[3:0] { + F0SF0 = 4'h0, + F0SF1 = 4'h1, + F1 = 4'h4, + F2 = 4'h8, + F3SF0 = 4'hC, + F3SF1 = 4'hD, + F3SF2 = 4'hE, + F3SF3 = 4'hF +} it_packet_type_e; // "it" stands for "instruction trace" + +/*TODO: + doptions struct for data tracing + refer to page 36 of the spec */ + +endpackage \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/rtl/lzc.sv b/corev_apu/instr_tracing/rv_tracer-main/rtl/lzc.sv new file mode 100644 index 0000000000..f28730ac7f --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/rtl/lzc.sv @@ -0,0 +1,106 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// `include "common_cells/assertions.svh" + +/// A trailing zero counter / leading zero counter. +/// Set MODE to 0 for trailing zero counter => cnt_o is the number of trailing zeros (from the LSB) +/// Set MODE to 1 for leading zero counter => cnt_o is the number of leading zeros (from the MSB) +/// If the input does not contain a zero, `empty_o` is asserted. Additionally `cnt_o` contains +/// the maximum number of zeros - 1. For example: +/// in_i = 000_0000, empty_o = 1, cnt_o = 6 (mode = 0) +/// in_i = 000_0001, empty_o = 0, cnt_o = 0 (mode = 0) +/// in_i = 000_1000, empty_o = 0, cnt_o = 3 (mode = 0) +/// Furthermore, this unit contains a more efficient implementation for Verilator (simulation only). +/// This speeds up simulation significantly. +module lzc #( + /// The width of the input vector. + parameter int unsigned WIDTH = 2, + /// Mode selection: 0 -> trailing zero, 1 -> leading zero + parameter bit MODE = 1'b0, + /// Dependent parameter. Do **not** change! + /// + /// Width of the output signal with the zero count. + parameter int unsigned CNT_WIDTH = cf_math_pkg::idx_width(WIDTH) +) ( + /// Input vector to be counted. + input logic [WIDTH-1:0] in_i, + /// Count of the leading / trailing zeros. + output logic [CNT_WIDTH-1:0] cnt_o, + /// Counter is empty: Asserted if all bits in in_i are zero. + output logic empty_o +); + + if (WIDTH == 1) begin : gen_degenerate_lzc + + assign cnt_o[0] = !in_i[0]; + assign empty_o = !in_i[0]; + + end else begin : gen_lzc + + localparam int unsigned NumLevels = $clog2(WIDTH); + + // `ifndef COMMON_CELLS_ASSERTS_OFF + // `ASSERT_INIT(width_0, WIDTH > 0, "input must be at least one bit wide") + // `endif + + logic [WIDTH-1:0][NumLevels-1:0] index_lut; + logic [2**NumLevels-1:0] sel_nodes; + logic [2**NumLevels-1:0][NumLevels-1:0] index_nodes; + + logic [WIDTH-1:0] in_tmp; + + // reverse vector if required + always_comb begin : flip_vector + for (int unsigned i = 0; i < WIDTH; i++) begin + in_tmp[i] = (MODE) ? in_i[WIDTH-1-i] : in_i[i]; + end + end + + for (genvar j = 0; unsigned'(j) < WIDTH; j++) begin : g_index_lut + assign index_lut[j] = (NumLevels)'(unsigned'(j)); + end + + for (genvar level = 0; unsigned'(level) < NumLevels; level++) begin : g_levels + if (unsigned'(level) == NumLevels - 1) begin : g_last_level + for (genvar k = 0; k < 2 ** level; k++) begin : g_level + // if two successive indices are still in the vector... + if (unsigned'(k) * 2 < WIDTH - 1) begin : g_reduce + assign sel_nodes[2 ** level - 1 + k] = in_tmp[k * 2] | in_tmp[k * 2 + 1]; + assign index_nodes[2 ** level - 1 + k] = (in_tmp[k * 2] == 1'b1) + ? index_lut[k * 2] : + index_lut[k * 2 + 1]; + end + // if only the first index is still in the vector... + if (unsigned'(k) * 2 == WIDTH - 1) begin : g_base + assign sel_nodes[2 ** level - 1 + k] = in_tmp[k * 2]; + assign index_nodes[2 ** level - 1 + k] = index_lut[k * 2]; + end + // if index is out of range + if (unsigned'(k) * 2 > WIDTH - 1) begin : g_out_of_range + assign sel_nodes[2 ** level - 1 + k] = 1'b0; + assign index_nodes[2 ** level - 1 + k] = '0; + end + end + end else begin : g_not_last_level + for (genvar l = 0; l < 2 ** level; l++) begin : g_level + assign sel_nodes[2 ** level - 1 + l] = + sel_nodes[2 ** (level + 1) - 1 + l * 2] | sel_nodes[2 ** (level + 1) - 1 + l * 2 + 1]; + assign index_nodes[2 ** level - 1 + l] = (sel_nodes[2 ** (level + 1) - 1 + l * 2] == 1'b1) + ? index_nodes[2 ** (level + 1) - 1 + l * 2] : + index_nodes[2 ** (level + 1) - 1 + l * 2 + 1]; + end + end + end + + assign cnt_o = NumLevels > unsigned'(0) ? index_nodes[0] : {($clog2(WIDTH)) {1'b0}}; + assign empty_o = NumLevels > unsigned'(0) ? ~sel_nodes[0] : ~(|in_i); + + end : gen_lzc + +// `ifndef COMMON_CELLS_ASSERTS_OFF +// `ASSERT_INIT(width_0, WIDTH >= 1, "The WIDTH must at least be one bit wide!") +// `endif + +endmodule : lzc diff --git a/corev_apu/instr_tracing/rv_tracer-main/rtl/rv_tracer.sv b/corev_apu/instr_tracing/rv_tracer-main/rtl/rv_tracer.sv new file mode 100644 index 0000000000..72e2c96205 --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/rtl/rv_tracer.sv @@ -0,0 +1,911 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/* TOP LEVEL MODULE */ + +module rv_tracer #( + //parameter IRETIRE_LEN = 32, // set to 1 for single retirement + parameter N = 1, // max number of special inst retired in a cycle, the input port number depends on this value + parameter ONLY_BRANCHES = 0, // special inst are branches or not + parameter APB_ADDR_WIDTH = 32 // address width for APB interface +) +( + input logic clk_i, + input logic rst_ni, + + input logic [N-1:0] valid_i, // used for multiple retirement + + /* data from the CPU */ + // mandatory inputs + input logic [N-1:0][te_pkg::ITYPE_LEN-1:0] itype_i, // termination type of block + input logic [te_pkg::XLEN-1:0] cause_i, + input logic [te_pkg::XLEN-1:0] tval_i, + input logic [te_pkg::PRIV_LEN-1:0] priv_i, + input logic [N-1:0][te_pkg::XLEN-1:0] iaddr_i, // pc of 1st inst in block + input logic [N-1:0][te_pkg::IRETIRE_LEN-1:0] iretire_i, // length of block in halfwords + input logic [N-1:0] ilastsize_i, // length of last inst in 2^ilastsize halfword + // non mandatory inputs + input logic [te_pkg::TIME_LEN-1:0] time_i, + //input logic [:0] context_i, + //input logic [te_pkg::CTYPE_LEN-1:0] ctype_i, // spec says it's 1 or 2 bit wide + //input logic [te_pkg::TRIGGER_LEN-1:0] trigger_i, // must be supported CPU side + + // support inputs + input logic [te_pkg::XLEN-1:0] tvec_i, // tvec_q, contains trap handler address + input logic [te_pkg::XLEN-1:0] epc_i, // epc_q, required for format 3 subformat 1 + input logic encapsulator_ready_i, // non mandatory + + // APB interface inputs + input logic [APB_ADDR_WIDTH-1:0] paddr_i, + input logic pwrite_i, + input logic psel_i, + input logic penable_i, + input logic [31:0] pwdata_i, + + // outputs + // info needed for the encapsulator + output logic [N-1:0] packet_valid_o, + output te_pkg::it_packet_type_e [N-1:0] packet_type_o, + output logic [N-1:0][te_pkg::P_LEN-1:0] packet_length_o, // in bytes + output logic [N-1:0][te_pkg::PAYLOAD_LEN-1:0] packet_payload_o, + // sideband signals + output logic stall_o, + + // APB interface outputs + output logic pready_o, + output logic [31:0] prdata_o +); + + /* signals for management */ + // registers + logic trace_activated; + logic trace_enable; + logic nocontext; + logic notime; + logic encoder_mode; + // filter + logic trigger_trace_on; // hardwired to 0? + logic trigger_trace_off; // hardwired to 0? + //logic qualified; // is it needed or I can use qualified_d? + logic trace_req_deactivate; + // priority + te_pkg::format_e packet_format[N-1:0]; + te_pkg::f_sync_subformat_e packet_f_sync_subformat[N-1:0]; + te_pkg::f_opt_ext_subformat_e packet_f_opt_ext_subformat[N-1:0]; + logic thaddr[N-1:0]; + logic lc_tc_mux[N-1:0]; + te_pkg::qual_status_e qual_status[N-1:0]; + logic nc_branch_map_flush; + logic [te_pkg::BRANCH_MAP_LEN-1:0] branch_map; + logic [te_pkg::BRANCH_COUNT_LEN-1:0] branch_count; + logic resync_rst; + // packet emitter + logic packet_valid[N-1:0]; + // resync counter + logic [N-1:0] packet_emitted; + // not classified + logic nc_branch_map_empty; + logic clk_gated; + logic turn_on_tracer_d, turn_on_tracer_q; + logic lossless_trace; + logic shallow_trace; + + // we have three phases, called last cycle (lc), this cycle (tc) and next + // cycle (nc), based on which we make decision whether we need to emit a + // packet or not. + logic tc_branch_map_empty; + logic [N-1:0] tc_resync; + logic [N-1:0] nc_exc_only; + logic [N-1:0] nc_ppccd_br; + logic [$clog2(te_pkg::XLEN):0] keep_bits[N-1:0]; + logic [te_pkg::XLEN-1:0] addr_to_compress[N-1:0]; + + logic [1:0][N-1:0][te_pkg::IRETIRE_LEN-1:0] iretired_tab; + logic [2:0] exception_tab; + logic [2:0] interrupt_tab; + logic [2:0][te_pkg::XLEN-1:0] cause_tab; + logic [1:0][te_pkg::XLEN-1:0] tvec_tab; + logic [2:0][te_pkg::XLEN-1:0] tval_tab; + logic [1:0][N-1:0][te_pkg::ITYPE_LEN-1:0] itype_tab; + logic [1:0][te_pkg::PRIV_LEN-1:0] priv_tab; + logic [1:0][N-1:0][te_pkg::XLEN-1:0] address_tab; + logic [2:0][te_pkg::XLEN-1:0] epc_tab; + logic [1:0][te_pkg::TIME_LEN-1:0] time_tab; + logic [2:0][N-1:0] updiscon_tab; + logic [2:0][N-1:0] qualified_tab; + + logic [N-1:0][te_pkg::IRETIRE_LEN-1:0] tc_iretired, nc_iretired; + logic lc_exception, tc_exception, nc_exception; + logic lc_interrupt, tc_interrupt, nc_interrupt; + logic [te_pkg::XLEN-1:0] lc_cause, tc_cause, nc_cause; + logic [te_pkg::XLEN-1:0] tc_tvec, nc_tvec; + logic [te_pkg::XLEN-1:0] lc_tval, tc_tval, nc_tval; + logic [N-1:0][te_pkg::ITYPE_LEN-1:0] tc_itype, nc_itype; + logic [te_pkg::PRIV_LEN-1:0] tc_priv, nc_priv; + logic [N-1:0][te_pkg::XLEN-1:0] tc_address, nc_address; + logic [te_pkg::XLEN-1:0] lc_epc, tc_epc, nc_epc; + logic [te_pkg::TIME_LEN-1:0] tc_time, nc_time; + logic [N-1:0] lc_updiscon, tc_updiscon, nc_updiscon; + logic [N-1:0] lc_qualified, tc_qualified, nc_qualified; + + + logic tc_first_qualified; + logic tc_final_qualified; + logic [N-1:0] updiscon; + logic [N-1:0][te_pkg::XLEN-1:0] address; + logic [N-1:0] qualified; + + + logic [N-1:0] valid0_d, valid0_q; + logic privchange_d, privchange_q; + // logic context_change_d, context_change_q; // non mandatory + // logic precise_context_report_d, precise_context_report_q; // requires ctype signal CPU side + // logic context_report_as_disc_d, context_report_as_disc_q; // ibidem + // logic no_context_report_d, no_context_report_q; // ibidem + // logic imprecise_context_report_d, imprecise_context_report_q; // ibidem + logic gt_max_resync_d, gt_max_resync_q; + logic et_max_resync_d, et_max_resync_q; + logic branch_map_full_d, branch_map_full_q; + //logic branch_misprediction_d, branch_misprediction_q; // non mandatory + logic trace_activated_d, trace_activated_q; + logic enc_activated_d, enc_activated_q; + logic enc_deactivated_d, enc_deactivated_q; + //logic packets_lost_d, packets_lost_q; // non mandatory + te_pkg::ioptions_s enc_config_d, enc_config_q; + logic enc_config_change_d, enc_config_change_q; + logic branch_d, branch_q; + logic branch_taken_d, branch_taken_q; + + // branch_map inputs + logic [N-1:0] branch_valid; + logic [N-1:0] branch_taken; + + // te_reg output to filter input + logic cause_filter; + logic [te_pkg::XLEN-1:0] upper_cause; + logic [te_pkg::XLEN-1:0] lower_cause; + logic [te_pkg::XLEN-1:0] match_cause; + logic cause_mode; + logic tvec_filter; + logic [te_pkg::XLEN-1:0] upper_tvec; + logic [te_pkg::XLEN-1:0] lower_tvec; + logic [te_pkg::XLEN-1:0] match_tvec; + logic tvec_mode; + logic tval_filter; + logic [te_pkg::XLEN-1:0] upper_tval; + logic [te_pkg::XLEN-1:0] lower_tval; + logic [te_pkg::XLEN-1:0] match_tval; + logic tval_mode; + logic priv_lvl_filter; + logic [te_pkg::PRIV_LEN-1:0] upper_priv; + logic [te_pkg::PRIV_LEN-1:0] lower_priv; + logic [te_pkg::PRIV_LEN-1:0] match_priv; + logic priv_lvl_mode; + logic iaddr_filter; + logic [te_pkg::XLEN-1:0] upper_iaddr; + logic [te_pkg::XLEN-1:0] lower_iaddr; + logic [te_pkg::XLEN-1:0] match_iaddr; + logic iaddr_mode; + + /* the following commented section has non mandatory signals + for now it's commented + */ + /* combinatorial network to define the following + signals from ctype: + - tc_no_context_report_i -> ctype == 0 + - tc_precise_context_report_i -> ctype == 2 + - tc_context_report_as_disc_i -> ctype == 3 + - tc_imprecise_context_report_i -> ctype == 1 + - nc_precise_context_report_i -> ctype == 2 + - nc_context_report_as_disc_i -> ctype == 3*/ + /* + always_comb begin : ctype_manager + case(ctype_i) + 2'h0: // no report - add signal + tc_no_context_report = '1; + 2'h1: + tc_imprecise_context_report = '1; + 2'h2: + tc_precise_context_report = '1; + 2'h3: + tc_context_report_as_disc = '1; + endcase + end + */ + + /*TODO: create a trigger decoder that produces: + - trigger_trace_on -> 2 + - trigger_trace_off -> 3 + - trigger_notify -> 4 + */ + // maybe it's enough to define values and hardwire them to 0 + + /* ASSIGNMENT */ + /* hardwired assignments */ + assign trigger_trace_on = '0; + assign trigger_trace_off = '0; + + /* FFs inputs */ + assign valid0_d = valid_i; + assign trace_activated_d = trace_activated; + assign enc_activated_d = trace_activated_d && ~trace_activated_q; + assign enc_deactivated_d = ~trace_activated_d && trace_activated_q; + assign enc_config_change_d = enc_config_d != enc_config_q; + + /* next cycle */ + assign nc_branch_map_empty = nc_branch_map_flush || (tc_branch_map_empty /*&& ~branch_q*/); + + // output + assign packet_valid_o = packet_emitted; + // sideband + assign stall_o = ~encapsulator_ready_i && lossless_trace; + + // other + assign branch_taken_d = |branch_taken; + + // first and final qualified + assign tc_first_qualified = trace_activated && |tc_qualified && !lc_qualified && trace_enable; + assign tc_final_qualified = trace_activated && |lc_qualified && !tc_qualified && trace_enable; + + always_ff @( posedge clk_i, negedge rst_ni ) begin + if(~rst_ni) begin + iretired_tab <= '0; + exception_tab <= '0; + interrupt_tab <= '0; + cause_tab <= '0; + tvec_tab <= '0; + tval_tab <= '0; + itype_tab <= '0; + priv_tab <= '0; + address_tab <= '0; + epc_tab <= '0; + time_tab <= '0; + updiscon_tab <= '0; + qualified_tab <= '0; + end else begin + if (|valid_i) begin + iretired_tab <= {iretired_tab[0], iretire_i}; + exception_tab <= {exception_tab[1:0], itype_i[0] == 1}; + interrupt_tab <= {interrupt_tab[1:0], itype_i[0] == 2}; + cause_tab <= {cause_tab[1:0],cause_i}; + tvec_tab <= {tvec_tab[0], tvec_i}; + tval_tab <= {tval_tab [1:0], tval_i}; + itype_tab <= {itype_tab[0], itype_i}; + priv_tab <= {priv_tab[0], priv_i}; + address_tab <= {address_tab[0], address}; + epc_tab <= {epc_tab[1:0], epc_i}; + time_tab <= {time_tab[0], time_i}; + updiscon_tab <= {updiscon_tab[1:0], updiscon}; + qualified_tab <={qualified_tab[1:0], qualified}; + end + end + + end + //lc asignements + assign lc_exception = exception_tab[2]; + assign lc_interrupt = interrupt_tab[2]; + assign lc_cause = cause_tab[2]; + assign lc_tval = tval_tab[2]; + assign lc_epc = epc_tab[2]; + assign lc_updiscon = updiscon_tab[2]; + assign lc_qualified = qualified_tab[2]; + // tc assignements + assign tc_iretired = iretired_tab[1]; + assign tc_exception = exception_tab[1]; + assign tc_interrupt = interrupt_tab[1]; + assign tc_cause= cause_tab[1]; + assign tc_tvec = tvec_tab[1]; + assign tc_tval = tval_tab[1]; + assign tc_itype = itype_tab[1]; + assign tc_priv = priv_tab[1]; + assign tc_address = address_tab[1]; + assign tc_epc = epc_tab[1]; + assign tc_time = time_tab[1]; + assign tc_updiscon = updiscon_tab[1]; + assign tc_qualified = qualified_tab[1]; + + // nc assignements + assign nc_iretired = iretired_tab[0]; + assign nc_exception = exception_tab[0]; + assign nc_interrupt = interrupt_tab[0]; + assign nc_cause= cause_tab[0]; + assign nc_tcvec = tvec_tab[0]; + assign nc_tval = tval_tab[0]; + assign nc_itype = itype_tab[0]; + assign nc_priv = priv_tab[0]; + assign nc_address = address_tab[0]; + assign nc_epc = epc_tab[0]; + assign nc_time = time_tab[0]; + assign nc_updiscon = updiscon_tab[0]; + assign nc_qualified = qualified_tab[0]; + + //FIXME need cleaning + // not static assignments + always_comb begin + // init + branch_valid = '0; + branch_taken = '0; + + privchange_d = privchange_q; + // context_change_d = context_change_q; + // precise_context_report_d = precise_context_report_q; // requires ctype signal CPU side + // context_report_as_disc_d = context_report_as_disc_q; //ibidem + // no_context_report_d = no_context_report_q; // ibidem + // imprecise_context_report_d = imprecise_context_report_q; // ibidem + branch_d = branch_q; + + // itype, iretired and address + // it works for all three cases + for (int i = 0; i < N; i++) begin + if (valid_i[i]) begin + address[i] = iaddr_i[i]; + //FIXME we remove block reconstruction address + //address[i] = iaddr_i[i]+2*(iretire_i[i] - 2**ilastsize_i[i]); + end + end + //FIXME weird timing here nc for erveryone ? + // assigning branch map inputs + for (int i = 0; i < N; i++) begin + if (nc_itype[i] == 4 || nc_itype[i] == 5) begin + branch_valid[i] = '1; + end + if (nc_itype[i] == 5) begin + branch_taken[i] = '1; + end + end + + // updiscon + if (N == 1 || (N > 1 && ONLY_BRANCHES)) begin + if (qualified[0]) begin + updiscon[0] = itype_i[0] == 6; + end + end + // wait for this case + if (N > 1 && !ONLY_BRANCHES) begin + for (int i = 0; i < N; i++) begin + if (qualified[i]) begin + updiscon[i] = itype_i[i] == 6; + end + end + end + + // updating registers values + if (|valid_i) begin + privchange_d = (nc_priv != tc_priv) && |valid_i; + // context_change_d; // TODO + //precise_context_report_d; // requires ctype signal CPU side + //context_report_as_disc_d; //ibidem + //no_context_report_d; // ibidem + //imprecise_context_report_d; // ibidem + branch_d = |branch_valid; + end + + if (!turn_on_tracer_q) begin + turn_on_tracer_d = |valid_i && nc_qualified; + end + end + + /* MODULES INSTANTIATION */ + // one instance for all 3 cases + + + /* MAPPED REGISTERS */ + te_reg #( + .APB_ADDR_WIDTH(APB_ADDR_WIDTH) + ) i_te_reg( + .clk_i (clk_i), + .rst_ni (rst_ni), + .trace_req_off_i ('0), + .trace_req_on_i (turn_on_tracer_q), // trigger_trace_on // from trigger unit + .encapsulator_ready_i(encapsulator_ready_i), + .cause_filter_o (cause_filter), + .upper_cause_o (upper_cause), + .lower_cause_o (lower_cause), + .match_cause_o (match_cause), + .cause_mode_o (cause_mode), + .tvec_filter_o (tvec_filter), + .upper_tvec_o (upper_tvec), + .lower_tvec_o (lower_tvec), + .match_tvec_o (match_tvec), + .tvec_mode_o (tvec_mode), + .tval_filter_o (tval_filter), + .upper_tval_o (upper_tval), + .lower_tval_o (lower_tval), + .match_tval_o (match_tval), + .tval_mode_o (tval_mode), + .priv_lvl_filter_o (priv_lvl_filter), + .upper_priv_o (upper_priv), + .lower_priv_o (lower_priv), + .match_priv_o (match_priv), + .priv_lvl_mode_o (priv_lvl_mode), + .iaddr_filter_o (iaddr_filter), + .upper_iaddr_o (upper_iaddr), + .lower_iaddr_o (lower_iaddr), + .match_iaddr_o (match_iaddr), + .iaddr_mode_o (iaddr_mode), + .trace_enable_o (trace_enable), + .trace_activated_o (trace_activated), + .nocontext_o (nocontext), + .notime_o (notime), + .encoder_mode_o (encoder_mode), + .configuration_o (enc_config_d), + .lossless_trace_o (lossless_trace), + .shallow_trace_o (shallow_trace), + .clk_gated_o (clk_gated), + .paddr_i (paddr_i), + .pwrite_i (pwrite_i), + .psel_i (psel_i), + .penable_i (penable_i), + .pwdata_i (pwdata_i), + .pready_o (pready_o), + .prdata_o (prdata_o) + ); + + /* BRANCH MAP */ + te_branch_map #( + .N(N) + ) i_te_branch_map( + .clk_i (clk_gated), + .rst_ni (rst_ni), + .valid_i (branch_valid & nc_qualified & valid0_q), + .branch_taken_i(branch_taken), + .flush_i (nc_branch_map_flush), + //.branch_taken_prediction_i(), // non mandatory + .map_o (branch_map), + .branches_o (branch_count), + //.pbc_o(), // non mandatory - branch prediction mode + //.misprediction_o(), // non mandatory - ibidem + .is_full_o (branch_map_full_d), + .is_empty_o (tc_branch_map_empty) + ); + + /* RESYNC COUNTER */ + te_resync_counter #( + .N(N), + .MODE(te_pkg::CYCLE_MODE), // count cycles + .MAX_VALUE(13'h1FFF) // 8192 + ) i_te_resync_counter( // for testing we keep the def settings + .clk_i (clk_gated), + .rst_ni (rst_ni), + .trace_enabled_i (trace_enable), + .packet_emitted_i(packet_emitted), + .resync_rst_i (resync_rst), + .gt_resync_max_o (gt_max_resync_d), + .et_resync_max_o (et_max_resync_d) + ); + + // N instances for all 3 cases + + /* FILTER */ + generate + if (ONLY_BRANCHES) begin + for (genvar i = 0; i < N; i++) begin + te_filter i_te_filter( + .trace_enable_i (trace_enable || trace_activated), // tracks 1st branch if 1st inst + .cause_filter_i (cause_filter), + .upper_cause_i (upper_cause), + .lower_cause_i (lower_cause), + .match_cause_i (match_cause), + .cause_mode_i (cause_mode), + .cause_i (cause_i), + .tvec_filter_i (tvec_filter), + .upper_tvec_i (upper_tvec), + .lower_tvec_i (lower_tvec), + .match_tvec_i (match_tvec), + .tvec_mode_i (tvec_mode), + .tvec_i (tvec_i), + .tval_filter_i (tval_filter), + .upper_tval_i (upper_tval), + .lower_tval_i (lower_tval), + .match_tval_i (match_tval), + .tval_mode_i (tval_mode), + .tval_i (tval_i), + .priv_lvl_filter_i(priv_lvl_filter), + .upper_priv_i (upper_priv), + .lower_priv_i (lower_priv), + .match_priv_i (match_priv), + .priv_lvl_mode_i (priv_lvl_mode), + .priv_i (priv_i), + .iaddr_filter_i (iaddr_filter), + .upper_iaddr_i (upper_iaddr), + .lower_iaddr_i (lower_iaddr), + .match_iaddr_i (match_iaddr), + .iaddr_mode_i (iaddr_mode), + .iaddr_i (iaddr_i[i]), + .nc_qualified_o (qualified[i]) + ); + end + end + endgenerate + + /* PRIORITY, PACKET EMITTER*/ + // case dependant + generate + // 1 instance for N == 1 || (N > 1 && ONLY_BRANCHES) + if (N == 1 || (N > 1 && ONLY_BRANCHES)) begin + /* PRIORITY */ + te_priority i_te_priority( + .clk_i (clk_gated), + .rst_ni (rst_ni), + .valid_i (valid0_q[0] || (enc_activated_q || enc_deactivated_q)), // necessary to generate F3SF3 packet + .lc_exception_i (lc_exception || lc_interrupt), + .lc_updiscon_i (lc_updiscon), + .tc_qualified_i (tc_qualified[0]), + .tc_exception_i (tc_exception|| tc_interrupt), + .tc_retired_i (tc_iretired[0]), + .tc_first_qualified_i (tc_first_qualified), + .tc_privchange_i (privchange_q), + //.tc_context_change_i(), // non mandatory + //.tc_precise_context_report_i(), // requires ctype signal CPU side + //.tc_context_report_as_disc_i(), // ibidem + //.tc_imprecise_context_report_i(), // ibidem + .tc_gt_max_resync_i (gt_max_resync_q), + .tc_et_max_resync_i (et_max_resync_q), + .tc_branch_map_empty_i (tc_branch_map_empty), + .tc_branch_map_full_i (branch_map_full_d), + //.tc_branch_misprediction_i(), // non mandatory + //.tc_pbc_i(), // non mandatory + .tc_enc_enabled_i (enc_activated_q), + .tc_enc_disabled_i (enc_deactivated_q), + .tc_opmode_change_i (enc_config_change_q), + .tc_final_qualified_i (tc_final_qualified), + .tc_packets_lost_i (~encapsulator_ready_i), // non mandatory + .nc_exception_i (nc_exception || nc_interrupt), + .nc_privchange_i (privchange_d), + //.nc_context_change_i(), + //.nc_precise_context_report_i(), // requires ctype signal CPU side + //.nc_context_report_as_disc_i(), // ibidem + .nc_branch_map_empty_i (nc_branch_map_empty), + .nc_qualified_i (nc_qualified[0]), + .nc_retired_i (nc_iretired[0]), + //.halted_i(), // non mandatory side band signal + //.reset_i(), // ibidem + //.implicit_return_i(), // non mandatory + //.tc_trigger_req_i(), // non mandatory + //.notify_o(), // non mandatory, depends on trigger request + .addr_to_compress_i (addr_to_compress[0]), + .valid_o (packet_valid[0]), + .packet_format_o (packet_format[0]), + .packet_f_sync_subformat_o(packet_f_sync_subformat[0]), + //.packet_f_opt_ext_subformat_o(packet_f_opt_ext_subformat), // non mandatory + .thaddr_o (thaddr[0]), + .lc_tc_mux_o (lc_tc_mux[0]), + .resync_timer_rst_o (resync_rst), + .qual_status_o (qual_status[0]), + .tc_resync_o (tc_resync[0]), + .nc_exc_only_o (nc_exc_only[0]), + .nc_ppccd_br_o (nc_ppccd_br[0]), + .keep_bits_o (keep_bits[0]) + ); + + /* PACKET EMITTER */ + te_packet_emitter i_te_packet_emitter( + .clk_i (clk_gated), + .rst_ni (rst_ni), + .valid_i (packet_valid[0]), + .packet_format_i (packet_format[0]), + .packet_f_sync_subformat_i(packet_f_sync_subformat[0]), + //.packet_f_opt_ext_subformat_i(packet_f_opt_ext_subformat), // non mandatory + .lc_cause_i (lc_cause), + .lc_tval_i (lc_tval), + .lc_interrupt_i (lc_interrupt), + .tc_cause_i (tc_cause), + .tc_tval_i (tc_tval), + .tc_interrupt_i (tc_interrupt), + .tc_resync_i (tc_resync[0]), + .nc_exc_only_i (nc_exc_only[0]), + .nc_ppccd_br_i (nc_ppccd_br[0]), + .nocontext_i (nocontext), + .notime_i (notime), + .tc_branch_i (branch_q), + .tc_branch_taken_i (branch_taken_q), + .tc_priv_i (tc_priv), + .tc_time_i (tc_time), // non mandatory + //.context_i(), // non mandatory + .tc_address_i (tc_address[0]), + .lc_tc_mux_i (lc_tc_mux[0]), + .thaddr_i (thaddr[0]), + .tc_tvec_i (tc_tvec), + .lc_epc_i (lc_epc), + .tc_ienable_i (trace_enable), + .encoder_mode_i (encoder_mode), + .qual_status_i (qual_status[0]), + .ioptions_i (enc_config_q), + //.denable_i(), // stand-by + //.dloss_i(), //stand-by + //.notify_i(), // non mandatory + .lc_updiscon_i (lc_updiscon[0]), + //.irreport_i(), // non mandatory + //.irdepth_i(), // non mandatory + .branches_i (branch_count), + .branch_map_i (branch_map), + .keep_bits_i (keep_bits[0]), + .shallow_trace_i (shallow_trace), + .packet_valid_o (packet_emitted[0]), + .packet_type_o (packet_type_o[0]), + .packet_payload_o (packet_payload_o[0]), + .payload_length_o (packet_length_o[0]), + .branch_map_flush_o (nc_branch_map_flush), + .addr_to_compress_o (addr_to_compress[0]) + ); + + end else if (N > 1 && !ONLY_BRANCHES) begin + // N instances for N > 1 && !ONLY_BRANCHES + for (genvar i = 0; i < N; i++) begin + if (i == 0) begin + /* PRIORITY */ + te_priority i_te_priority( + .clk_i (clk_gated), + .rst_ni (rst_ni), + .valid_i (|valid0_q || (enc_activated_q || enc_deactivated_q)), + .lc_exception_i (lc_exception || lc_interrupt), + .lc_updiscon_i (lc_updiscon[i]), + .tc_qualified_i (tc_qualified[i]), + .tc_exception_i (tc_exception|| tc_interrupt), + .tc_retired_i (tc_iretired[i]), + .tc_first_qualified_i (tc_first_qualified), + .tc_privchange_i (privchange_q), + //.tc_context_change_i(), // non mandatory + //.tc_precise_context_report_i(), // requires ctype signal CPU side + //.tc_context_report_as_disc_i(), // ibidem + //.tc_imprecise_context_report_i(), // ibidem + .tc_gt_max_resync_i (gt_max_resync_q), // connected only to the first port + .tc_et_max_resync_i (et_max_resync_q), // connected only to the first port + .tc_branch_map_empty_i (tc_branch_map_empty), + .tc_branch_map_full_i (branch_map_full_q), // connected only to the first port + //.tc_branch_misprediction_i(), // non mandatory + //.tc_pbc_i(), // non mandatory + .tc_enc_enabled_i (enc_activated_q), + .tc_enc_disabled_i (enc_deactivated_q), + .tc_opmode_change_i (enc_config_change_q), + .tc_final_qualified_i (tc_final_qualified), + .tc_packets_lost_i (~encapsulator_ready_i), // non mandatory + .nc_exception_i (nc_exception || nc_interrupt), + .nc_privchange_i (privchange_d), + //.nc_context_change_i(), + //.nc_precise_context_report_i(), // requires ctype signal CPU side + //.nc_context_report_as_disc_i(), // ibidem + .nc_branch_map_empty_i (nc_branch_map_empty), + .nc_qualified_i (nc_qualified[i]), + .nc_retired_i (nc_iretired[i]), + //.halted_i(), // non mandatory side band signal + //.reset_i(), // ibidem + //.implicit_return_i(), // non mandatory + //.tc_trigger_req_i(), // non mandatory + //.notify_o(), // non mandatory, depends on trigger request + .addr_to_compress_i (addr_to_compress[i]), + .valid_o (packet_valid[i]), + .packet_format_o (packet_format[i]), + .packet_f_sync_subformat_o(packet_f_sync_subformat[i]), + //.packet_f_opt_ext_subformat_o(packet_f_opt_ext_subformat), // non mandatory + .thaddr_o (thaddr[i]), + .lc_tc_mux_o (lc_tc_mux[i]), + .resync_timer_rst_o (resync_rst), + .qual_status_o (qual_status[i]), + .tc_resync_o (tc_resync[i]), + .nc_exc_only_o (nc_exc_only[i]), + .nc_ppccd_br_o (nc_ppccd_br[i]), + .keep_bits_o (keep_bits[i]) + ); + + /* PACKET EMITTER */ + te_packet_emitter i_te_packet_emitter( + .clk_i (clk_gated), + .rst_ni (rst_ni), + .valid_i (packet_valid[i]), + .packet_format_i (packet_format[i]), + .packet_f_sync_subformat_i(packet_f_sync_subformat[i]), + //.packet_f_opt_ext_subformat_i(packet_f_opt_ext_subformat), // non mandatory + .lc_cause_i (lc_cause), + .lc_tval_i (lc_tval), + .lc_interrupt_i (lc_interrupt), + .tc_cause_i (tc_cause), + .tc_tval_i (tc_tval), + .tc_interrupt_i (tc_interrupt), + .tc_resync_i (tc_resync[i]), + .nc_exc_only_i (nc_exc_only[i]), + .nc_ppccd_br_i (nc_ppccd_br[i]), + .nocontext_i (nocontext), + .notime_i (notime), + .tc_branch_i (branch_q), + .tc_branch_taken_i (branch_taken_q), + .tc_priv_i (tc_priv), + .tc_time_i (tc_time), // non mandatory + //.context_i(), // non mandatory + .tc_address_i (tc_address[i]), + .lc_tc_mux_i (lc_tc_mux[i]), + .thaddr_i (thaddr[i]), + .tc_tvec_i (tc_tvec), + .lc_epc_i (lc_epc), + .tc_ienable_i (trace_enable), + .encoder_mode_i (encoder_mode), + .qual_status_i (qual_status[i]), + .ioptions_i (enc_config_q), + //.denable_i(), // stand-by + //.dloss_i(), //stand-by + //.notify_i(), // non mandatory + .lc_updiscon_i (lc_updiscon[i]), + //.irreport_i(), // non mandatory + //.irdepth_i(), // non mandatory + .branches_i (branch_count), + .branch_map_i (branch_map), + .keep_bits_i (keep_bits[i]), + .shallow_trace_i (shallow_trace), + .packet_valid_o (packet_emitted[i]), + .packet_type_o (packet_type_o[i]), + .packet_payload_o (packet_payload_o[i]), + .payload_length_o (packet_length_o[i]), + .branch_map_flush_o (nc_branch_map_flush), + .addr_to_compress_o (addr_to_compress[i]) + ); + end else begin + /* PRIORITY */ + te_priority i_te_priority( + .clk_i (clk_gated), + .rst_ni (rst_ni), + .valid_i (|valid0_q || (enc_activated_q || enc_deactivated_q)), + .lc_exception_i (lc_exception || lc_interrupt), + .lc_updiscon_i (lc_updiscon[i]), + .tc_qualified_i (tc_qualified[i]), + .tc_exception_i (tc_exception || tc_interrupt), + .tc_retired_i (tc_iretired[i]), + .tc_first_qualified_i (tc_first_qualified), + .tc_privchange_i (privchange_q), + //.tc_context_change_i(), // non mandatory + //.tc_precise_context_report_i(), // requires ctype signal CPU side + //.tc_context_report_as_disc_i(), // ibidem + //.tc_imprecise_context_report_i(), // ibidem + .tc_gt_max_resync_i (), // connected only to the first port + .tc_et_max_resync_i (), // connected only to the first port + .tc_branch_map_empty_i (tc_branch_map_empty), + .tc_branch_map_full_i (), // connected only to the first port + //.tc_branch_misprediction_i(), // non mandatory + //.tc_pbc_i(), // non mandatory + .tc_enc_enabled_i (enc_activated_q), + .tc_enc_disabled_i (enc_deactivated_q), + .tc_opmode_change_i (enc_config_change_q), + .tc_final_qualified_i (tc_final_qualified), + .tc_packets_lost_i (~encapsulator_ready_i), // non mandatory + .nc_exception_i (nc_exception || nc_interrupt), + .nc_privchange_i (privchange_d), + //.nc_context_change_i(), + //.nc_precise_context_report_i(), // requires ctype signal CPU side + //.nc_context_report_as_disc_i(), // ibidem + .nc_branch_map_empty_i (nc_branch_map_empty), + .nc_qualified_i (nc_qualified[i]), + .nc_retired_i (nc_iretired[i]), + //.halted_i(), // non mandatory side band signal + //.reset_i(), // ibidem + //.implicit_return_i(), // non mandatory + //.tc_trigger_req_i(), // non mandatory + //.notify_o(), // non mandatory, depends on trigger request + .addr_to_compress_i (addr_to_compress[i]), + .valid_o (packet_valid[i]), + .packet_format_o (packet_format[i]), + .packet_f_sync_subformat_o(packet_f_sync_subformat[i]), + //.packet_f_opt_ext_subformat_o(packet_f_opt_ext_subformat), // non mandatory + .thaddr_o (thaddr[i]), + .lc_tc_mux_o (lc_tc_mux[i]), + .resync_timer_rst_o (), // connected only to the first port + .qual_status_o (qual_status[i]), + .tc_resync_o (tc_resync[i]), + .nc_exc_only_o (nc_exc_only[i]), + .nc_ppccd_br_o (nc_ppccd_br[i]), + .keep_bits_o (keep_bits[i]) + ); + + /* PACKET EMITTER */ + te_packet_emitter i_te_packet_emitter( + .clk_i (clk_gated), + .rst_ni (rst_ni), + .valid_i (packet_valid[i]), + .packet_format_i (packet_format[i]), + .packet_f_sync_subformat_i(packet_f_sync_subformat[i]), + //.packet_f_opt_ext_subformat_i(packet_f_opt_ext_subformat), // non mandatory + .lc_cause_i (lc_cause), + .lc_tval_i (lc_tval), + .lc_interrupt_i (lc_interrupt), + .tc_cause_i (tc_cause), + .tc_tval_i (tc_tval), + .tc_interrupt_i (tc_interrupt), + .tc_resync_i (tc_resync[i]), + .nc_exc_only_i (nc_exc_only[i]), + .nc_ppccd_br_i (nc_ppccd_br[i]), + .nocontext_i (nocontext), + .notime_i (notime), + .tc_branch_i (branch_q), + .tc_branch_taken_i (branch_taken_q), + .tc_priv_i (tc_priv), + .tc_time_i (tc_time), // non mandatory + //.context_i(), // non mandatory + .tc_address_i (tc_address[i]), + .lc_tc_mux_i (lc_tc_mux[i]), + .thaddr_i (thaddr[i]), + .tc_tvec_i (tc_tvec), + .lc_epc_i (lc_epc), + .tc_ienable_i (trace_enable), + .encoder_mode_i (encoder_mode), + .qual_status_i (qual_status[i]), + .ioptions_i (enc_config_q), + //.denable_i(), // stand-by + //.dloss_i(), //stand-by + //.notify_i(), // non mandatory + .lc_updiscon_i (lc_updiscon[i]), + //.irreport_i(), // non mandatory + //.irdepth_i(), // non mandatory + .branches_i (branch_count), + .branch_map_i (branch_map), + .keep_bits_i (keep_bits[i]), + .shallow_trace_i (shallow_trace), + .packet_valid_o (packet_emitted[i]), + .packet_type_o (packet_type_o[i]), + .packet_payload_o (packet_payload_o[i]), + .payload_length_o (packet_length_o[i]), + .branch_map_flush_o (), // connected only to the first port + .addr_to_compress_o (addr_to_compress[i]) + ); + end + end + end + endgenerate + + /* REGISTERS MANAGEMENT */ + always_ff @( posedge clk_i, negedge rst_ni ) begin : registers + if(~rst_ni) begin + valid0_q <= '0; + privchange_q <= '0; + // context_change_q <= '0; + //precise_context_report_q <= '0; // requires ctype signal CPU side + //context_report_as_disc_q <= '0; //ibidem + //no_context_report_q <= '0; // ibidem + //imprecise_context_report_q <= '0; // ibidem + gt_max_resync_q <= '0; + et_max_resync_q <= '0; + branch_map_full_q <= '0; + //branch_misprediction_q <= '0; // non mandatory + trace_activated_q <= '0; + enc_activated_q <= '0; + enc_deactivated_q <= '0; + //packets_lost_q <= '0; // non mandatory + enc_config_q <= te_pkg::DELTA_ADDRESS; // 3'b0 + enc_config_change_q <= '0; + branch_taken_q <= '0; + branch_q <= '0; + turn_on_tracer_q <= '0; + end else begin + privchange_q <= privchange_d; + // context_change_q <= context_change_d; + //precise_context_report_q <= precise_context_report_d; // requires ctype signal CPU side + //context_report_as_disc_q <= context_report_as_disc_d; //ibidem + //no_context_report_q <= no_context_report_d; // ibidem + //imprecise_context_report_q <= imprecise_context_report_d; // ibidem + branch_q <= branch_d; + valid0_q <= valid0_d; + gt_max_resync_q <= gt_max_resync_d; + et_max_resync_q <= et_max_resync_d; + branch_map_full_q <= branch_map_full_d; + //branch_misprediction_q <= branch_misprediction_d; // non mandatory + trace_activated_q <= trace_activated_d; + enc_activated_q <= enc_activated_d; + enc_deactivated_q <= enc_deactivated_d; + //packets_lost_q <= packets_lost_d; // non mandatory + enc_config_q <= enc_config_d; + enc_config_change_q <= enc_config_change_d; + branch_taken_q <= branch_taken_d; + turn_on_tracer_q <= turn_on_tracer_d; + end + end + +endmodule \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/rtl/te_branch_map.sv b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_branch_map.sv new file mode 100644 index 0000000000..c1e2f0fc8b --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_branch_map.sv @@ -0,0 +1,85 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/* BRANCH MAP */ +/* +It keeps track of taken and non taken branches. + +Whenever a branch happens it updates the branch map +and the number of branches stored. + +When flush_i signal is asserted, the branch map is +cleaned. +*/ + +module te_branch_map #( + parameter N = 1 // max number of committed branches in one cycle +) +( + input logic clk_i, + input logic rst_ni, + + input logic [N-1:0] valid_i, + input logic [N-1:0] branch_taken_i, + input logic flush_i, + + output logic [te_pkg::BRANCH_MAP_LEN-1:0] map_o, + output logic [te_pkg::BRANCH_COUNT_LEN-1:0] branches_o, + output logic is_full_o, + output logic is_empty_o +); + + + logic [te_pkg::BRANCH_MAP_LEN-1:0] map_d, map_q; + logic [te_pkg::BRANCH_COUNT_LEN-1:0] branch_cnt_d, branch_cnt_q; + + always_comb begin + map_d = map_q; + branch_cnt_d = branch_cnt_q; + + if (flush_i) begin + map_d = '0; + branch_cnt_d = '0; + end + + if (valid_i) begin + if(flush_i) begin + map_d[0] = ~branch_taken_i; + branch_cnt_d = 5'b1; + end else begin + map_d[branch_cnt_q] = ~branch_taken_i ; + branch_cnt_d = branch_cnt_q +1; + end + end + end + + assign map_o = map_d; + assign branches_o = branch_cnt_d; + assign is_full_o = (branch_cnt_d == 31); + assign is_empty_o = (branch_cnt_d == 0); + + + always_ff @(posedge clk_i, negedge rst_ni) begin + if(~rst_ni) begin + map_q <= '0; + branch_cnt_q <= '0; + + end else begin + map_q <= map_d; + branch_cnt_q <= branch_cnt_d; + end + end + +endmodule \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/rtl/te_filter.sv b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_filter.sv new file mode 100644 index 0000000000..6d33b7ebc5 --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_filter.sv @@ -0,0 +1,142 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/* FILTER MODULE */ +/* +it declares instructions qualified or not +*/ + +module te_filter +( + // if trace isn't enabled it doesn't make sense to filter + input logic trace_enable_i, + + /* + The idea is to have all inputs to be filtered in range or match. + To achieve this, the filter requires for each parameter: + - enable + - upper and lower values + - to be matched value + - select between in range or match + - qualified for each mode + + The trace to be qualified according to the filters set it requires + an AND between the qualified of the parameters to filter. + */ + + // parameters to filter + // cause + input logic cause_filter_i, + input logic [te_pkg::XLEN-1:0] upper_cause_i, + input logic [te_pkg::XLEN-1:0] lower_cause_i, + input logic [te_pkg::XLEN-1:0] match_cause_i, + input logic cause_mode_i, + input logic [te_pkg::XLEN-1:0] cause_i, + // tvec + input logic tvec_filter_i, + input logic [te_pkg::XLEN-1:0] upper_tvec_i, + input logic [te_pkg::XLEN-1:0] lower_tvec_i, + input logic [te_pkg::XLEN-1:0] match_tvec_i, + input logic tvec_mode_i, + input logic [te_pkg::XLEN-1:0] tvec_i, + // tval + input logic tval_filter_i, + input logic [te_pkg::XLEN-1:0] upper_tval_i, + input logic [te_pkg::XLEN-1:0] lower_tval_i, + input logic [te_pkg::XLEN-1:0] match_tval_i, + input logic tval_mode_i, + input logic [te_pkg::XLEN-1:0] tval_i, + // priv_lvl + input logic priv_lvl_filter_i, + input logic [te_pkg::PRIV_LEN-1:0] upper_priv_i, + input logic [te_pkg::PRIV_LEN-1:0] lower_priv_i, + input logic [te_pkg::PRIV_LEN-1:0] match_priv_i, + input logic priv_lvl_mode_i, + input logic [te_pkg::PRIV_LEN-1:0] priv_i, + // iaddr (pc) + input logic iaddr_filter_i, + input logic [te_pkg::XLEN-1:0] upper_iaddr_i, + input logic [te_pkg::XLEN-1:0] lower_iaddr_i, + input logic [te_pkg::XLEN-1:0] match_iaddr_i, + input logic iaddr_mode_i, + input logic [te_pkg::XLEN-1:0] iaddr_i, + + output logic nc_qualified_o +); + + // output signals for comparators + // cause + logic cause_in_range; + logic cause_equals; + // tvec + logic tvec_in_range; + logic tvec_equals; + // tval + logic tval_in_range; + logic tval_equals; + // priv_lvl + logic priv_lvl_in_range; + logic priv_lvl_equals; + // iaddr (pc) + logic iaddr_in_range; + logic iaddr_equals; + + // assignments + // cause + assign cause_in_range = cause_mode_i == te_pkg::RANGE_MODE && + cause_i <= upper_cause_i && + cause_i >= lower_cause_i; + assign cause_equals = cause_mode_i == te_pkg::EQUAL_MODE && + cause_i == match_cause_i; + // tvec + assign tvec_in_range = tvec_mode_i == te_pkg::RANGE_MODE && + tvec_i <= upper_tvec_i && + tvec_i >= lower_tvec_i; + assign tvec_equals = tvec_mode_i == te_pkg::EQUAL_MODE && + tvec_i == match_tvec_i; + // tval + assign tval_in_range = tval_mode_i == te_pkg::RANGE_MODE && + tval_i <= upper_tval_i && + tval_i >= lower_tval_i; + assign tval_equals = tval_mode_i == te_pkg::EQUAL_MODE && + tval_i == match_tval_i; + // priv_lvl + assign priv_lvl_in_range = priv_lvl_mode_i == te_pkg::RANGE_MODE && + priv_i <= upper_priv_i && + priv_i >= lower_priv_i; + assign priv_lvl_equals = priv_lvl_mode_i == te_pkg::EQUAL_MODE && + priv_i == match_priv_i; + // iaddr + assign iaddr_in_range = iaddr_mode_i == te_pkg::RANGE_MODE && + iaddr_i <= upper_iaddr_i && + iaddr_i >= lower_iaddr_i; + assign iaddr_equals = iaddr_mode_i == te_pkg::EQUAL_MODE && + iaddr_i == match_iaddr_i; + + // assigning output + // if no filter is enabled -> the instruction is qualified + assign nc_qualified_o = ((cause_filter_i && (cause_in_range || cause_equals)) || + ~cause_filter_i) && // cause + ((tvec_filter_i && (tvec_in_range || tvec_equals)) || + ~tvec_filter_i) && // tvec + ((tval_filter_i && (tval_in_range || tval_equals)) || + ~tval_filter_i) && // tval + ((priv_lvl_filter_i && (priv_lvl_in_range || priv_lvl_equals)) || + ~priv_lvl_filter_i) && // priv_lvl + ((iaddr_filter_i && (iaddr_in_range || iaddr_equals)) || + ~iaddr_filter_i) && // iaddr + trace_enable_i; + +endmodule \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/rtl/te_packet_emitter.sv b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_packet_emitter.sv new file mode 100644 index 0000000000..50bec71670 --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_packet_emitter.sv @@ -0,0 +1,1097 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/* PACKET EMITTER */ +/* +it produces the packets for the output interface +*/ + +module te_packet_emitter +( + input logic clk_i, + input logic rst_ni, + input logic valid_i, + + // necessary info to assemble packet + input te_pkg::format_e packet_format_i, + input te_pkg::f_sync_subformat_e packet_f_sync_subformat_i, // SF for F3 + //input f_opt_ext_subformat_e packet_f_opt_ext_subformat_i, // non mandatory, SF for F0 + + // lc (last cycle) signals + input logic [te_pkg::XLEN-1:0] lc_cause_i, + input logic [te_pkg::XLEN-1:0] lc_tval_i, + input logic lc_interrupt_i, + + // tc (this cycle) signals + input logic [te_pkg::XLEN-1:0] tc_cause_i, + input logic [te_pkg::XLEN-1:0] tc_tval_i, + input logic tc_interrupt_i, + input logic tc_resync_i, + + input logic nc_exc_only_i, + input logic nc_ppccd_br_i, + + // nc (next cycle) signals + + /* the following signals used to determine + if the packet emitter has to put context + and/or time in the payload*/ + input logic nocontext_i, // both read from registers + input logic notime_i, + // in this implementation both hardwired to 0 + + // format 3 subformat 0 specific signals + input logic tc_branch_i, + input logic tc_branch_taken_i, + input logic [te_pkg::PRIV_LEN-1:0] tc_priv_i, + input logic [te_pkg::TIME_LEN-1:0] tc_time_i, // optional + //input logic [:0] context_i, // optional + input logic [te_pkg::XLEN-1:0] tc_address_i, + + // format 3 subformat 1 specific signals + input logic lc_tc_mux_i, + /* format 3 subformat 1 packets require sometimes lc_cause o tc_cause + To discriminate I use a mux to choose between lc or tc */ + + input logic thaddr_i, + input logic [te_pkg::XLEN-1:0] tc_tvec_i, // trap handler address + input logic [te_pkg::XLEN-1:0] lc_epc_i, + + // format 3 subformat 3 specific signals + input logic tc_ienable_i, // trace encoder enabled + input logic encoder_mode_i, // only branch trace supported (value==0) + input te_pkg::qual_status_e qual_status_i, + input te_pkg::ioptions_s ioptions_i, + // about DATA trace, in stand-by at the moment + //input logic denable_i, // DATA trace enabled, if supported + //input logic dloss_i, // one or more DATA trace packets lost, if supported + //input logic [:0] doptions_i, // it's like ioptions, but for DATA trace + + + // format 2 specific signals + /* notify -> means the packet was requested by the cpu trigger unit*/ + //input logic notify_i, // non mandatory + + // most of the time these 2 values can be compressed + input logic lc_updiscon_i, + + // necessary if implicit_return mode is enabled + //input logic irreport_i, + + //input logic [2**te_pkg::CALL_COUNTER_SIZE-1:0] irdepth_i, // non mandatory, traces nested calls + + // format 1 specific signals + /* this format exists in two modes: + - address, branch map + - NO address, branch maps + + Their generation depends on the value of branches: + - 0: no need for address + - >0: address required + */ + input logic [te_pkg::BRANCH_COUNT_LEN-1:0] branches_i, + input logic [te_pkg::BRANCH_MAP_LEN-1:0] branch_map_i, // can change size to improve efficiency + + // format 0 specific signals + /* This format can have two possible subformats: + - subformat 0: number of correctly predicted branches + - subformat 1: jump target cache index + + Non mandatory, required support by the encoder. + */ + input logic [$clog2(te_pkg::XLEN):0] keep_bits_i, // required for address compression + input logic shallow_trace_i, // used to flush branch map at each packet + + // outputs + output logic packet_valid_o, // asserted when a packet is generated + output te_pkg::it_packet_type_e packet_type_o, + output logic [te_pkg::PAYLOAD_LEN-1:0] packet_payload_o, + output logic [te_pkg::P_LEN-1:0] payload_length_o, // in bytes + output logic branch_map_flush_o, // flushing done after each request + // to send back to priority module in order to compress them + output logic [te_pkg::XLEN-1:0] addr_to_compress_o +); + + // internal signals + logic branch; + logic interrupt; + logic [te_pkg::XLEN-1:0] address; + logic [te_pkg::XLEN-1:0] ecause; + logic [te_pkg::XLEN-1:0] diff_addr; + logic [te_pkg::XLEN-1:0] latest_addr_d, latest_addr_q; // address of the latest packet emitted + logic [te_pkg::XLEN-1:0] tval; + logic [1:0] time_and_context; // if payload requires time/context + logic notify; + logic updiscon; + logic irreport; + logic [2**te_pkg::CALL_COUNTER_SIZE-1:0] irdepth; + logic [4:0] branch_map_off; + logic [3:0] address_off; + logic [8:0] used_bits; // counts the bits used inside each payload + logic flush_d, flush_q; + logic update_latest_addr; + logic resync_d, resync_q; + logic [te_pkg::XLEN-1:0] resync_addr_d, resync_addr_q; + + // assigning values + assign branch = ~(tc_branch_i && tc_branch_taken_i); + assign address = thaddr_i ? tc_tvec_i : lc_epc_i; + assign ecause = lc_tc_mux_i ? tc_cause_i : lc_cause_i; + assign tval = lc_tc_mux_i ? tc_tval_i : lc_tval_i; + assign interrupt = lc_tc_mux_i ? tc_interrupt_i : lc_interrupt_i; + assign time_and_context = {~notime_i, ~nocontext_i}; + assign branch_map_flush_o = flush_q; + assign payload_length_o = (used_bits + 7) >> 3; + assign latest_branch_addr_d = tc_address_i; + + always_comb begin + // init + resync_d = resync_q; + resync_addr_d = resync_addr_q; + + // updates resync signal + if (tc_resync_i) begin + resync_d = '1; + resync_addr_d = tc_address_i; + end + + // synchronous reset of resync signal + if (packet_type_o == te_pkg::F3SF0 && resync_q) begin + resync_d = '0; + end + end + + + // register to store the last address emitted in a packet + always_ff @(posedge clk_i, negedge rst_ni) begin + if(~rst_ni) begin + latest_addr_q <= '0; + flush_q <= '0; + resync_q <= '0; + resync_addr_q <= '0; + end else begin + latest_addr_q <= latest_addr_d; + resync_q <= resync_d; + resync_addr_q <= resync_addr_d; + flush_q <= flush_d; + end + end + + // combinatorial network to compute the offset to compress the branch_map + always_comb begin : branch_map_offset + if(branches_i == 1) begin + branch_map_off = 1; + end else if(branches_i <= 3) begin + branch_map_off = 3; + end else if(branches_i <= 7) begin + branch_map_off = 7; + end else if(branches_i <= 15) begin + branch_map_off = 15; + end else if (branches_i < 31) begin + branch_map_off = 31; + end else begin + branch_map_off = '0; + end + + end + + /* + the address compression works in byte chunks: based on the value of + keep_bits_i, the number of least significant bytes to keep is determined. + + example: + keep_bits_i == 7 -> 1 lsB kept 0111 + keep_bits_i == 10 -> 2 lsB kept 1010 + keep_bits_i == 25 -> 4 lsB kept 11001 + */ + // 33 = 100001 + 7 = 101000 >>3 = 0101 = 5 + + // find the number of least significant bytes to keep in the compressed address + assign address_off = (keep_bits_i + 7)>>3; + + // combinatorial network to output packets + always_comb begin + // init values + packet_payload_o = '0; + packet_valid_o = '0; + flush_d = '0; + used_bits = '0; + packet_type_o = te_pkg::F0SF0; + update_latest_addr = '0; + + if(valid_i) begin + /* branch_map_flush_o + the signal is output in this cycle, but the branch map does + the flush in the next cycle to leave time to the packet + emitter to read values and put them in the payload + */ + // flushes at each packet emitted to get a less precise tracing + flush_d = shallow_trace_i; + + // setting the packet to emit as valid + packet_valid_o = '1; + + /* packet payload creation: + at the beginning it's put in the payload the common part (i.e. the packet format) + then, for each format and subformat it's put the rest of the payload + */ + + // setting the packet format - common for all payloads + packet_payload_o[1:0] = packet_format_i; + + // format bits + used_bits += 2; + + case(packet_format_i) + te_pkg::F_SYNC: begin // format 3 + // setting packet subformat - common for all type 3 payloads + packet_payload_o[3:2] = packet_f_sync_subformat_i; + + used_bits += 2; // subformat bits + + // setting the rest of payload for each type + case(packet_f_sync_subformat_i) + te_pkg::SF_START: begin // subformat 0 + // updating packet type + packet_type_o = te_pkg::F3SF0; + update_latest_addr = '1; + + case(time_and_context) + 2'b00: begin + used_bits += 1 + (address_off * 8) + te_pkg::PRIV_LEN; + + packet_payload_o[4+:1+te_pkg::PRIV_LEN] = { + tc_priv_i, + branch + }; + // address compression + case (address_off) + 1: begin + packet_payload_o[5+te_pkg::PRIV_LEN+:8] = { + addr_to_compress_o[7:0] + }; + end + 2: begin + packet_payload_o[5+te_pkg::PRIV_LEN+:16] = { + addr_to_compress_o[15:0] + }; + end + 3: begin + packet_payload_o[5+te_pkg::PRIV_LEN+:24] = { + addr_to_compress_o[23:0] + }; + end + 4: begin + packet_payload_o[5+te_pkg::PRIV_LEN+:32] = { + addr_to_compress_o[31:0] + }; + end + `ifdef TE_ARCH64 // 64bits case + 5: begin + packet_payload_o[5+te_pkg::PRIV_LEN+:40] = { + addr_to_compress_o[39:0] + }; + end + 6: begin + packet_payload_o[5+te_pkg::PRIV_LEN+:48] = { + addr_to_compress_o[47:0] + }; + end + 7: begin + packet_payload_o[5+te_pkg::PRIV_LEN+:56] = { + addr_to_compress_o[55:0] + }; + end + 8: begin + packet_payload_o[5+te_pkg::PRIV_LEN+:64] = { + addr_to_compress_o + }; + end + `endif + endcase + end + + 2'b10: begin + used_bits += 1 + te_pkg::PRIV_LEN + te_pkg::TIME_LEN + (address_off * 8); + + packet_payload_o[4+:1+te_pkg::PRIV_LEN+te_pkg::TIME_LEN] = { + tc_time_i, + tc_priv_i, + branch + }; + // address compression + // FIXME(MAX): simplify case with: + // for (int unsigned i = 1; i <= 8; i++) begin + // if (i == address_off) begin + // packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:i*8] = { + // addr_to_compress_o[i*8-1:0] + // }; + // end + // end + case (address_off) + 1: begin + packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:8] = { + addr_to_compress_o[7:0] + }; + end + 2: begin + packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:16] = { + addr_to_compress_o[15:0] + }; + end + 3: begin + packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:24] = { + addr_to_compress_o[23:0] + }; + end + 4: begin + packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:32] = { + addr_to_compress_o[31:0] + }; + end + `ifdef TE_ARCH64 // 64bits case + 5: begin + packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:40] = { + addr_to_compress_o[39:0] + }; + end + 6: begin + packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:48] = { + addr_to_compress_o[47:0] + }; + end + 7: begin + packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:56] = { + addr_to_compress_o[55:0] + }; + end + 8: begin + packet_payload_o[5+te_pkg::PRIV_LEN+te_pkg::TIME_LEN+:64] = { + addr_to_compress_o + }; + end + `endif + endcase + end + /*TODO: other cases*/ + endcase + end + te_pkg::SF_TRAP: begin // subformat 1 + // updating packet type + packet_type_o = te_pkg::F3SF1; + update_latest_addr = '1; + + case(time_and_context) + 2'b00: begin + used_bits += 1 + te_pkg::PRIV_LEN + te_pkg::XLEN + 2 + (address_off * 8) + te_pkg::XLEN; // last XLEN is for tval + + packet_payload_o[4+:1+te_pkg::PRIV_LEN+te_pkg::XLEN+2] = { + thaddr_i, + interrupt, + ecause, + tc_priv_i, + branch + }; + // address compression //FIXME Why tval is with addr_to_compress ? and not before ??? + case (address_off) + 1: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+:8+te_pkg::XLEN] = { + addr_to_compress_o[7:0], + tval + + }; + end + 2: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+:16+te_pkg::XLEN] = { + addr_to_compress_o[15:0], + tval + }; + end + 3: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+:24+te_pkg::XLEN] = { + addr_to_compress_o[23:0], + tval + }; + end + 4: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+:32+te_pkg::XLEN] = { + addr_to_compress_o[31:0], + tval + }; + end + `ifdef TE_ARCH64 // 64bits case + 5: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+:40+te_pkg::XLEN] = { + addr_to_compress_o[39:0], + tval + }; + end + 6: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+:48+te_pkg::XLEN] = { + addr_to_compress_o[47:0], + tval + }; + end + 7: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+:56+te_pkg::XLEN] = { + addr_to_compress_o[55:0], + tval + }; + end + 8: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+:64+te_pkg::XLEN] = { + addr_to_compress_o, + tval + }; + end + `endif + endcase + end + + 2'b10: begin + used_bits += 1 + te_pkg::PRIV_LEN + te_pkg::XLEN + 2 + (address_off * 8) + te_pkg::TIME_LEN + te_pkg::XLEN ; // why time_len *2 , time = 64 bits ? + + packet_payload_o[4+:1+te_pkg::PRIV_LEN+te_pkg::XLEN+2+te_pkg::TIME_LEN] = { + thaddr_i, + interrupt, + ecause, + tc_time_i, + tc_priv_i, + branch + }; + // address compression + case (address_off) + 1: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+te_pkg::TIME_LEN+:8+te_pkg::XLEN] = { // FIXME Replace XLEN by TIME_LEN every time ? + addr_to_compress_o[7:0], + tval + + }; + end + 2: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+te_pkg::TIME_LEN+:16+te_pkg::XLEN] = { + addr_to_compress_o[15:0], + tval + }; + end + 3: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+te_pkg::TIME_LEN+:24+te_pkg::XLEN] = { + addr_to_compress_o[23:0], + tval + }; + end + 4: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+te_pkg::TIME_LEN+:32+te_pkg::XLEN] = { + addr_to_compress_o[31:0], + tval + }; + end + `ifdef TE_ARCH64 // 64bits case + 5: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+te_pkg::TIME_LEN+:40+te_pkg::XLEN] = { + addr_to_compress_o[39:0], + tval + }; + end + 6: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+te_pkg::TIME_LEN+:48+te_pkg::XLEN] = { + addr_to_compress_o[47:0], + tval + }; + end + 7: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+te_pkg::TIME_LEN+:56+te_pkg::XLEN] = { + addr_to_compress_o[55:0], + tval + }; + end + 8: begin + packet_payload_o[7+te_pkg::PRIV_LEN+te_pkg::XLEN+te_pkg::TIME_LEN+:64+te_pkg::XLEN] = { + addr_to_compress_o, + tval + }; + end + `endif + endcase + end + /*TODO: other cases*/ + endcase + end + te_pkg::SF_CONTEXT: begin // subformat 2 + // updating packet type + packet_type_o = te_pkg::F3SF2; + + case(time_and_context) + 2'b00: begin + used_bits += te_pkg::PRIV_LEN; + + packet_payload_o[4+:te_pkg::PRIV_LEN] = { + tc_priv_i + }; + end + + 2'b10: begin + used_bits += te_pkg::PRIV_LEN + te_pkg::TIME_LEN; + + packet_payload_o[4+:te_pkg::PRIV_LEN+te_pkg::TIME_LEN] = { + tc_time_i, + tc_priv_i + }; + end + /*TODO: other cases*/ + endcase + end + te_pkg::SF_SUPPORT: begin // subformat 3 + // updating packet type + packet_type_o = te_pkg::F3SF3; + + used_bits += 11; + + packet_payload_o[4+:1+1+2+7] = { + /* info required for data tracing - in the future + doptions_i, + dloss_i, + denable_i, */ + ioptions_i, + qual_status_i, + encoder_mode_i, + tc_ienable_i + }; + end + endcase + end + + te_pkg::F_ADDR_ONLY: begin // format 2 + // updating packet type + packet_type_o = te_pkg::F2; + update_latest_addr = '1; + + // requires trigger unit in CPU + /* + if(notify_i) begin // request from trigger unit + notify = !tc_address_i[XLEN-1]; + updiscon = notify; + irreport = updsicon; + irdepth = irdepth_i; + end else begin*/ + + // case of an updiscon + if(lc_updiscon_i && (nc_exc_only_i || nc_ppccd_br_i)) begin //FIXME spec says lc_updiscon AND nc_execption/interrupt /priv change / resync <= need to add nc_resync + notify = tc_address_i[te_pkg::XLEN-1]; + updiscon = !notify; + irreport = updiscon; + irdepth = {2**te_pkg::CALL_COUNTER_SIZE{updiscon}}; + /* non mandatory + end else if(implicit_mode_i && irreport_i) begin // request for implicit return mode + notify = tc_address_i[XLEN-1]; + updiscon = notify; + irreport = !updiscon; + irdepth = irdepth_i; + */ + end else begin //other cases + notify = tc_address_i[te_pkg::XLEN-1]; + updiscon = notify; + irreport = updiscon; + irdepth = {2**te_pkg::CALL_COUNTER_SIZE{updiscon}}; + end + + // checking if implicit return is supported + if (te_pkg::CALL_COUNTER_SIZE == 0 && + te_pkg::RETURN_STACK_SIZE == 0) begin // not supported + + // payload bits + used_bits += 3 + address_off*8 ; + + // address compression + case (address_off) + 1: begin + packet_payload_o[2+:8+3] = { + addr_to_compress_o[7:0], + irreport, + updiscon, + notify + }; + end + 2: begin + packet_payload_o[2+:16+3] = { + addr_to_compress_o[15:0], + irreport, + updiscon, + notify + }; + end + 3: begin + packet_payload_o[2+:24+3] = { + addr_to_compress_o[23:0], + irreport, + updiscon, + notify + }; + end + 4: begin + packet_payload_o[2+:32+3] = { + addr_to_compress_o[31:0], + irreport, + updiscon, + notify + }; + end + `ifdef TE_ARCH64 // 64bits case + 5: begin + packet_payload_o[2+:40+3] = { + addr_to_compress_o[39:0], + irreport, + updiscon, + notify + }; + end + 6: begin + packet_payload_o[2+:48+3] = { + addr_to_compress_o[47:0], + irreport, + updiscon, + notify + }; + end + 7: begin + packet_payload_o[2+:56+3] = { + addr_to_compress_o[55:0], + irreport, + updiscon, + notify + }; + end + 8: begin + packet_payload_o[2+:64+3] = { + addr_to_compress_o, + irreport, + updiscon, + notify + }; + end + `endif + endcase + + end else begin // supported + // payload bits + used_bits += 3 + 2**te_pkg::CALL_COUNTER_SIZE + address_off*8 ; + + // address compression + case (address_off) + 1: begin + packet_payload_o[2+:8+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[7:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 2: begin + packet_payload_o[2+:16+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[15:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 3: begin + packet_payload_o[2+:24+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[23:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 4: begin + packet_payload_o[2+:32+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[31:0], + irdepth, + irreport, + updiscon, + notify + }; + end + `ifdef TE_ARCH64 // 64bits case + 5: begin + packet_payload_o[2+:40+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[39:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 6: begin + packet_payload_o[2+:48+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[47:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 7: begin + packet_payload_o[2+:56+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[55:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 8: begin + packet_payload_o[2+:64+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o, + irdepth, + irreport, + updiscon, + notify + }; + end + `endif + endcase + end + end + + te_pkg::F_DIFF_DELTA: begin // format 1 + /* There can be two type of payloads for this format: + 1. address, branch map + 2. no address, branch map + + Type 1 payload is used when there has been at least + one branch from last packet. This can be determined + by the number of branches in the branch map. + + Type 2 payload is used when the address is not needed, + for examples if the branch map is full. + */ + // flushing the branch_map + flush_d = '1; + // updating packet type + packet_type_o = te_pkg::F1; + + // requires trigger unit in CPU + /* + if(notify_i) begin // request from trigger unit + notify = !tc_address_i[XLEN-1]; + updiscon = notify; + irreport = updsicon; + irdepth = irdepth_i; + end else begin*/ + + // case of an updiscon + if(lc_updiscon_i && (nc_exc_only_i || nc_ppccd_br_i)) begin //FIXME spec says lc_updiscon AND nc_execption/interrupt /priv change / resync <= need to add nc_resync + notify = tc_address_i[te_pkg::XLEN-1]; + updiscon = !notify; + irreport = updiscon; + irdepth = {2**te_pkg::CALL_COUNTER_SIZE{updiscon}}; + /* non mandatory + end else if(implicit_return_i && irreport_i) begin // request for implicit return mode + notify = tc_address_i[XLEN-1]; + updiscon = notify; + irreport = !updiscon; + irdepth = irdepth_i; + */ + end else begin // other cases + notify = tc_address_i[te_pkg::XLEN-1]; + updiscon = notify; + irreport = updiscon; + irdepth = {2**te_pkg::CALL_COUNTER_SIZE{updiscon}}; + end + + // branches and branch_map bits + used_bits += (branch_map_off==0)? te_pkg::BRANCH_COUNT_LEN + 32 : te_pkg::BRANCH_COUNT_LEN + branch_map_off; + + // adding branch count and branch map + if (branch_map_off == 1) begin + packet_payload_o[2+:te_pkg::BRANCH_COUNT_LEN+1] = { + branch_map_i[0], + branches_i + }; + end else if (branch_map_off == 3) begin + packet_payload_o[2+:te_pkg::BRANCH_COUNT_LEN+3] = { + branch_map_i[2:0], + branches_i + }; + end else if (branch_map_off == 7) begin + packet_payload_o[2+:te_pkg::BRANCH_COUNT_LEN+7] = { + branch_map_i[6:0], + branches_i + }; + end else if (branch_map_off == 15) begin + packet_payload_o[2+:te_pkg::BRANCH_COUNT_LEN+15] = { + branch_map_i[14:0], + branches_i + }; + end else if (branch_map_off == 31) begin + packet_payload_o[2+:te_pkg::BRANCH_COUNT_LEN+31] = { + branch_map_i[30:0], + branches_i + }; + end else begin //FIXME if we have discontinuity branches =31 not 0 + packet_payload_o[2+:te_pkg::BRANCH_COUNT_LEN+31] = { + branch_map_i[30:0], + 5'b00000 + }; + end + + // attaching the rest of the payload + if(branches_i < 31) begin // branch map not full - address + update_latest_addr = '1; + // checking if implicit return is supported + if (te_pkg::CALL_COUNTER_SIZE == 0 && + te_pkg::RETURN_STACK_SIZE == 0) begin // not supported + // rest of the payload bits + used_bits += 3 + address_off*8 ; + + // address compression + case (address_off) + 1: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:8+3] = { + addr_to_compress_o[7:0], + irreport, + updiscon, + notify + }; + end + 2: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:16+3] = { + addr_to_compress_o[15:0], + irreport, + updiscon, + notify + }; + end + 3: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:24+3] = { + addr_to_compress_o[23:0], + irreport, + updiscon, + notify + }; + end + 4: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:32+3] = { + addr_to_compress_o[31:0], + irreport, + updiscon, + notify + }; + end + `ifdef TE_ARCH64 // 64bits case + 5: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:40+3] = { + addr_to_compress_o[39:0], + irreport, + updiscon, + notify + }; + end + 6: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:48+3] = { + addr_to_compress_o[47:0], + irreport, + updiscon, + notify + }; + end + 7: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:56+3] = { + addr_to_compress_o[55:0], + irreport, + updiscon, + notify + }; + end + 8: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:64+3] = { + addr_to_compress_o, + irreport, + updiscon, + notify + }; + end + `endif + endcase + + end else begin // supported -> uses irdepth and irreport + // rest of the payload bits + used_bits += 3 + 2**te_pkg::CALL_COUNTER_SIZE + address_off*8 ; + + // address compression + case (address_off) + 1: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:8+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[7:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 2: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:16+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[15:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 3: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:24+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[23:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 4: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:32+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[31:0], + irdepth, + irreport, + updiscon, + notify + }; + end + `ifdef TE_ARCH64 // 64bits case + 5: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:40+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[39:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 6: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:48+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[47:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 7: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:56+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o[55:0], + irdepth, + irreport, + updiscon, + notify + }; + end + 8: begin + packet_payload_o[2+te_pkg::BRANCH_COUNT_LEN+branch_map_off+:64+3+2**te_pkg::CALL_COUNTER_SIZE] = { + addr_to_compress_o, + irdepth, + irreport, + updiscon, + notify + }; + end + `endif + endcase + end + end + end + + //F_OPT_EXT: begin // format 0 // TODO + // requires trigger unit in CPU + /* + if(notify_i) begin // request from trigger unit + notify = !tc_address_i[XLEN-1]; + updiscon = notify; + irreport = updsicon; + irdepth = irdepth_i; + end else begin + notify = tc_address_i[XLEN-1]; + updiscon = notify; + irreport = updiscon; + irdepth = {2**CALL_COUNTER_SIZE{updiscon}}; + end */ + + /* requires non mandatory support for jtc and branch prediction + case(packet_f_opt_ext_subformat_i) + SF_PBC: begin // subformat 0 + /* There can be two type of payloads for this subformat: + 1. no address, branch count + 2. address, branch count + * / + + // only for F0SF0 payload w/address + // updating latest address sent in a packet + + packet_payload_o = {F_OPT_EXT, SF_PBC, etc..}; + packet_valid_o = '1; + end + + SF_JTC: begin // subformat 1 + packet_payload_o = {F_OPT_EXT, SF_JTC, etc..}; + packet_valid_o = '1; + end + endcase + */ + //end + endcase + end + end + + always_comb begin : address_to_compress + diff_addr = '0; + addr_to_compress_o = '0; + latest_addr_d = latest_addr_q; + + // determines differential address for F1, F2 + if (packet_valid_o && (packet_format_i == te_pkg::F_DIFF_DELTA || + packet_format_i == te_pkg::F_ADDR_ONLY)) begin + if (ioptions_i.delta_address_en) begin + diff_addr = latest_addr_q - tc_address_i; // mostly >0 exept for jump , remove signed + addr_to_compress_o = diff_addr; + end else if (ioptions_i.full_address_en) begin + addr_to_compress_o = tc_address_i; + end + end + + // determines latest address + if (packet_valid_o && update_latest_addr) begin + if (packet_type_o == te_pkg::F1 || + packet_type_o == te_pkg::F2) begin // F1, F2 + latest_addr_d = tc_address_i; + addr_to_compress_o = tc_address_i; + end + if (packet_type_o == te_pkg::F3SF0) begin // F3SF0 + if (resync_q) begin //FIXME WHY ? + latest_addr_d = tc_address_i; + addr_to_compress_o = tc_address_i; + end else begin + latest_addr_d = tc_address_i; + addr_to_compress_o = tc_address_i; + end + end + if (packet_type_o == te_pkg::F3SF1) begin // F3SF1 + latest_addr_d = address; + addr_to_compress_o = address; + end + end + end + +endmodule \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/rtl/te_priority.sv b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_priority.sv new file mode 100644 index 0000000000..9fd6db48af --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_priority.sv @@ -0,0 +1,405 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/*PRIORITY*/ +/* +change this module name to a more appropriate one +for example "packet identifier" or something similar +*/ +/* +it orders packet generation - refer to page 53 of the spec +*/ + +module te_priority ( + + input logic clk_i, + input logic rst_ni, + + input logic valid_i, + + /* signals for the jump target cache mode - non mandatory */ + //input logic jtc_enabled_i, + //input logic address_in_cache_i, // communicates if the address is present in cache + + // lc (last cycle) signals + input logic lc_exception_i, + input logic lc_updiscon_i, // updsicon == uninferable PC discontinuity + + // tc (this cycle) signals + input logic tc_qualified_i, + input logic tc_exception_i, + input logic [te_pkg::IRETIRE_LEN-1:0] tc_retired_i, + input logic tc_first_qualified_i, + input logic tc_privchange_i, + //input logic tc_context_change_i, // non mandatory + //input logic tc_precise_context_report_i, // requires ctype signal CPU side + //input logic tc_context_report_as_disc_i, // ibidem + //input logic tc_imprecise_context_report_i, // ibidem + input logic tc_gt_max_resync_i, // greater than timeout + input logic tc_et_max_resync_i, // one step to timeout + input logic tc_branch_map_empty_i, + input logic tc_branch_map_full_i, + //input logic tc_branch_misprediction_i, // non mandatory + //input logic tc_pbc_i, // correctly predicted branch count, non mandatory + + // format 3 subformat 3 - NOT shown in graph + input logic tc_enc_enabled_i, + input logic tc_enc_disabled_i, + input logic tc_opmode_change_i, + input logic tc_final_qualified_i, + input logic tc_packets_lost_i, // non mandatory + + // nc (next cycle) signals + input logic nc_exception_i, + input logic nc_privchange_i, + //input logic nc_context_change_i, // non mandatory + //input logic nc_precise_context_report_i, // requires ctype signal CPU side + //input logic nc_context_report_as_disc_i, // ibidem + input logic nc_branch_map_empty_i, + input logic nc_qualified_i, + input logic [te_pkg::IRETIRE_LEN-1:0] nc_retired_i, // used w/nc_exception for signal nc_exc_only + + // non mandatory sideband signals + // refer to page 52 of the spec + //input logic halted_i, + //input logic reset_i, + + // inputs for irreport and irdepth, non mandatory + //input logic implicit_return_i, // tells if the mode is enabled + //input logic [:0] call_counter_size_i, // size of nested calls counter, 2^value + //input logic [:0] return_stack_size_i, // size of nested calls stack, 2^value + + // trigger unit request ports, must be supported by the CPU + //input logic tc_trigger_req_i, + //output logic notify_o, + // communicates the packet emitter that format 2 packet was requested by trigger unit + + // input to compress + input logic [te_pkg::XLEN-1:0] addr_to_compress_i, + + // outputs for packet_emitter + output logic valid_o, + output te_pkg::format_e packet_format_o, + output te_pkg::f_sync_subformat_e packet_f_sync_subformat_o, + //output te_pkg::f_opt_ext_subformat_e packet_f_opt_ext_subformat_o, // non mandatory, used for jtc and branch prediction + output logic thaddr_o, // required for f3 sf1 packet payload + output logic lc_tc_mux_o, // operates the MUX to choose between lc or tc cause, tval, interrupt: 0 -> lc, 1 + output logic resync_timer_rst_o, // resets counter + output te_pkg::qual_status_e qual_status_o, + //output logic irreport_o, // non mandatory, required implicit return mode + output logic tc_resync_o, + output logic nc_exc_only_o, + output logic nc_ppccd_br_o, + // output for compression + output logic [$clog2(te_pkg::XLEN):0] keep_bits_o + ); + + + /* internal signals required for packet determination */ + // last cycle + logic lc_ended_ntr_d, lc_ended_ntr_q; + logic lc_ended_rep_d, lc_ended_rep_q; + // this cycle + logic tc_exc_only; // for a precise definition: page 51 of the spec + logic tc_ppccd; // ibidem + logic tc_resync_br; // ibidem + logic tc_er_n; // ibidem + logic tc_rpt_br; // ibidem + //logic tc_cci; // ibidem + logic tc_reported_d, tc_reported_q; // ibidem + logic reported_status; + logic reported_update; // determines when reported_q updates + // reported is updated when the lc_exception was updated or not + logic tc_f3_sf3; + // next cycle + + // signals for compression + logic [$clog2(te_pkg::XLEN)-1:0] addr_zeros, addr_ones; + logic [$clog2(te_pkg::XLEN)-1:0] sign_extendable; + logic empty_zeros; + logic empty_ones; + + // signals to store + logic tc_resync_br_d, tc_resync_br_q; + + // value assignment + assign tc_exc_only = tc_exception_i && tc_retired_i == 0; + assign tc_ppccd = tc_privchange_i /*|| (tc_context_change_i && + (tc_precise_context_report_i || + tc_context_report_as_disc_i))*/; + assign tc_resync_br = tc_et_max_resync_i && ~tc_branch_map_empty_i; + assign tc_er_n = (tc_exception_i && tc_retired_i != 0) /*|| tc_trigger_req_i*/; + assign tc_rpt_br = tc_branch_map_full_i && !nc_branch_map_empty_i/* || tc_branch_misprediction_i*/; + //assign tc_cci = tc_context_change_i && tc_imprecise_context_report_i; + assign nc_exc_only_o = nc_exception_i && nc_retired_i == 0; + assign nc_ppccd_br_o = (nc_privchange_i /*|| (nc_context_change_i && + (nc_precise_context_report_i || nc_context_report_as_disc_i))*/) && + ~nc_branch_map_empty_i; + assign tc_f3_sf3 = tc_enc_enabled_i || tc_enc_disabled_i || tc_opmode_change_i || + tc_final_qualified_i || tc_packets_lost_i; + assign reported_update = ( packet_format_o == te_pkg::F_SYNC && + packet_f_sync_subformat_o == te_pkg::SF_TRAP && + ~thaddr_o) || + ( packet_format_o == te_pkg::F_SYNC && + packet_f_sync_subformat_o == te_pkg::SF_START && + ~tc_exc_only); + assign tc_resync_o = valid_i && tc_resync_br_q; + + always_comb begin + // init + tc_resync_br_d = tc_resync_br_q; + + if (reported_update) begin + tc_reported_d = reported_status; + end + + if (tc_resync_br) begin + tc_resync_br_d = '1; + end + + if (valid_o && + (packet_format_o == te_pkg::F_DIFF_DELTA || + packet_format_o == te_pkg::F_ADDR_ONLY)) begin + tc_resync_br_d = '0; + end + end + + /* + The reset value is 0, the spec doesn't say how to behave. + The 0 value specifies an exception w/out retired instr + in this cycle and an exception in the previous cycle. + */ + always_ff @( posedge clk_i, negedge rst_ni ) begin + if(~rst_ni) begin + tc_reported_q <= '0; + lc_ended_ntr_q <= '0; + lc_ended_rep_q <= '0; + tc_resync_br_q <= '0; + end else begin + tc_reported_q <= tc_reported_d; + tc_resync_br_q <= tc_resync_br_d; + lc_ended_ntr_q <= lc_ended_ntr_d; + lc_ended_rep_q <= lc_ended_rep_d; + end + end + + /*TODO: add condition to determine if F2, F1, F0SF0 are requested by the trigger unit*/ + + /* combinatorial network to determine packet format */ + // refer to flowchart at page 53 of the spec + always_comb begin : select_packet_format + // default init values + valid_o = '0; + packet_format_o = te_pkg::F_OPT_EXT; + packet_f_sync_subformat_o = te_pkg::SF_START; + //packet_f_opt_ext_subformat_o = SF_PBC; + //notify_o = '0; + thaddr_o = '0; + lc_tc_mux_o = '0; + resync_timer_rst_o = '0; + reported_status = '0; + qual_status_o = te_pkg::NO_CHANGE; + lc_ended_ntr_d = '0; + lc_ended_rep_d = '0; + + if(valid_i) begin + // format 3 subformat 3 packet generation + /* this if is not in the flowchart, but it's only described. + To me it made more sense to have it as the first if. */ + if(tc_f3_sf3) begin + packet_format_o = te_pkg::F_SYNC; + packet_f_sync_subformat_o = te_pkg::SF_SUPPORT; + // if-then-else to determine qual_status value for payload + if(lc_ended_ntr_q == '1) begin + qual_status_o = te_pkg::ENDED_NTR; + end else if(lc_ended_rep_q == '1) begin + qual_status_o = te_pkg::ENDED_REP; + end else if(tc_packets_lost_i == '1) begin + qual_status_o = te_pkg::TRACE_LOST; + end + valid_o = '1; + /* TODO: if for halted and reset sideband signals, + if at least one asserted -> considers unqualified*/ + end else if(tc_qualified_i) begin + if(lc_exception_i) begin + if(tc_exc_only) begin + packet_format_o = te_pkg::F_SYNC; + packet_f_sync_subformat_o = te_pkg::SF_TRAP; + resync_timer_rst_o = '1; + lc_tc_mux_o = 0; + reported_status = '1; + thaddr_o = '0; + /* thaddr_d = 0; resync_cnt = 0 + cause = lc_cause_i; tval = lc_tval*/ + valid_o = '1; + end else if(tc_reported_q) begin + packet_format_o = te_pkg::F_SYNC; + packet_f_sync_subformat_o = te_pkg::SF_START; + resync_timer_rst_o = '1; + //reported_d = '0; // not necessary + // resync_cnt = 0 + valid_o = '1; + end else begin // not reported + packet_format_o = te_pkg::F_SYNC; + packet_f_sync_subformat_o = te_pkg::SF_TRAP; + resync_timer_rst_o = '1; + lc_tc_mux_o = '0; + thaddr_o = '1; + /*thaddr_d = 1; resync_cnt = 0 + cause = lc_cause_i; tval = lc_tval */ + valid_o = '1; + end + end else if(tc_first_qualified_i || tc_ppccd || (tc_gt_max_resync_i && !tc_resync_br_q)) begin + packet_format_o = te_pkg::F_SYNC; + packet_f_sync_subformat_o = te_pkg::SF_START; + resync_timer_rst_o = '1; + //resync_cnt = 0 + valid_o = '1; + end else if(lc_updiscon_i) begin + // packet generated due to updiscon + lc_ended_ntr_d = '1; + if(tc_exc_only) begin + packet_format_o = te_pkg::F_SYNC; + packet_f_sync_subformat_o = te_pkg::SF_TRAP; + thaddr_o = '0; + resync_timer_rst_o = '1; + lc_tc_mux_o = '1; + /* thaddr = 0; resync_cnt = 0 + cause = tc_cause_i; tval = tc_tval */ + valid_o = '1; + end else begin + /* choosing between format 0/1/2 */ + /*if(tc_pbc_i >= 31) begin // format 0 subformat 0 + packet_format_o = F_OPT_EXT; + packet_f_opt_ext_subformat_o = SF_JTC; + // value for payload TBD + end else if(jtc_enabled_i && address_in_cache_i) begin // format 0 subformat 1 + packet_format_o = F_OPT_EXT; + packet_f_opt_ext_subformat_o = SF_JTC; + // value for payload TBD + end else*/ if(!tc_branch_map_empty_i) begin + packet_format_o = te_pkg::F_DIFF_DELTA; + end else begin // branch count == 0 + packet_format_o = te_pkg::F_ADDR_ONLY; + end + valid_o = '1; + end + end else if(tc_resync_br_q || tc_er_n) begin + // non mandatory + /* if(tc_er_n && tc_trigger_req_i) begin // requested from trigger unit + notify_o = '1; + end */ + + /* choosing between format 0/1/2 */ + /*if(tc_pbc_i >= 31) begin + packet_format_o = F_OPT_EXT; + packet_f_opt_ext_subformat_o = SF_JTC; + // value for payload TBD + end else if(jtc_enabled_i && address_in_cache_i) begin + packet_format_o = F_OPT_EXT; + packet_f_opt_ext_subformat_o = SF_JTC; + // value for payload TBD + end else*/ if(!tc_branch_map_empty_i) begin + packet_format_o = te_pkg::F_DIFF_DELTA; + end else begin // branch count == 0 + packet_format_o = te_pkg::F_ADDR_ONLY; + end + valid_o = '1; + end else if(nc_exc_only_o || nc_ppccd_br_o || !nc_qualified_i) begin + if(!nc_qualified_i) begin + // the packet is sent because it's the last instr qualified + lc_ended_rep_d = '1; + end + /* choosing between format 0/1/2 */ + /*if(tc_pbc_i >= 31) begin + packet_format_o = F_OPT_EXT; + packet_f_opt_ext_subformat_o = SF_JTC; + // value for payload TBD + end else if(jtc_enabled_i && address_in_cache_i) begin + packet_format_o = F_OPT_EXT; + packet_f_opt_ext_subformat_o = SF_JTC; + // value for payload TBD + end else*/ if(!tc_branch_map_empty_i) begin + packet_format_o = te_pkg::F_DIFF_DELTA; + end else begin // branch count == 0 + packet_format_o = te_pkg::F_ADDR_ONLY; + end + valid_o = '1; + end else if(tc_rpt_br) begin + /* // non mandatory, requires support for jtc and branch prediction + if(tc_pbc_i >= 31) begin + packet_format_o = F_OPT_EXT; + packet_f_opt_ext_subformat_o = SF_PBC; + valid_o = '1; + end else begin*/ + packet_format_o = te_pkg::F_DIFF_DELTA; + valid_o = '1; + //end + end /*else if(tc_cci) begin // non mandatory, requires support for context + packet_format_o = F_SYNC; + packet_f_sync_subformat_o = SF_CONTEXT; + valid_o = '1; + end*/ + end + end + end + + /* compression logic */ + /* short explanation on how it works: + by using the lzc we determine how many bits we can discard starting from the MSB, + this process is done with the normal address (we count 0s) and bitwise not of the + signal (we count 1s). + Then we decide in which way we can compress more and output the keep_bits signal. + + On the encoder side, it's possible to reconstruct the address: because we don't + remove all 0s (or 1s) from the MSB, but we keep one. This way it's possible to + sign extend the compressed address and get back the original address. + + Example 1: + address to compress: 0000001100010 + bits kept: -----01100010 + + Example 2: + address to compress: 1111011110110 + bits kept: ---1011110110 + + */ + // choosing between removing 1s or 0s + assign sign_extendable = addr_zeros > addr_ones ? addr_zeros : addr_ones; + // outputting the least sign bits we want to keep + // empty signals are used to cover 32'b0 and 32'b1 corner cases + assign keep_bits_o = (empty_zeros || empty_ones) ? 1 : te_pkg::XLEN - sign_extendable + 1; + + // leading zero counters + // from common_cells + lzc #( + .WIDTH(te_pkg::XLEN), + .MODE(1) + )i_lzc_zeros( + .in_i (addr_to_compress_i), + .cnt_o (addr_zeros), + .empty_o(empty_zeros) + ); + + lzc #( + .WIDTH(te_pkg::XLEN), + .MODE(1) + )i_lzc_ones( + .in_i (~addr_to_compress_i), + .cnt_o (addr_ones), + .empty_o(empty_ones) + ); + +endmodule \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/rtl/te_reg.sv b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_reg.sv new file mode 100644 index 0000000000..0b7a086a51 --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_reg.sv @@ -0,0 +1,792 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/*REG*/ +/* +it stores values for the encoder in memory mapped registers +*/ + +// uncomment to enable 64bits arch support +//`define TE_ARCH64 + +module te_reg #( + parameter APB_ADDR_WIDTH = 32 // it is the max allowed, maybe change to a smaller value +) +( + input logic clk_i, + input logic rst_ni, + + // tracing management + input logic trace_req_off_i, // from filter + input logic trace_req_on_i, // directly from trigger unit + input logic encapsulator_ready_i, + + // filter settings + output logic cause_filter_o, + output logic [te_pkg::XLEN-1:0] upper_cause_o, + output logic [te_pkg::XLEN-1:0] lower_cause_o, + output logic [te_pkg::XLEN-1:0] match_cause_o, + output logic cause_mode_o, + output logic tvec_filter_o, + output logic [te_pkg::XLEN-1:0] upper_tvec_o, + output logic [te_pkg::XLEN-1:0] lower_tvec_o, + output logic [te_pkg::XLEN-1:0] match_tvec_o, + output logic tvec_mode_o, + output logic tval_filter_o, + output logic [te_pkg::XLEN-1:0] upper_tval_o, + output logic [te_pkg::XLEN-1:0] lower_tval_o, + output logic [te_pkg::XLEN-1:0] match_tval_o, + output logic tval_mode_o, + output logic priv_lvl_filter_o, + output logic [te_pkg::PRIV_LEN-1:0] upper_priv_o, + output logic [te_pkg::PRIV_LEN-1:0] lower_priv_o, + output logic [te_pkg::PRIV_LEN-1:0] match_priv_o, + output logic priv_lvl_mode_o, + output logic iaddr_filter_o, + output logic [te_pkg::XLEN-1:0] upper_iaddr_o, + output logic [te_pkg::XLEN-1:0] lower_iaddr_o, + output logic [te_pkg::XLEN-1:0] match_iaddr_o, + output logic iaddr_mode_o, + + output logic trace_enable_o, // turned off by filter + output logic trace_activated_o, // managed by user + // packet_emitter settings and control + output logic nocontext_o, + output logic notime_o, + output logic encoder_mode_o, // hardwired to 0 - can only be 0 according to spec + output te_pkg::ioptions_s configuration_o, + output logic lossless_trace_o, + output logic shallow_trace_o, + + output logic clk_gated_o, + + // APB I/O interface + input logic [APB_ADDR_WIDTH-1:0] paddr_i, + input logic pwrite_i, + input logic psel_i, + input logic penable_i, + input logic [31:0] pwdata_i, + output logic pready_o, + output logic [31:0] prdata_o +); + + // FFs I/Os + logic trace_enable_d, trace_enable_q; + // trace enabling + logic trace_req_off, trace_req_on; + logic turn_on, turn_off; + logic clk_gated; + logic test_enabled; + + // registers I/O + logic cause_filter_d, cause_filter_q; + logic [te_pkg::XLEN-1:0] upper_cause_d, upper_cause_q; + logic [te_pkg::XLEN-1:0] lower_cause_d, lower_cause_q; + logic [te_pkg::XLEN-1:0] match_cause_d, match_cause_q; + logic cause_mode_d, cause_mode_q; + logic tvec_filter_d, tvec_filter_q; + logic [te_pkg::XLEN-1:0] upper_tvec_d, upper_tvec_q; + logic [te_pkg::XLEN-1:0] lower_tvec_d, lower_tvec_q; + logic [te_pkg::XLEN-1:0] match_tvec_d, match_tvec_q; + logic tvec_mode_d, tvec_mode_q; + logic tval_filter_d, tval_filter_q; + logic [te_pkg::XLEN-1:0] upper_tval_d, upper_tval_q; + logic [te_pkg::XLEN-1:0] lower_tval_d, lower_tval_q; + logic [te_pkg::XLEN-1:0] match_tval_d, match_tval_q; + logic tval_mode_d, tval_mode_q; + logic priv_lvl_filter_d, priv_lvl_filter_q; + logic [te_pkg::PRIV_LEN-1:0] upper_priv_d, upper_priv_q; + logic [te_pkg::PRIV_LEN-1:0] lower_priv_d, lower_priv_q; + logic [te_pkg::PRIV_LEN-1:0] match_priv_d, match_priv_q; + logic priv_lvl_mode_d, priv_lvl_mode_q; + logic iaddr_filter_d, iaddr_filter_q; + logic [te_pkg::XLEN-1:0] upper_iaddr_d, upper_iaddr_q; + logic [te_pkg::XLEN-1:0] lower_iaddr_d, lower_iaddr_q; + logic [te_pkg::XLEN-1:0] match_iaddr_d, match_iaddr_q; + logic iaddr_mode_d, iaddr_mode_q; + logic trace_activated_d, trace_activated_q; + logic nocontext_d, nocontext_q; + logic notime_d, notime_q; + te_pkg::ioptions_s configuration_d, configuration_q; + logic lossless_trace_d, lossless_trace_q; + logic shallow_trace_d, shallow_trace_q; + + // APB transaction + logic read_access; + logic write_access; + logic setup_d, setup_q; + + // assignments + // filter + assign cause_filter_o = cause_filter_q; + assign upper_cause_o = upper_cause_q; + assign lower_cause_o = lower_cause_q; + assign match_cause_o = match_cause_q; + assign cause_mode_o = cause_mode_q; + assign tvec_filter_o = tvec_filter_q; + assign upper_tvec_o = upper_tvec_q; + assign lower_tvec_o = lower_tvec_q; + assign match_tvec_o = match_tvec_q; + assign tvec_mode_o = tvec_mode_q; + assign tval_filter_o = tval_filter_q; + assign upper_tval_o = upper_tval_q; + assign lower_tval_o = lower_tval_q; + assign match_tval_o = match_tval_q; + assign tval_mode_o = tval_mode_q; + assign priv_lvl_filter_o = priv_lvl_filter_q; + assign upper_priv_o = upper_priv_q; + assign lower_priv_o = lower_priv_q; + assign match_priv_o = match_priv_q; + assign priv_lvl_mode_o = priv_lvl_mode_q; + assign iaddr_filter_o = iaddr_filter_q; + assign upper_iaddr_o = upper_iaddr_q; + assign lower_iaddr_o = lower_iaddr_q; + assign match_iaddr_o = match_iaddr_q; + assign iaddr_mode_o = iaddr_mode_q; + // packet emitter + assign configuration_o = configuration_q; + assign lossless_trace_o = lossless_trace_q; // if == 1 stalls the core when the encapsulator buffer is full + assign shallow_trace_o = shallow_trace_q; // if == 1 flushes the branch map at each packet emitted + assign nocontext_o = nocontext_q; + assign notime_o = notime_q; + assign encoder_mode_o = '0; // hardwired + assign trace_activated_o = trace_activated_q; + + // tracing is switched on only when it's not enabled anc a request of turning on is received + assign turn_on = (trace_enable_q == 0) && (trace_req_on /*|| encapsulator_ready_i*/); // encapsulator signal is temporarely disabled + // tracing is switched off only when it's not enabled anc a request of turning off is received + assign turn_off = (trace_enable_q == 1) && (trace_req_off /*|| ~encapsulator_ready_i*/); + // the toggle of trace_enable value happens only when turn off or turn off is asserted + assign trace_enable_d = (turn_off || turn_on) ? ~trace_enable_q : trace_enable_q; + assign trace_enable_o = trace_enable_d; + + assign clk_gated_o = clk_gated; + assign test_enabled = '0; + + assign setup_d = psel_i && ~penable_i; + assign pready_o = setup_q && psel_i && penable_i; + assign read_access = pready_o && !pwrite_i; + assign write_access = pready_o && pwrite_i; + + /* APB read and write */ + always_comb begin + // initialization + // set _d as _q, because we don't to erase them all + cause_filter_d = cause_filter_q; + cause_mode_d = cause_mode_q; + tvec_filter_d = tvec_filter_q; + tvec_mode_d = tvec_mode_q; + tval_filter_d = tval_filter_q; + tval_mode_d = tval_mode_q; + priv_lvl_filter_d = priv_lvl_filter_q; + priv_lvl_mode_d = priv_lvl_mode_q; + iaddr_filter_d = iaddr_filter_q; + iaddr_mode_d = iaddr_mode_q; + lower_priv_d = lower_priv_q; + upper_priv_d = upper_priv_q; + match_priv_d = match_priv_q; + trace_activated_d = trace_activated_q; + lossless_trace_d = lossless_trace_q; + shallow_trace_d = shallow_trace_q; + notime_d = notime_q; + nocontext_d = nocontext_q; + configuration_d = configuration_q; + upper_cause_d = upper_cause_q; + lower_cause_d = lower_cause_q; + match_cause_d = match_cause_q; + upper_tvec_d = upper_tvec_q; + lower_tvec_d = lower_tvec_q; + match_tvec_d = match_tvec_q; + upper_tval_d = upper_tval_q; + lower_tval_d = lower_tval_q; + match_tval_d = match_tval_q; + upper_iaddr_d = upper_iaddr_q; + lower_iaddr_d = lower_iaddr_q; + match_iaddr_d = match_iaddr_q; + prdata_o = '0; // clean output + + if (read_access) begin + case (paddr_i[7:0]) + // XLEN agnostic (or always <= than 32) + // FILTER + // enable and mode + te_pkg::CAUSE_ENABLE_MODE: begin + prdata_o[0] = cause_filter_q; + prdata_o[1] = cause_mode_q; + end + + te_pkg::TVEC_ENABLE_MODE: begin + prdata_o[0] = tvec_filter_q; + prdata_o[1] = tvec_mode_q; + end + + te_pkg::TVAL_ENABLE_MODE: begin + prdata_o[0] = tval_filter_q; + prdata_o[1] = tval_mode_q; + end + + te_pkg::PRIV_ENABLE_MODE: begin + prdata_o[0] = priv_lvl_filter_q; + prdata_o[1] = priv_lvl_mode_q; + end + + te_pkg::IADDR_ENABLE_MODE: begin + prdata_o[0] = iaddr_filter_q; + prdata_o[1] = iaddr_mode_q; + end + + // priv + te_pkg::PRIV_RANGE: begin + prdata_o[te_pkg::PRIV_LEN-1:0] = lower_priv_q; + prdata_o[te_pkg::PRIV_LEN*2-1:te_pkg::PRIV_LEN] = upper_priv_q; + end + + te_pkg::PRIV_MATCH: begin + prdata_o[te_pkg::PRIV_LEN-1:0] = match_priv_q; + end + + // TRACE MANAGEMENT + te_pkg::TRACE_STATE: begin + prdata_o[0] = trace_activated_q; + end + + te_pkg::LOSSLESS_TRACE: begin + prdata_o[0] = lossless_trace_q; + end + + te_pkg::SHALLOW_TRACE: begin + prdata_o[0] = shallow_trace_q; + end + + // PACKET EMITTER + te_pkg::NO_TIME: begin + prdata_o[0] = notime_q; + end + + te_pkg::NO_CONTEXT: begin + prdata_o[0] = nocontext_q; + end + + te_pkg::DELTA_ADDRESS: begin + prdata_o[0] = configuration_q.delta_address_en; + end + te_pkg::FULL_ADDRESS: begin + prdata_o[0] = configuration_q.full_address_en; + end + te_pkg::IMPLICIT_EXCEPTION: begin + prdata_o[0] = configuration_q.implicit_exception_en; + end + te_pkg::SIJUMP: begin + prdata_o[0] = configuration_q.sijump_en; + end + te_pkg::IMPLICIT_RETURN: begin + prdata_o[0] = configuration_q.implicit_return_en; + end + te_pkg::BRANCH_PREDICTION: begin + prdata_o[0] = configuration_q.branch_prediction_en; + end + te_pkg::JUMP_TARGET_CACHE: begin + prdata_o[0] = configuration_q.jump_target_cache_en; + end + + `ifdef TE_ARCH64 // 64bits case + // FILTER + // cause + te_pkg::CAUSE_UPPER: begin + prdata_o[te_pkg::XLEN-1:0] = upper_cause_q; + end + + te_pkg::CAUSE_LOWER: begin + prdata_o[te_pkg::XLEN-1:0] = lower_cause_q; + end + + te_pkg::CAUSE_MATCH: begin + prdata_o[te_pkg::XLEN-1:0] = match_cause_q; + end + + // tvec + te_pkg::TVEC_UPPER_L: begin // least significant bits + prdata_o = upper_tvec_q[31:0]; + end + + te_pkg::TVEC_UPPER_M: begin // most significant bits + prdata_o = upper_tvec_q[63:32]; + end + + te_pkg::TVEC_LOWER_L: begin // least significant bits + prdata_o = lower_tvec_q[31:0]; + end + + te_pkg::TVEC_LOWER_M: begin // most significant bits + prdata_o = lower_tvec_q[63:32]; + end + + te_pkg::TVEC_MATCH_L: begin // least significant bits + prdata_o = match_tvec_q[31:0]; + end + + te_pkg::TVEC_MATCH_M: begin // most significant bits + prdata_o = match_tvec_q[63:32]; + end + + // tval + te_pkg::TVAL_UPPER_L: begin // least significant bits + prdata_o = upper_tval_q[31:0]; + end + + te_pkg::TVAL_UPPER_M: begin // most significant bits + prdata_o = upper_tval_q[63:32]; + end + + te_pkg::TVAL_LOWER_L: begin // least significant bits + prdata_o = lower_tval_q[31:0]; + end + + te_pkg::TVAL_LOWER_M: begin // most significant bits + prdata_o = lower_tval_q[63:32]; + end + + te_pkg::TVAL_MATCH_L: begin // least significant bits + prdata_o = match_tval_q[31:0]; + end + + te_pkg::TVAL_MATCH_M: begin // most significant bits + prdata_o = match_tval_q[63:32]; + end + + // iaddr + te_pkg::IADDR_UPPER_L: begin // least significant bits + prdata_o = upper_iaddr_q[31:0]; + end + + te_pkg::IADDR_UPPER_M: begin // most significant bits + prdata_o = upper_iaddr_q[63:32]; + end + + te_pkg::IADDR_LOWER_L: begin // least significant bits + prdata_o = lower_iaddr_q[31:0]; + end + + te_pkg::IADDR_LOWER_M: begin // most significant bits + prdata_o = lower_iaddr_q[63:32]; + end + + te_pkg::IADDR_MATCH_L: begin // least significant bits + prdata_o = match_iaddr_q[31:0]; + end + + te_pkg::IADDR_MATCH_M: begin // most significant bits + prdata_o = match_iaddr_q[63:32]; + end + + `else // 32bits case + // FILTER + // cause + te_pkg::CAUSE_UPPER: begin + prdata_o[te_pkg::XLEN-1:0] = upper_cause_q; + end + + te_pkg::CAUSE_LOWER: begin + prdata_o[te_pkg::XLEN-1:0] = lower_cause_q; + end + + te_pkg::CAUSE_MATCH: begin + prdata_o[te_pkg::XLEN-1:0] = match_cause_d; + end + + // tvec + te_pkg::TVEC_UPPER: begin + prdata_o = upper_tvec_q; + end + + te_pkg::TVEC_LOWER: begin + prdata_o = lower_tvec_q; + end + + te_pkg::TVEC_MATCH: begin + prdata_o = match_tvec_q; + end + + // tval + te_pkg::TVAL_UPPER: begin + prdata_o = upper_tval_q; + end + + te_pkg::TVAL_LOWER: begin + prdata_o = lower_tval_q; + end + + te_pkg::TVAL_MATCH: begin + prdata_o = match_tval_q; + end + + // iaddr + te_pkg::IADDR_UPPER: begin + prdata_o = upper_iaddr_q; + end + + te_pkg::IADDR_LOWER: begin + prdata_o = lower_iaddr_q; + end + + te_pkg::IADDR_MATCH: begin + prdata_o = match_iaddr_q; + end + `endif + endcase + end else if (write_access) begin + + + case (paddr_i[7:0]) + // common cases + te_pkg::CAUSE_ENABLE_MODE: begin + cause_filter_d = pwdata_i[0]; + cause_mode_d = pwdata_i[1]; + end + + te_pkg::TVEC_ENABLE_MODE: begin + tvec_filter_d = pwdata_i[0]; + tvec_mode_d = pwdata_i[1]; + end + + te_pkg::TVAL_ENABLE_MODE: begin + tval_filter_d = pwdata_i[0]; + tval_mode_d = pwdata_i[1]; + end + + te_pkg::PRIV_ENABLE_MODE: begin + priv_lvl_filter_d = pwdata_i[0]; + priv_lvl_mode_d = pwdata_i[1]; + end + + te_pkg::IADDR_ENABLE_MODE: begin + iaddr_filter_d = pwdata_i[0]; + iaddr_mode_d = pwdata_i[1]; + end + + // priv + te_pkg::PRIV_RANGE: begin + lower_priv_d = pwdata_i[te_pkg::PRIV_LEN-1:0]; + upper_priv_d = pwdata_i[te_pkg::PRIV_LEN*2-1:te_pkg::PRIV_LEN]; + end + + te_pkg::PRIV_MATCH: begin + match_priv_d = pwdata_i[te_pkg::PRIV_LEN-1:0]; + end + + // TRACE MANAGEMENT + te_pkg::TRACE_STATE: begin + trace_activated_d = pwdata_i[0]; + end + + te_pkg::LOSSLESS_TRACE: begin + lossless_trace_d = pwdata_i[0]; + end + + te_pkg::SHALLOW_TRACE: begin + shallow_trace_d = pwdata_i[0]; + end + + // PACKET EMITTER + te_pkg::NO_TIME: begin + notime_d = pwdata_i[0]; + end + + te_pkg::NO_CONTEXT: begin + nocontext_d = pwdata_i[0]; + end + + te_pkg::DELTA_ADDRESS: begin + configuration_d.delta_address_en = pwdata_i[0]; + end + + te_pkg::FULL_ADDRESS: begin + configuration_d.full_address_en = pwdata_i[0]; + end + + te_pkg::IMPLICIT_EXCEPTION: begin + configuration_d.implicit_exception_en = pwdata_i[0]; + end + + te_pkg::SIJUMP: begin + configuration_d.sijump_en = pwdata_i[0]; + end + + te_pkg::IMPLICIT_RETURN: begin + configuration_d.implicit_return_en = pwdata_i[0]; + end + + te_pkg::BRANCH_PREDICTION: begin + configuration_d.branch_prediction_en = pwdata_i[0]; + end + + te_pkg::JUMP_TARGET_CACHE: begin + configuration_d.jump_target_cache_en = pwdata_i[0]; + end + + `ifdef TE_ARCH64 + // cause + te_pkg::CAUSE_UPPER: begin + upper_cause_d = pwdata_i[te_pkg::XLEN-1:0]; + end + + te_pkg::CAUSE_LOWER: begin + lower_cause_d = pwdata_i[te_pkg::XLEN-1:0]; + end + + te_pkg::CAUSE_MATCH: begin + match_cause_d = pwdata_i[te_pkg::XLEN-1:0]; + end + + // tvec + te_pkg::TVEC_UPPER_L: begin // least significant bits + upper_tvec_d[31:0] = pwdata_i; + end + + te_pkg::TVEC_UPPER_M: begin // most significant bits + upper_tvec_d[63:32] = pwdata_i; + end + + te_pkg::TVEC_LOWER_L: begin // least significant bits + lower_tvec_d[31:0] = pwdata_i; + end + + te_pkg::TVEC_LOWER_M: begin // most significant bits + lower_tvec_d[63:32] = pwdata_i; + end + + te_pkg::TVEC_MATCH_L: begin // least significant bits + match_tvec_d[31:0] = pwdata_i; + end + + te_pkg::TVEC_MATCH_M: begin // most significant bits + match_tvec_d[63:32] = pwdata_i; + end + + // tval + te_pkg::TVAL_UPPER_L: begin // least significant bits + upper_tval_d[31:0] = pwdata_i; + end + + te_pkg::TVAL_UPPER_M: begin // most significant bits + upper_tval_d[63:32] = pwdata_i; + end + + te_pkg::TVAL_LOWER_L: begin // least significant bits + lower_tval_d[31:0] = pwdata_i; + end + + te_pkg::TVAL_LOWER_M: begin // most significant bits + lower_tval_d[63:32] = pwdata_i; + end + + te_pkg::TVAL_MATCH_L: begin // least significant bits + match_tval_d[31:0] = pwdata_i; + end + + te_pkg::TVAL_MATCH_M: begin // most significant bits + match_tval_d[63:32] = pwdata_i; + end + + // iaddr + te_pkg::IADDR_UPPER_L: begin // least significant bits + upper_iaddr_d[31:0] = pwdata_i; + end + + te_pkg::IADDR_UPPER_M: begin // most significant bits + upper_iaddr_d[63:32] = pwdata_i; + end + + te_pkg::IADDR_LOWER_L: begin // least significant bits + lower_iaddr_d[31:0] = pwdata_i; + end + + te_pkg::IADDR_LOWER_M: begin // most significant bits + lower_iaddr_d[63:32] = pwdata_i; + end + + te_pkg::IADDR_MATCH_L: begin // least significant bits + match_iaddr_d[31:0] = pwdata_i; + end + + te_pkg::IADDR_MATCH_M: begin // most significant bits + match_iaddr_d[63:32] = pwdata_i; + end + `else // 32 bits case + // cause + te_pkg::CAUSE_UPPER: begin + upper_cause_d = pwdata_i[te_pkg::XLEN-1:0]; + end + + te_pkg::CAUSE_LOWER: begin + lower_cause_d = pwdata_i[te_pkg::XLEN-1:0]; + end + + te_pkg::CAUSE_MATCH: begin + match_cause_d = pwdata_i[te_pkg::XLEN-1:0]; + end + + // tvec + te_pkg::TVEC_UPPER: begin + upper_tvec_d = pwdata_i; + end + + te_pkg::TVEC_LOWER: begin + lower_tvec_d = pwdata_i; + end + + te_pkg::TVEC_MATCH: begin + match_tvec_d = pwdata_i; + end + + // tval + te_pkg::TVAL_UPPER: begin + upper_tval_d = pwdata_i; + end + + te_pkg::TVAL_LOWER: begin + lower_tval_d = pwdata_i; + end + + te_pkg::TVAL_MATCH: begin + match_tval_d = pwdata_i; + end + + // iaddr + te_pkg::IADDR_UPPER: begin + upper_iaddr_d = pwdata_i; + end + + te_pkg::IADDR_LOWER: begin + lower_iaddr_d = pwdata_i; + end + + te_pkg::IADDR_MATCH: begin + match_iaddr_d = pwdata_i; + end + `endif + endcase + end + end + + // clock gating module + pulp_clock_gating i_clock_gating( + .clk_i (clk_i), + .en_i (trace_activated_o), + .test_en_i(test_enabled), + .clk_o (clk_gated) + ); + + // edge detector for trace_req_on_i + // turns on and off the tracing + edge_detect i_edge_detect_on( + .clk_i(clk_gated), + .rst_ni(rst_ni), + .d_i(trace_req_on_i), + .re_o(trace_req_on), + .fe_o() + ); + + // edge detector for trace_req_off_i + // turns on and off the tracing + edge_detect i_edge_detect_off( + .clk_i(clk_gated), + .rst_ni(rst_ni), + .d_i(trace_req_off_i), + .re_o(trace_req_off), + .fe_o() + ); + + always_ff @(posedge clk_i, negedge rst_ni) begin + if(~rst_ni) begin + trace_enable_q <= '1; + // storing config parameters + cause_filter_q <= '0; + upper_cause_q <= '0; + lower_cause_q <= '0; + match_cause_q <= '0; + cause_mode_q <= '0; + tvec_filter_q <= '0; + upper_tvec_q <= '0; + lower_tvec_q <= '0; + match_tvec_q <= '0; + tvec_mode_q <= '0; + tval_filter_q <= '0; + upper_tval_q <= '0; + lower_tval_q <= '0; + match_tval_q <= '0; + tval_mode_q <= '0; + priv_lvl_filter_q <= '0; + upper_priv_q <= '0; + lower_priv_q <= '0; + match_priv_q <= '0; + priv_lvl_mode_q <= '0; + iaddr_filter_q <= '0; + upper_iaddr_q <= '0; + lower_iaddr_q <= '0; + match_iaddr_q <= '0; + iaddr_mode_q <= '0; + configuration_q.delta_address_en <= '0; // delta address only one mandatory //FIXME changing this for debug + configuration_q.full_address_en <= '1; + configuration_q.implicit_exception_en <= '0; + configuration_q.sijump_en <= '0; + configuration_q.implicit_return_en <= '0; + configuration_q.branch_prediction_en <= '0; + configuration_q.jump_target_cache_en <= '0; + lossless_trace_q <= '0; + shallow_trace_q <= '0; + nocontext_q <= '1; + notime_q <= '0; + trace_activated_q <= '1; + setup_q <= '0; + end else begin + trace_enable_q <= trace_enable_d; + // storing config parameters + cause_filter_q <= cause_filter_d; + upper_cause_q <= upper_cause_d; + lower_cause_q <= lower_cause_d; + match_cause_q <= match_cause_d; + cause_mode_q <= cause_mode_d; + tvec_filter_q <= tvec_filter_d; + upper_tvec_q <= upper_tvec_d; + lower_tvec_q <= lower_tvec_d; + match_tvec_q <= match_tvec_d; + tvec_mode_q <= tvec_mode_d; + tval_filter_q <= tval_filter_d; + upper_tval_q <= upper_tval_d; + lower_tval_q <= lower_tval_d; + match_tval_q <= match_tval_d; + tval_mode_q <= tval_mode_d; + priv_lvl_filter_q <= priv_lvl_filter_d; + upper_priv_q <= upper_priv_d; + lower_priv_q <= lower_priv_d; + match_priv_q <= match_priv_d; + priv_lvl_mode_q <= priv_lvl_mode_d; + iaddr_filter_q <= iaddr_filter_d; + upper_iaddr_q <= upper_iaddr_d; + lower_iaddr_q <= lower_iaddr_d; + match_iaddr_q <= match_iaddr_d; + iaddr_mode_q <= iaddr_mode_d; + configuration_q <= configuration_d; + lossless_trace_q <= lossless_trace_d; + shallow_trace_q <= shallow_trace_d; + nocontext_q <= nocontext_d; + notime_q <= notime_d; + trace_activated_q <= trace_activated_d; + setup_q <= setup_d; + end + end + +endmodule \ No newline at end of file diff --git a/corev_apu/instr_tracing/rv_tracer-main/rtl/te_resync_counter.sv b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_resync_counter.sv new file mode 100644 index 0000000000..d8c6f9a8aa --- /dev/null +++ b/corev_apu/instr_tracing/rv_tracer-main/rtl/te_resync_counter.sv @@ -0,0 +1,106 @@ +// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Umberto Laghi +// Contact: umberto.laghi2@unibo.it +// Github: @ubolakes + +/* RESYNC COUNTER */ +/* +It keeps track of the emitted packets or cycles elapsed, +operational mode and threshold are set by the user. + +It produces a signal when the counter reaches the specified +threshold and it remains to 1 until it receives a reset signal. + +In packed mode: the packets that exceeds the defined threshold +are discarded, because they belong to a pre-resync period. +Packets received while the counter is requesting a resync are +ignored. +*/ + +module te_resync_counter #( + parameter N = 1, + parameter MODE = te_pkg::CYCLE_MODE, // counts cycles as default + parameter MAX_VALUE = 16'hFFFF // default max value, can be personalized + ) + ( + input logic clk_i, + input logic rst_ni, + + input logic trace_enabled_i, // it comes from filter + input logic [N-1:0] packet_emitted_i, + input logic resync_rst_i, + + output logic gt_resync_max_o, // greater than the max value, in reality MAX_VALUE + output logic et_resync_max_o // equals to the max value, in reality MAX_VALUE-1 + ); + + /* + The packets that exceeds the defined threshold are discarded, + because they belong to a pre-resync period. + Packets received while the counter is requesting a resync are + ignored. + */ + + // signals declaration + logic [$clog2(MAX_VALUE):0] counter_d, counter_q; + logic [$clog2(N):0] n_packets; + logic overflow; + + // assignments + // both for packet and cycle mode + assign et_resync_max_o = counter_d == MAX_VALUE; + assign gt_resync_max_o = counter_d > MAX_VALUE && ~resync_rst_i; + + always_comb begin + // init + counter_d = counter_q; + n_packets = '0; + + // packet mode + if (MODE == te_pkg::PACKET_MODE && trace_enabled_i) begin + // counting the packets received + for (int i = 0; i < N; i++) begin + if (packet_emitted_i[i]) begin + n_packets += 1; + end + end + + // summing the packets counted + for (int i = 0; i < n_packets; i++) begin + if (counter_d <= MAX_VALUE) begin + counter_d += 1; + end + end + end + + // cycle mode + if (MODE == te_pkg::CYCLE_MODE && trace_enabled_i && counter_d <= MAX_VALUE) begin + counter_d += 1; + end + + // synchronous reset + if (resync_rst_i) begin + counter_d = '0; + end + end + + + always_ff @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + counter_q <= '0; + end else begin + counter_q <= counter_d; + end + end + +endmodule \ No newline at end of file diff --git a/corev_apu/tb/ariane_testharness.sv b/corev_apu/tb/ariane_testharness.sv index 3f68612b9d..c200c33daa 100644 --- a/corev_apu/tb/ariane_testharness.sv +++ b/corev_apu/tb/ariane_testharness.sv @@ -682,19 +682,112 @@ module ariane_testharness #( .CAUSE_LEN (iti_pkg::CAUSE_LEN), .ITYPE_LEN (iti_pkg::ITYPE_LEN), .IRETIRE_LEN (iti_pkg::IRETIRE_LEN), + .block_mode(0), .rvfi_to_iti_t(rvfi_to_iti_t), .iti_to_encoder_t(iti_to_encoder_t) - ) i_iti ( + ) i_cva6_iti ( .clk_i (clk_i), .rst_ni (ndmreset_n), // inputs from rvfi .valid_i(rvfi_to_iti.valid), .rvfi_to_iti_i(rvfi_to_iti), - // outputs for the encoder module TODO .valid_o(), .iti_to_encoder_o(iti_to_encoder) ); + logic packet_valid; + te_pkg::it_packet_type_e packet_type; + logic [te_pkg::P_LEN-1:0] packet_length; + logic [te_pkg::PAYLOAD_LEN-1:0] packet_payload; + + rv_tracer #( + .N(1), + .ONLY_BRANCHES(1) + ) i_encoder( + .clk_i (clk_i), + .rst_ni (rst_ni), + .valid_i (iti_to_encoder.valid), + .itype_i (iti_to_encoder.itype), + .cause_i (iti_to_encoder.cause), + .tval_i (iti_to_encoder.tval), + .priv_i (iti_to_encoder.priv), + .iaddr_i (iti_to_encoder.iaddr), + .iretire_i (iti_to_encoder.iretire), + .ilastsize_i (iti_to_encoder.ilastsize), + .time_i (iti_to_encoder.cycles), + .tvec_i ('0), + .epc_i ('0), + .encapsulator_ready_i('1), + .paddr_i ('0), + .pwrite_i ('0), + .psel_i ('0), + .penable_i ('0), + .pwdata_i ('0), + .packet_valid_o (packet_valid), + .packet_type_o (packet_type), + .packet_length_o (packet_length), + .packet_payload_o (packet_payload), + .stall_o (), + .pready_o (), + .prdata_o () + ); + + logic encap_valid; + encap_pkg::encap_fifo_entry_s encap_fifo_entry_i; + encap_pkg::encap_fifo_entry_s encap_fifo_entry_o; + logic encap_fifo_full; + logic encap_fifo_empty; + logic encap_fifo_pop; + + encapsulator i_encapsulator ( + .clk_i (clk_i), + .valid_i (packet_valid), + .packet_length_i (packet_length), + .flow_i ('0), + .timestamp_present_i('1), + //.srcid_i(), + .timestamp_i (rvfi_to_iti.cycles), + //.type_i(), + .trace_payload_i (packet_payload), + .valid_o (encap_valid), + .encap_fifo_entry_o (encap_fifo_entry_i) + ); + + fifo_v3 # ( + .DEPTH(16), + .dtype(encap_pkg::encap_fifo_entry_s) + ) i_fifo_encap ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .flush_i ('0), + .testmode_i('0), + .full_o (encap_fifo_full), + .empty_o (encap_fifo_empty), + .usage_o (), + .data_i (encap_fifo_entry_i), + .push_i (encap_valid), + .data_o (encap_fifo_entry_o), + .pop_i (encap_fifo_pop) + ); + localparam DATA_LEN = 8; + + logic slicer_valid; + logic [DATA_LEN-1:0] slice; + logic [$clog2(DATA_LEN)-4:0] valid_bytes; + + slicer_DPTI #( + .SLICE_LEN(DATA_LEN), + .NO_TIME ('0) + ) i_slicer ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .valid_i (!encap_fifo_empty), + .encap_fifo_entry_i(encap_fifo_entry_o), + .fifo_full_i ('0), // usrFull DPTI in ariane_xilinx + .valid_o (slicer_valid), + .slice_o (slice), + .done_o (encap_fifo_pop) + ); cva6_rvfi #( .CVA6Cfg (CVA6Cfg), diff --git a/verif/regress/Instr_tracing_test.sh b/verif/regress/Instr_tracing_test.sh new file mode 100755 index 0000000000..e4a0078b48 --- /dev/null +++ b/verif/regress/Instr_tracing_test.sh @@ -0,0 +1,127 @@ +#!/bin/bash + +# Copyright 2025 Thales DIS design services SAS +# +# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# You may obtain a copy of the License at https://solderpad.org/licenses/ +# +# Author: Maxime Colson - Thales + +# Usage ./compare_iti_trace.sh +# Exit 0 if iti traces match, 1 otherwise. + +exit_error() { + echo "$1" >&2 + exit ${2:-1} +} + +clean_file_preserve_header() { + local input_f="$1" + local output_f="$2" + local start_skip="$3" + local end_skip="$4" + + local total_lines lines_to_keep + total_lines=$(wc -l < "$input_f") + lines_to_keep=$((total_lines - start_skip - end_skip)) + + if [ "$lines_to_keep" -le 0 ]; then + exit_error "Error: not enought lines in $input_f" + fi + + { + head -n1 "$input_f" + tail -n "+$((start_skip + 1))" "$input_f" | head -n "$lines_to_keep" + } | sed $'s/\r$//'> "$output_f" +} + +if [ "$#" -ne 1 ]; then + exit_error "Usage: $0 " 2 +fi + +exe="$1" +base=$(basename "$exe" .o) +mkdir verif/sim/Instr_tracing_artifact +workdir="$(realpath verif/sim/Instr_tracing_artifact)" + + +if ! bash verif/regress/iti_test.sh "$exe"; then + exit_error "Error: iti_test.sh failed" +fi + +if [ ! -f verif/sim/iti.traces ]; then + exit_error "Error: iti.traces does not exist" +fi +if [ ! -f verif/sim/encaps.traces ]; then + exit_error "Error: encaps.traces does not exist" +fi + +cp verif/sim/iti.traces "$workdir/iti.trace" +cp verif/sim/encaps.traces "$workdir/encaps.trace" + +rm verif/sim/iti.traces +rm verif/sim/encaps.traces + +cd "$workdir" +git clone https://github.com/riscv-non-isa/riscv-trace-spec.git +cd riscv-trace-spec +git checkout dca761264721068c4576eebd206e2c8b0b9d58b6 +cd referenceFlow +bash scripts/build.sh + +tmp_riscv="$workdir/riscv-trace-spec/referenceFlow/tests/test_files/$base.riscv" +cd ../../.. +cp "$exe" "$tmp_riscv" +cd Instr_tracing_artifact/riscv-trace-spec/referenceFlow +if ! ./scripts/run_regression.sh -t itype3_debug --annotate --debug $tmp_riscv; then + exit_error "Error: run_regression failed" +fi + +reg_dir=$(ls -td ./regression_* 2>/dev/null | head -n1) +if [ -z "$reg_dir" ]; then + exit_error "Error: Folder regression does not exist" +fi + +iti_out="$reg_dir/itype3_debug/$base.encoder_input" +if [ ! -f "$iti_out" ]; then + exit_error "Error: $iti_out does not exist" +fi +encod_out="$reg_dir/itype3_debug/$base.te_inst" +if [ ! -f "$iti_out" ]; then + exit_error "Error: $encod_out does not exist" +fi + +cp "$iti_out" "$workdir/iti_reg.trace" +cp "$encod_out" "$workdir/encod_reg.trace" + +clean_file_preserve_header "$workdir/iti_reg.trace" "$workdir/iti_reg_cleaned.trace" 6 2 +clean_file_preserve_header "$workdir/iti.trace" "$workdir/iti_cleaned.trace" 7 0 + +if diff -q "$workdir/iti_reg_cleaned.trace" "$workdir/iti_cleaned.trace" > /dev/null; then + echo "SUCESS: Same ITI Traces" +else + diff -u "$workdir/iti_reg_cleaned.trace" "$workdir/iti_cleaned.trace" + exit_error "FAILED: ITI traces do not match" +fi + +decapsuler_path="$workdir/../../../corev_apu/instr_tracing/Decapsuler" + +if ! make -C "$decapsuler_path"; then + exit_error "Error: Compilation of Decapsuler failed" +fi + +if ! "$decapsuler_path/Decapsuler" "$workdir/encaps.trace"; then + exit_error "Error: Decapsulation failed" +fi + +clean_file_preserve_header "$workdir/encod_reg.trace" "$workdir/encod_reg_cleaned.trace" 3 2 +clean_file_preserve_header "$workdir/encaps.csv" "$workdir/encaps_cleaned.trace" 3 0 + +if diff -q "$workdir/encod_reg_cleaned.trace" "$workdir/encaps_cleaned.trace" > /dev/null; then + echo "SUCESS: Same Encoder Packets" +else + python3 "$decapsuler_path/diff_color.py" "$workdir/encaps.csv" "$workdir/encod_reg.trace" + exit_error "FAILED: Encoder Packets do not match" +fi \ No newline at end of file diff --git a/verif/regress/iti_test.sh b/verif/regress/iti_test.sh index a787b89a32..1b914d202a 100644 --- a/verif/regress/iti_test.sh +++ b/verif/regress/iti_test.sh @@ -1,12 +1,20 @@ -# Copyright 2021 Thales DIS design services SAS +# Copyright 2025 Thales DIS design services SAS # # Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 # You may obtain a copy of the License at https://solderpad.org/licenses/ # -# Original Author: Jean-Roch COULON - Thales - +# Author: Maxime Colson - Thales + +if [ "$#" -eq 1 ]; then + ELF_ARG="$1" +elif [ "$#" -gt 1 ]; then + echo "Usage: $0 " + exit 1 +else + ELF_ARG="../tests/custom/ITI/test_iti_asm.o" +fi # where are the tools if ! [ -n "$RISCV" ]; then echo "Error: RISCV variable undefined" @@ -14,7 +22,7 @@ if ! [ -n "$RISCV" ]; then fi if ! [ -n "$DV_SIMULATORS" ]; then - DV_SIMULATORS=vcs-testharness,spike + DV_SIMULATORS=vcs-testharness fi # install the required tools @@ -40,9 +48,8 @@ cd verif/sim/ make -C ../.. clean make clean_all -python3 cva6.py --elf_tests ../tests/custom/ITI/test_iti_asm.o --target cv32a65x --iss_yaml cva6.yaml --iss=$DV_SIMULATORS --linker=../../config/gen_from_riscv_config/cv32a65x/linker/link.ld $DV_OPTS -#python3 cva6.py --c_tests ../tests/custom/ITI/test_iti_asm.c --iss_yaml cva6.yaml --target cv32a65x --iss=$DV_SIMULATORS --linker=../../config/gen_from_riscv_config/cv32a65x/linker/link.ld --gcc_opts="$CC_OPTS" $DV_OPTS -cp iti.trace ../../.gitlab-ci +python3 cva6.py --elf_tests "$ELF_ARG" --target cv32a60x --iss_yaml cva6.yaml --iss=$DV_SIMULATORS --linker=../../config/gen_from_riscv_config/cv32a60x/linker/link.ld $DV_OPTS +#python3 cva6.py --c_tests ../tests/custom/ITI/test_iti_asm.c --iss_yaml cva6.yaml --target cv32a60x --iss=$DV_SIMULATORS --linker=../../config/gen_from_riscv_config/cv32a65x/linker/link.ld --gcc_opts="$CC_OPTS" $DV_OPTS make -C ../.. clean make clean_all diff --git a/verif/tests/custom/ITI/iti_asm.S b/verif/tests/custom/ITI/iti_asm.S index 19904977b5..de4e8674f3 100644 --- a/verif/tests/custom/ITI/iti_asm.S +++ b/verif/tests/custom/ITI/iti_asm.S @@ -14,7 +14,7 @@ branch_test: - c.li x12,10 + li x12,10 loop: bne x13,x13, branch_test bne x13,x13, branch_test @@ -28,8 +28,8 @@ branch_test: bne x13,x13, branch_test bne x13,x13, branch_test bne x13,x13, branch_test - c.addi x12, -1 - c.bnez x12, loop + addi x12,x12, -1 + bne x12, x0, loop - c.jr ra + jalr x0,0(ra)