# ============================================================================= # play_saolei.tcl —— 没有 VGA 显示器时,在 xsim 命令行里"玩"扫雷 # # 用法(建议用 source -encoding utf-8 加载本文件,否则 xsim 默认按 GBK 读,中文注释会乱): # cd <某个空目录,例如 _tmp/saolei_sim> # xvlog -d SAOLEI_ROM -i -i \ # \ # # 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 不按键,只重画一遍当前画面 + 存一张 PNG # view 用系统看图器打开最新那张 PNG # help 键位说明 # # 截图:k 每执行**一个**按键动作就自动存一张 PNG 到 shots/NNN_<按键>.png # (可以直接放进报告),同时覆盖 shots/latest.png。 # 在 VS Code 里打开 shots/latest.png,每次操作后它都会自动刷新 —— 这就是 # "每一步都能看到 PNG" 的用法。 # # 原理: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+screenshot view open latest PNG" puts " help this text quit exit" puts " every key saved one PNG: shots/NNN_.png and shots/latest.png" puts " ---------------------------------------------------------------------------" } # ---- every step saves one PNG: shots/001_c.png ... plus shots/latest.png ---- set shot_dir "shots" file mkdir $shot_dir set shot_n 0 proc save_shot {tag} { global fb2png shot_dir if {![file exists "now.txt"]} { return } incr ::shot_n set name [format "%s/%03d_%s.png" $shot_dir $::shot_n $tag] if {[catch { exec py $fb2png --quiet now.txt $name } err]} { puts " (screenshot failed: $err)" return } catch { file copy -force $name "$shot_dir/latest.png" } puts " png -> $name" } proc view {} { global shot_dir set f [file normalize "$shot_dir/latest.png"] if {![file exists $f]} { puts " (no screenshot yet)"; return } catch { exec cmd /c start "" $f } } # one step: send the key -> advance simulation -> save PNG -> 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 save_shot $ch } render } proc shot {} { save_shot "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