Problem: a radio receiver provides XBus values in a non-blocking fashion (making it different than normal XBus behavior). If there is no value, it will return
-999. If the radio sends a packet containing
1, then the buzzer should turn on. If the packet instead contains a
0, then the buzzer should turn off. The buzzer is controlled via simple I/O. To make the buzzer buzz, its input needs to alternate between 0 and 100 each cycle.
The challenge here is that the radio receiver outputs packets with
1 on XBus, and those packets need to generate behavior that is retained cycle-to-cycle. At the same time, we have three distinct values we might see coming off the XBus, but testing consumes the value, so if we want to test for all values, we need to store the value in
acc so we can reference it multiple times. This creates a need for two pieces of state to be stored. This can be accomplished using two chips, but this introduces a cycle of latency if they interleave incorrectly, which causes the validation to fail. So here's the challenge:
-999(which simply proceeds with the current behavior), we must store whether the buzzer is enabled or not,
0, we have to store the value in
I worked over several hours to develop a solution that synchronizes two MX4000s by ensuring the buzzer status is written to
p1 by the first chip before the second chip reads the value.
The first chip reads from
x0, storing whether the buzzer is enabled on
p1. Since simple I/O is persistent, we use
p1 as a register of sorts:
mov x0 acc mul 100 tgt acc -1 + mov acc p1 end: slp 1
The second chip then reads the value and cycles power to the buzzer if it is enabled. The most interesting part is that it executes
nops until the first chip has written a value:
nop nop nop nop teq p0 100 + mov 100 p1 + slp 1 + mov 0 p1 slp 1
This solution took me a couple hours of thinking, and is much worse than the average solutions! It uses just a touch shy of double the power of most solutions (432 vs. less than 250), uses 2-4 extra lines of code, and costs ¥1 more! So I'm missing something fundamental here that's worth learning.
I spent about 15 minutes thinking about what I could do better. To bring cost down, I swapped two MC4000s for a single MC6000. The strategy here is to add the incoming value to the existing value, which the code must ensure is either
100. I then tease apart whether the buzzer is enabled or not with
teq acc 100, and if so, insert an extra oscillation cycle to avoid storing extra state:
add x0 teq acc -999 + mov 0 acc teq acc -899 + mov 1 acc tgt acc 99 + sub 100 mul 100 mov acc p1 teq acc 100 + slp 1 + mov 0 p1 slp 1
This is effective! Cost is down to ¥5 and power is reduced to 326 (from 432), but it's still a long way from ~250. It only reduces code by 1 line, from 14 to 13, which is still higher than average (12, it appears). What insight am I missing?
It felt like I was using too much power executing tests for various possible values. On this attempt, I tried to collapse as many checks as possible:
add x0 tlt acc 0 + dgt 2 + add 9 - dgt 0 mul 100 mov acc p1 teq acc 100 + slp 1 + mov 0 p1 slp 1
This leaves cost at ¥5, but reduces code to 11 lines and power to 288. Still less efficient than the average solution!!