650Vue Part 7: Status Register Bit Displays
In the previous section, we looked at drawing the values of the AC, XR, YR, SP, and PC registers as seven-segment LED displays, but there was one register missing—SR, the status register.
The status register is different from the other 6502 registers. While we can express
SR as a single byte value, it's more useful for a programmer to see the 8 individual bits it is
composed of, because each bit corresponds to a processor 'flag' that can be either on or off. The
flags, from left to right, are usually represented by the letters NV-BDIZC
, which
stand for: Negative, oVerflow, "unused", Break, Decimal mode,
Interrupt disable, Zero, and Carry. (We'll talk about the flags in more detail
in a later update, but you can
read more
if you're curious.) To see the full code for the SR display, please see my
commit in Github.
We can show the status register's eight bit flags as a row of eight lights. If a bit is 1, the
light will be lit up; if the bit is 0, the light will be dark. It's not actually necessary to
to check each flag individually in order to power these lights, because SR lives in the Vuex
store as a single 8-bit value. All we need to do is convert the value in SR into an 8-digit
binary number padded with leading zeros, and that string will tell us which lights should be
lit. For example, if we have bits 5, 4, and 0 set to "on", and all the remaining bits left "off",
then we want our status bits packed into a string like this: 00110001
. The computed
property bits()
in the StatusLights
component turns the value stored
in SR into an 8-bit binary string (Figure 1). Remember that mapState
lets us
simplify this.$store.state.cpu.sr
into this.cpu.sr
:
Displaying the status lights is simple. Because the bits()
computed property
returns a string of ones and zeros, we can simply read off the digits one at a time, from
left to right, and draw the corresponding lights on or off as required. I made two "lamp"
graphics called led_1
and led_0
, and the template in Figure 2
handles the loop:
As you can see from the previous figures, the StatusLights component is actually quite simple. The status register display should look something like the following:
At this point, I indulged in a bit of over-engineering. For the moment, we don't actually care about reading flags individually, because the loop in Figure 2 will let us display the whole set in one go. However, at some point, the virtual machine will need to be able to read, set, and clear flags as it runs. We can define a set of constants—one for each of the eight flags (Figure 4):
I chose to define each flag with its hexadecimal representation because that's how I think of
them after years of writing 6502 machine language. As an alternative, we could define each
flag as a power of two, so that instead of 0x01, 0x02, 0x04 ...
, we'd write
1 << 0, 1 << 1, 1 << 2 ...
both representations are equally valid.
In order to read each flag individually, we need a getter in our Vuex store. Remember how
we don't want to write getters if all we're doing is retrieving a simple store
property? Well, here's a situation where a getter is the right tool for the job—when we need
to manipulate a property before we retrieve it. In this case, we want to pass in one of our flag
constants and let the store tell us if the bit that it represents is on or off. We add the
flagStatus
getter to our store. Figure 5 shows two versions of flagStatus()
.
The first version uses the store's internal state
object, while the second uses
some fancy nested argument destructuring to simplify the notation of the return value:
For example, to find out if the carry flag is on or off, a component just has to call our new
getter like this: this.$store.getters.flagStatus(constants.flags.SR_CARRY)
.
Experienced machine-language programmers will recognize the use of boolean &
as a
bitmask to read the value of a single bit.
Similar to the mapState
helper, Vuex gives us a mapGetters
helper. If we
add ...mapGetters(['flagStatus'])
to our component, we can use the more compact
notation this.flagStatus(constants.flags.SR_CARRY)
.
We already have enough code written to make a very simple running machine. In the next section, we'll look at building some simple control logic and turn this thing on.