欢迎光临散文网 会员登陆 & 注册

【深圳 IO 攻略】第 18 关:远程退出开关

2022-06-03 19:17 作者:ココアお姉ちゃん  | 我要投稿

本文首发于 B 站《深圳 IO》文集(https://www.bilibili.com/read/readlist/rl569860)。原创不易,转载请注明出处。

关卡展示

本关要求当你收到 C2S-RF901 发来的数据包时,按照如下规则更新三个电源的开关状态:

  • -1:保持原始状态不变;

  • 0:关闭一个电源,具体关闭的电源由第二个数决定;

  • 1:开启一个电源,具体开启的电源由第二个数决定。

与此同时,当你 5 秒钟内没收到任何数据包时(包括 -1 保持状态的数据包也算在内),关闭所有电源。

这一关我们很容易想到将置位指令和 DX-300 结合使用。我们将电源 0~2 分别和 DX-300 的 p0~p2 口相连,用芯片中的 acc 寄存器记录实时的电源状态。然后:当我们收到 -1 数据包时,不做任何操作;当我们收到以 0 开头的数据包时,将第二个数所指示的位数置 0,并将新的 acc 值发送给 DX-300;当我们收到以 1 开头的数据包时,将第二个数所指示的位数置 1,并将新的 acc 值发送给 DX-300。

可问题在于另一条需求:5 秒钟没收到数据包时要将所有电源关闭。可我们的 acc 已经被占用了,dat 又不能做数学运算,那我该拿什么玩意来计时呢?

其实,计时这方面,我们并不需要 acc 寄存器所支持的所有数学运算。我们只需要两种运算:加一和归零。说到这里,不知道读者有没有一种灵机一动的感觉:上一节提到的 ROM 和 RAM,读数据口时地址值会自增!因此,我们完全可以用 ROM 来实现计时功能!

我们用这样的方法来操作 ROM:

  • 将 ROM 的 4 号地址空间写上 -1(作为关闭所有电源的信号),其余位置保持 0;

  • 收到数据包时,将 ROM 的地址值 0(相当于让计时器归零)

  • 没有收到数据包时,读一下 ROM 的数据口,此时地址值会自己 +1(相当于计时器 +1)。如果读到的数值是 0,那么就维持现状;若读到了 -1,那么就给 DX-300 赋 0,关闭所有的电源。

为什么要在 ROM 的 4 号地址空间里写 -1 呢?因为收到数据包的时候,我们要将地址值置 0,相当于让计时器回到“第 0 秒”。而我们选择在“第 5 秒”时关闭,读第 4 秒的数据时,计时器自增 1 就正好到达了第 5 秒,而我们读到的却仍然是“上一秒”的值。所以我们要“提前预判”,在读第 4 秒的时候就要告知我们的芯片,该关闭全部电源了。

这样,我们就成功借助了 ROM 实现了“第二个 acc”用于计时。电路图和代码如下:

首先我们将当前时钟周期里的首数字读入 dat 暂存(mov x1 dat)。然后我们判断首数字到底是 -999 还是 -1、0、1(tcp dat -2)。如果是 -999,那么读一次 ROM 的数据口,令地址值自增 1,相当于计了 1 秒钟(- tcp x2 0)。如果读到了小于 0 的值,那么就说明是时候关闭所有的电源信号了,将 acc 归零,同时将 DX-300 连接的三个电源输出也都全部归零(- mov 0 x0, - mov 0 acc)。回到开头,如果读到的首数字不是 -999,那么首先将 ROM 的地址值归零,相当于将计时器归零(+ mov 0 x3)。然后进一步判断首数字到底是 -1 还是另两种值。如果首数字是 -1,则我们只把计时器清零,不对 acc 的值做任何改变。如果首数字是 0(teq dat 0),那么读入第二个数字,并将 acc 对应位置(0:个位,1:十位,2:百位)上的数字置为 0(+ dst x1 0);如果首数字是 1(teq dat 1),那么读入第二个数字,并将 acc 对应位置上的数字置为 1(+ dst x1 1)。操作完毕后,将当前的 acc 发送给 DX-300(mov acc x0),然后休眠一秒(slp 1),进入下一个机器周期。

点击左下角的【模拟】,稍等片刻,便会弹出结算界面:

优化电量和代码行数

注意我提到的以上解释说明中的这一部分:

如果首数字是 0(teq dat 0),那么读入第二个数字,并将 acc 对应位置(0:个位,1:十位,2:百位)上的数字置为 0(+ dst x1 0);

如果首数字是 1(teq dat 1),那么读入第二个数字,并将 acc 对应位置上的数字置为 1(+ dst x1 1)。

首数字是 0 时将对应位置 0,首数字是 1 时将对应位置 1。发现了没?这两句话可以合并成“当首数字 >-1 时,将对应位置修改成这个首数字”!我们的代码也可以相应地化简,不需要依次判断 dat 是否为 0 和 1 了,只需要判断 dat 是否大于 -1,满足条件时将 dst 指令中的第二个操作数改成 dat 就行了。于是我们将代码改成了下面这样:

最终的三项指标为:成本 ¥8,电量 287(比历史最佳减少了 147 格电),代码行数 10(比历史最佳减少了 1 行代码)

甚至我们将 mov acc x2 这条指令也加上了 + 号。只有当 acc 的值变化了的时候才需要传给 DX-300,平时没有变化的时候完全不需要反复传同样的信号。

进一步优化电量和代码行数

依然是利用那个“读只写 p 口,或连接着这些 p 口的 DX-300 时,会得到立即数 0,同时清零这些 p 口,一举两得”的技巧,我们将第 4 行和第 5 行的

两行代码合并成下面一行代码:

最终的三项指标为:成本 ¥8,电量 286(比历史最佳少了 1 格电),代码行数 9(比历史最佳少了 1 行代码)

碎碎念

虽然压缩到了 9 行代码,最终也只用了 4 个 x 口,但因为用到了 dat 寄存器,所以这块 MC6000 无法替换成只有四个 x 口的 MC4000X 芯片,成本是降不下来的……

【深圳 IO 攻略】第 18 关:远程退出开关的评论 (共 条)

分享到微博请遵守国家法律