Skip to content

Commit fc5b9eb

Browse files
committed
fx
1 parent 36f7b2c commit fc5b9eb

File tree

2 files changed

+118
-53
lines changed

2 files changed

+118
-53
lines changed

.github/workflows/evening.yml

Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ jobs:
3333
run: |
3434
cd $GITHUB_WORKSPACE/..
3535
proxychains git clone -b dev_difftest --single-branch --depth 1 https://github.com/OpenXiangShan/env-scripts.git
36+
cd env-scripts
37+
echo "ENV_SCRIPTS_HOME=$(pwd)" >> $GITHUB_ENV
3638
3739
- name: Build NutShell
3840
run: |
3941
cd $NOOP_HOME
4042
make verilog BOARD=fpgadiff MILL_ARGS="--difftest-config ESBIF" -j2
43+
cp -i ./difftest/src/test/vsrc/fpga/fpga_clock_gate.v ./build/rtl/
4144
4245
- name: Create FPGA project
4346
run: |
@@ -46,52 +49,20 @@ jobs:
4649
make update_core_flist CORE_DIR=$DUT_HOME
4750
make vivado CPU=nutshell
4851
49-
- name: Build FPGA bitstream
52+
- name: Build FPGA synth
5053
run: |
5154
source /nfs/home/tools/Xilinx/Vivado/2020.2/settings64.sh
5255
cd $GITHUB_WORKSPACE/../env-scripts/fpga_diff
53-
make bitstream PRJ=fpga_nutshell/fpga_nutshell.xpr
54-
55-
- name: Wait for synthesis & report (nutshell)
56-
run: |
57-
set -euo pipefail
58-
cd "$GITHUB_WORKSPACE/../env-scripts/fpga_diff"
59-
BIT_DIR="fpga_nutshell/fpga_nutshell.runs/impl_1"
60-
REPORT="vivado-analyse.txt"
61-
TIMEOUT_MIN=180
62-
END=$(( $(date +%s) + TIMEOUT_MIN*60 ))
63-
echo "[wait] Waiting Vivado to finish and bitstream to appear..."
64-
while true; do
65-
BIT_OK=$(ls "$BIT_DIR"/*.bit 2>/dev/null || true)
66-
if pgrep -f '[v]ivado' >/dev/null 2>&1; then
67-
VIVADO_ALIVE=yes
68-
else
69-
VIVADO_ALIVE=no
70-
fi
71-
if [ -n "$BIT_OK" ] && [ "$VIVADO_ALIVE" = no ]; then
72-
echo "[wait] Vivado exited and bitstream found."
73-
break
74-
fi
75-
if [ $(date +%s) -gt $END ]; then
76-
echo "[wait] Timeout (${TIMEOUT_MIN}m). Vivado or bitstream not ready." >&2
77-
[ -n "$BIT_OK" ] || echo "[wait] Missing bit file under $BIT_DIR" >&2
78-
echo "[wait] Vivado alive: $VIVADO_ALIVE" >&2
79-
exit 1
80-
fi
81-
sleep 30
82-
done
83-
ls -lh "$BIT_DIR"/*.bit
84-
85-
# Generate report AFTER Vivado finishes
56+
make synth PRJ=fpga_nutshell/fpga_nutshell.xpr
8657
bash ./tools/generate_reports.sh nutshell
87-
test -f "$REPORT" || { echo "[wait] $REPORT not generated" >&2; exit 1; }
8858
8959
- name: Extract Vivado Hierarchical utilization
60+
continue-on-error: true
9061
run: |
9162
set -euo pipefail
92-
IN_PATH="${IN_PATH:-$GITHUB_WORKSPACE/../env-scripts/fpga_diff/vivado-analyse.txt}"
63+
IN_PATH=$ENV_SCRIPTS_HOME/fpga_diff/vivado-analyse.txt"
9364
OUT_PATH="$RUNNER_TEMP/vivado_hier.md"
94-
python3 "$GITHUB_WORKSPACE/scripts/fpga_sim/ci.py" --input "$IN_PATH" --output "$OUT_PATH" --format markdown
65+
python3 "$GITHUB_WORKSPACE/scripts/fpga_sim/ci.py" --input "$IN_PATH" --output "$OUT_PATH" --format markdown --cpu nutshell
9566
echo "VIVADO_HIER_MD=$OUT_PATH" >> "$GITHUB_ENV"
9667
9768
- name: Comment utilization to PR
@@ -102,13 +73,14 @@ jobs:
10273
with:
10374
script: |
10475
const fs = require('fs');
105-
const body = fs.readFileSync(process.env.VIVADO_HIER_MD, 'utf8');
106-
await github.rest.issues.createComment({
107-
owner: context.repo.owner,
108-
repo: context.repo.repo,
109-
issue_number: context.issue.number,
110-
body
111-
});
76+
let body;
77+
try {
78+
body = fs.readFileSync(process.env.VIVADO_HIER_MD, 'utf8');
79+
if (!body.trim()) throw new Error('empty');
80+
} catch (e) {
81+
body = 'Vivado Hierarchical utilization: section missing or extract failed. Please check the job logs for runme.log output.';
82+
}
83+
await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body });
11284
11385
test-fpga-xiangshan-miniconfig:
11486
if: ${{ github.event_name == 'schedule' }}
@@ -152,15 +124,16 @@ jobs:
152124
make update_core_flist CORE_DIR=$DUT_HOME
153125
make vivado CPU=xiangshan
154126
155-
- name: Build FPGA bitstream
127+
- name: Build FPGA synth
156128
run: |
157129
cd $GITHUB_WORKSPACE/../env-scripts/fpga_diff
158-
make bitstream PRJ=fpga_xiangshan/fpga_xiangshan.xpr
130+
make synth PRJ=fpga_xiangshan/fpga_xiangshan.xpr
159131
bash ./tools/generate_reports.sh xiangshan
160132
161133
- name: Print Vivado Hierarchical utilization to logs
162134
run: |
163135
set -euo pipefail
164136
IN_PATH="${IN_PATH:-$GITHUB_WORKSPACE/../env-scripts/fpga_diff/vivado-analyse.txt}"
165137
echo "===== Vivado Hierarchical utilization ====="
166-
python3 "$GITHUB_WORKSPACE/tools/ci/parse_vivado_hier.py" --input "$IN_PATH" --format markdown
138+
# Use unified extractor; it will print env-scripts logs and fail if section missing
139+
python3 "$GITHUB_WORKSPACE/scripts/fpga_sim/ci.py" --input "$IN_PATH" --format markdown --cpu xiangshan

scripts/fpga_sim/ci.py

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@
88
==================== Timing Summaries (end) ====================
99
We also stop at any other delimiter line made of ---- / ==== that is not itself
1010
a Hierarchical utilization header.
11+
12+
If the section is missing, we invoke env-scripts make targets:
13+
make get_impl_log CPU=<cpu>
14+
(fallback) make get_synth_log CPU=<cpu>
15+
and always exit with code 3 so CI marks the step as failed for visibility.
1116
"""
1217

1318
import argparse
1419
import os
1520
import re
1621
import sys
22+
import subprocess
1723

1824
# Header patterns that indicate the beginning of the hierarchical utilization block.
1925
HIER_HEADER_PATTERNS = [
@@ -69,13 +75,98 @@ def extract_section(text):
6975
collected.pop()
7076
return '\n'.join(collected) + '\n'
7177

78+
def infer_cpu_from_path(path: str) -> str:
79+
p = path.lower()
80+
if 'xiangshan' in p:
81+
return 'xiangshan'
82+
return 'nutshell'
83+
84+
def try_print_logs_via_make(start_dir: str, cpu: str) -> bool:
85+
"""Invoke env-scripts make targets to print Vivado logs to stderr.
86+
87+
Tries get_impl_log first, then get_synth_log. Returns True if any output is printed.
88+
"""
89+
# Run make inside env-scripts/fpga_diff (the vivado-analyse.txt directory)
90+
env_root = os.path.abspath(start_dir)
91+
sys.stderr.write(f"[ci.py] using env-scripts/fpga_diff at {env_root}\n")
92+
printed_any = False
93+
for target in ('get_impl_log', 'get_synth_log'):
94+
try:
95+
sys.stderr.write(f"[ci.py] invoking make -C {env_root} {target} CPU={cpu}\n")
96+
proc = subprocess.run(
97+
['make', '-C', env_root, target, f'CPU={cpu}'],
98+
stdout=subprocess.PIPE,
99+
stderr=subprocess.STDOUT,
100+
text=True,
101+
encoding='utf-8',
102+
errors='ignore',
103+
timeout=600,
104+
)
105+
out = proc.stdout or ''
106+
if proc.returncode == 0 and out.strip():
107+
sys.stderr.write(f"[ci.py] ---- BEGIN {target} (CPU={cpu}) ----\n")
108+
sys.stderr.write(out)
109+
if not out.endswith('\n'):
110+
sys.stderr.write('\n')
111+
sys.stderr.write(f"[ci.py] ---- END {target} ----\n")
112+
printed_any = True
113+
# If impl log printed, we can stop; otherwise try synth as fallback
114+
if target == 'get_impl_log':
115+
return True
116+
else:
117+
sys.stderr.write(f"[ci.py] {target} failed (rc={proc.returncode}) or produced no usable output\n")
118+
except Exception as e:
119+
sys.stderr.write(f"[ci.py] failed to run {target}: {e}\n")
120+
return printed_any
121+
122+
# (legacy helper removed; log collection now delegated to make targets)
123+
124+
def try_print_runme_logs_by_path(start_dir: str, cpu: str) -> bool:
125+
"""Fallback: read known runme.log paths directly and print to stderr.
126+
127+
For nutshell:
128+
<start_dir>/fpga_nutshell/fpga_nutshell.runs/{impl_1,synth_1}/runme.log
129+
For xiangshan:
130+
<start_dir>/fpga_xiangshan/fpga_xiangshan.runs/{impl_1,synth_1}/runme.log
131+
"""
132+
cpu = (cpu or 'nutshell').lower()
133+
if 'xiangshan' in cpu:
134+
proj = os.path.join(start_dir, 'fpga_xiangshan')
135+
runs_base = os.path.join(proj, 'fpga_xiangshan.runs')
136+
else:
137+
proj = os.path.join(start_dir, 'fpga_nutshell')
138+
runs_base = os.path.join(proj, 'fpga_nutshell.runs')
139+
140+
printed = False
141+
for stage in ('impl_1', 'synth_1'):
142+
log_path = os.path.join(runs_base, stage, 'runme.log')
143+
if os.path.exists(log_path):
144+
try:
145+
with open(log_path, 'r', encoding='utf-8', errors='ignore') as lf:
146+
content = lf.read()
147+
sys.stderr.write(f"[ci.py] ---- BEGIN {cpu}:{stage} runme.log ----\n")
148+
sys.stderr.write(content)
149+
if not content.endswith('\n'):
150+
sys.stderr.write('\n')
151+
sys.stderr.write(f"[ci.py] ---- END {cpu}:{stage} runme.log ----\n")
152+
printed = True
153+
if stage == 'impl_1':
154+
# Prefer impl_1; if present, no need to fallback to synth_1
155+
return True
156+
except Exception as e:
157+
sys.stderr.write(f"[ci.py] failed reading {log_path}: {e}\n")
158+
else:
159+
sys.stderr.write(f"[ci.py] log not found: {log_path}\n")
160+
return printed
161+
72162
def main():
73163
ap = argparse.ArgumentParser(description='Extract "Hierarchical utilization" section from Vivado report.')
74164
ap.add_argument('-i', '--input', required=True, help='Path to vivado-analyse.txt')
75165
ap.add_argument('-o', '--output', help='Optional output file path')
76166
ap.add_argument('--format', choices=['text', 'markdown'], default='text', help='Output formatting')
77167
ap.add_argument('--fail-missing', action='store_true',
78168
help='Exit with code 3 if section missing (default: do not fail).')
169+
ap.add_argument('--cpu', help='CPU name for env-scripts log helpers (e.g., nutshell, xiangshan). Optional.')
79170
args = ap.parse_args()
80171

81172
if not os.path.exists(args.input):
@@ -87,12 +178,13 @@ def main():
87178

88179
section = extract_section(raw)
89180
if section is None:
90-
msg = 'Hierarchical utilization section not found.'
91-
if args.fail_missing:
92-
sys.stderr.write('[ci.py] ' + msg + '\n')
93-
sys.exit(3)
94-
# Graceful: print note and exit 0
95-
out_text = msg + '\n'
181+
base = os.path.dirname(os.path.abspath(args.input))
182+
cpu = args.cpu or infer_cpu_from_path(base)
183+
ok = try_print_logs_via_make(base, cpu)
184+
if not ok:
185+
try_print_runme_logs_by_path(base, cpu)
186+
sys.stderr.write('[ci.py] Hierarchical utilization section not found.\n')
187+
sys.exit(3)
96188
else:
97189
if args.format == 'markdown':
98190
out_text = 'Vivado Hierarchical utilization:\n\n```txt\n' + section.rstrip('\n') + '\n```\n'

0 commit comments

Comments
 (0)