- srcs/tb/tb_saolei_play.v:受 cmd.txt 驱动的交互式 TB,每 100us 轮询一个按键字符, 每 1ms 把显存 dump 到 now.txt - tools/play_saolei.tcl:xsim 里 k c / k u / k f 一步一按键,自动把 now.txt 画到终端 - saolei/tools/fb2png.py:新增 --term,用 ANSI 24 位色在终端画 40x30 棋盘,光标格反色 - .gitignore:放行 create_project_saolei.tcl 实测:k c 进关卡、k uuuu 光标精确移动 4 格、k c 首击展开出数字 1/2
94 lines
3.9 KiB
Tcl
94 lines
3.9 KiB
Tcl
# =============================================================================
|
||
# play_saolei.tcl —— 没有 VGA 显示器时,在 xsim 命令行里"玩"扫雷
|
||
#
|
||
# 用法(建议用 source -encoding utf-8 加载本文件,否则 xsim 默认按 GBK 读,中文注释会乱):
|
||
# cd <某个空目录,例如 _tmp/saolei_sim>
|
||
# xvlog -d SAOLEI_ROM -i <pipelined-cpu/srcs/board> -i <pipelined-cpu/srcs/rtl> \
|
||
# <pipelined-cpu/srcs/rtl/*.v> <pipelined-cpu/srcs/board/cpu21_board_top.v> \
|
||
# <pipelined-cpu/srcs/tb/tb_saolei_play.v>
|
||
# xelab -d SAOLEI_ROM -top tb_saolei_play -snapshot saolei_play
|
||
# xsim saolei_play -tclbatch <本脚本绝对路径>
|
||
#
|
||
# 然后在 xsim 提示符下敲命令(一个字母就是一步,会立刻重画棋盘):
|
||
# k c 左键点击(= 板上 BTNC)
|
||
# k u / k d / k l / k r 光标 上/下/左/右(也认 w s a d)
|
||
# k f 插旗模式点击(点一下插旗,再点取消;= 按住 SW3 再点)
|
||
# k p 只切换插旗模式开关(不点击)
|
||
# k z 复位(等于重新上电,回到开始界面)
|
||
# k uucc 可以连写:上、上、点、点
|
||
# shot 不按键,只重画一遍当前画面
|
||
# help 键位说明
|
||
#
|
||
# 原理:k 把字符写进 cmd.txt;tb_saolei_play 每 100 us 仿真时间轮询一次并执行按键,
|
||
# 同时每 1 ms 把显存 dump 到 now.txt;k 再调 fb2png.py --term 把画面画到终端。
|
||
# 仿真速度大约是 1 ms 仿真时间 = 0.5 s 墙钟,所以每步等 1~2 秒,比真实慢很多,
|
||
# 但足够用来验证"这个程序真的能玩"。
|
||
# =============================================================================
|
||
|
||
set script_dir [file dirname [file normalize [info script]]]
|
||
set fb2png [file normalize [file join $script_dir .. .. saolei tools fb2png.py]]
|
||
|
||
# 按键字符 -> 人类可读的动作(只用于回显)
|
||
array set KEYNAME {
|
||
c "左键点击" u "上" w "上" d "下" s "下"
|
||
l "左" a "左" r "右"
|
||
f "插旗点击" p "切插旗开关" g "go 键" z "复位"
|
||
}
|
||
|
||
# 每次只把一个字符写进 cmd.txt(TB 每 100 us 读走一个,读完就清空)
|
||
proc send_char {c} {
|
||
set fh [open "cmd.txt" "w"]
|
||
puts -nonewline $fh $c
|
||
close $fh
|
||
}
|
||
|
||
# 先确保 cmd.txt 存在,否则 TB 每 100 us 都会刷一条 could not be opened 警告
|
||
if {![file exists "cmd.txt"]} {
|
||
set fh [open "cmd.txt" "w"]
|
||
close $fh
|
||
}
|
||
|
||
# 把 now.txt 渲染到终端(ANSI 彩色棋盘)
|
||
proc render {} {
|
||
global fb2png
|
||
if {![file exists "now.txt"]} {
|
||
puts " (now.txt not ready yet - run a bit first)"
|
||
return
|
||
}
|
||
if {[catch { exec py $fb2png --term now.txt >@stdout 2>@stderr } err]} {
|
||
puts " render failed: $err"
|
||
puts " try manually: py \"$fb2png\" --term now.txt"
|
||
}
|
||
}
|
||
|
||
proc help {} {
|
||
puts " ---------------- SAOLEI controls (type at the xsim prompt) ----------------"
|
||
puts " k c left click (board BTNC)"
|
||
puts " k u/d/l/r move cursor up/down/left/right (w/s/a/d work too)"
|
||
puts " k f click in flag mode k p toggle flag switch only"
|
||
puts " k z reset k uucc several actions at once"
|
||
puts " shot redraw help this text quit exit"
|
||
puts " PNG screenshot: py \"$::fb2png\" now.txt shot.png"
|
||
puts " ---------------------------------------------------------------------------"
|
||
}
|
||
|
||
# one step: send the key -> advance simulation -> redraw
|
||
proc k {keys} {
|
||
set s [string map {" " "c"} [string tolower $keys]]
|
||
foreach ch [split $s ""] {
|
||
if {[string length $ch] == 0} { continue }
|
||
puts " >> $ch"
|
||
send_char $ch
|
||
run 1500 us
|
||
}
|
||
render
|
||
}
|
||
|
||
proc shot {} { render }
|
||
|
||
# ---- opening: run a little so the start screen is drawn, then show it ----
|
||
help
|
||
puts "booting... (init + draw start screen)"
|
||
run 3 ms
|
||
render
|