| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- #!/bin/bash
- set -euo pipefail
- PROJECT="$(cd "$(dirname "$0")" && pwd)"
- LOG_DIR="$PROJECT/log"
- TD_BIN="${TD_BIN:-/root/TD_4.6.7/TD_4.6.7_Linux/bin/td}"
- UART_DEV="${UART_DEV:-/dev/ttyUSB0}"
- TRACE_TIMEOUT="${TRACE_TIMEOUT:-10}"
- TRACE_MIN_SNAPSHOTS="${TRACE_MIN_SNAPSHOTS:-10}"
- LOCK_FILE="$PROJECT/.ci.lock"
- for cmd in python3 iverilog vvp flock sha256sum awk tee stty; do
- command -v "$cmd" >/dev/null 2>&1 || {
- echo "ERROR: missing command: $cmd"
- exit 2
- }
- done
- [ -x "$TD_BIN" ] || {
- echo "ERROR: TD not executable: $TD_BIN"
- exit 2
- }
- [ -e "$UART_DEV" ] || {
- echo "ERROR: UART device missing: $UART_DEV"
- exit 2
- }
- [ -f "$PROJECT/scripts/run_test.sh" ] || {
- echo "ERROR: missing scripts/run_test.sh"
- exit 2
- }
- [ -f "$PROJECT/scripts/build.sh" ] || {
- echo "ERROR: missing scripts/build.sh"
- exit 2
- }
- [ -f "$PROJECT/scripts/program.sh" ] || {
- echo "ERROR: missing scripts/program.sh"
- exit 2
- }
- [ -f "$PROJECT/host/reference_selftest.py" ] || {
- echo "ERROR: missing host/reference_selftest.py"
- exit 2
- }
- [ -f "$PROJECT/host/trace_ci_check.py" ] || {
- echo "ERROR: missing host/trace_ci_check.py"
- exit 2
- }
- # 防止两个 CI 同时操作同一块 FPGA
- exec 9>"$LOCK_FILE"
- flock -w 300 9 || {
- echo "ERROR: FPGA CI is already running"
- exit 3
- }
- # log/ 永远只代表最近一次 CI
- rm -rf "$LOG_DIR"
- mkdir -p "$LOG_DIR"
- # 清理 TD 以前自动产生的时间戳日志
- rm -f "$PROJECT"/td_*.log
- STARTED="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- GIT_SHA="LOCAL-NOT-GIT"
- GIT_DIRTY="unknown"
- if command -v git >/dev/null 2>&1 &&
- git -C "$PROJECT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
- GIT_SHA="$(git -C "$PROJECT" rev-parse HEAD)"
- if [ -n "$(git -C "$PROJECT" status --porcelain)" ]; then
- GIT_DIRTY="yes"
- else
- GIT_DIRTY="no"
- fi
- fi
- echo "=============================================="
- echo " FPGA PWM TRACE CI"
- echo "=============================================="
- echo "Project : $PROJECT"
- echo "TD : $TD_BIN"
- echo "UART : $UART_DEV"
- echo "Log : $LOG_DIR"
- echo
- set +e
- (
- set -euo pipefail
- echo "=============================================="
- echo "STAGE 1: TESTBENCH"
- echo "=============================================="
- cd "$PROJECT"
- bash scripts/run_test.sh
- echo
- echo "=============================================="
- echo "STAGE 2: REFERENCE SELFTEST"
- echo "=============================================="
- python3 host/reference_selftest.py
- echo
- echo "=============================================="
- echo "STAGE 3: FPGA BUILD"
- echo "=============================================="
- TD_BIN="$TD_BIN" bash scripts/build.sh
- echo
- echo "=============================================="
- echo "STAGE 4: FPGA PROGRAM"
- echo "=============================================="
- TD_BIN="$TD_BIN" bash scripts/program.sh
- echo
- echo "=============================================="
- echo "STAGE 5: UART TRACE"
- echo "=============================================="
- sleep 2
- echo "Configuring UART: $UART_DEV @ 115200 8N1 raw"
- stty -F "$UART_DEV" \
- raw -echo \
- 115200 cs8 -cstopb -parenb \
- -ixon -ixoff -crtscts
- python3 host/trace_ci_check.py \
- "$UART_DEV" \
- --timeout "$TRACE_TIMEOUT" \
- --min-snapshots "$TRACE_MIN_SNAPSHOTS"
- ) 2>&1 | tee "$LOG_DIR/ci.log"
- RC=${PIPESTATUS[0]}
- set -e
- BIT="$PROJECT/build/td/fpga_pwm_trace.bit"
- BIT_SHA256="N/A"
- if [ -s "$BIT" ]; then
- BIT_SHA256="$(sha256sum "$BIT" | awk '{print $1}')"
- fi
- ENDED="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- if [ "$RC" -eq 0 ]; then
- RESULT="PASS"
- else
- RESULT="FAIL"
- fi
- cat > "$LOG_DIR/metadata.txt" <<META
- project=$PROJECT
- git_sha=$GIT_SHA
- git_dirty=$GIT_DIRTY
- host=$(hostname)
- td_bin=$TD_BIN
- uart_dev=$UART_DEV
- bit=$BIT
- bit_sha256=$BIT_SHA256
- started=$STARTED
- ended=$ENDED
- exit_code=$RC
- result=$RESULT
- META
- # TD 每次运行自己产生的 td_时间.log 不保留
- # 完整 CI 输出已经统一保存在 log/ci.log
- rm -f "$PROJECT"/td_*.log
- echo
- echo "=============================================="
- if [ "$RC" -eq 0 ]; then
- echo " CI PASS"
- else
- echo " CI FAIL"
- fi
- echo "=============================================="
- echo "Result : $RESULT"
- echo "Log : $LOG_DIR/ci.log"
- echo "Meta : $LOG_DIR/metadata.txt"
- echo "Bit : $BIT"
- exit "$RC"
|