Continuing to add instructions to the core yesterday I noticed a pattern that had always been there in the code, but which had not previously jumped out at me. Almost every instruction makes changes to one or more bits (or 'flags') in the Program Status Register - the PSR, or PSW as it is sometimes referred to, if described as a Word instead of a Register. I have a couple of unexciting methods in there to get or set the value of a bit in a byte, which look like this:
// Return boolean bit setting (0=false, 1=true)
public bool GetBit(int testValue, int bitMask)
{
return (testValue & bitMask) == bitMask;
}
// Set or clear the specified bit
private int SetBit(int data, int bitMask, bool bitState)
{
return bitState ? data | bitMask : data & ~bitMask;
}
And these are typically called in scenarios like these:
They're also a bit 'clunky' to use, as they need a bitmask passed in as a parameter - not the end of the world, but it does mean you have to think in terms of powers of two when setting or reading bits. Instead of saying 'set bit 7', for example, you have to say 'set the bit masked by value 2^7, or 128). Not especially intuitive - that's why I'm using constants for the bit references in the calls to the methods, as I've just got them all set-up as 1, 2, 4, ... 64, 128.
It seemed like there was a correlation between hitting bits in a byte and twiddling values in an array. You can certainly consider a byte to be nothing more than an 8-element array of bits, and so it seemed plausible that there might be a neater way of addressing an individual bit in a byte to get or set its' value. Interestingly, the designers of the .NET libraries foresaw this requirement and developed the BitArray class - sadly hampered by one or two useability flaws which make it quite arduous to use (like being able to give the BitArray object a value at initialisation, but then not being able to easily change that value later).
So I got to thinking about other ways I could address individual bits in a byte through an array-like interface. Obviously I could re-engineer the PSR class so that it really was an array internally, and then write methods to reference the elements of that array in isolation; I'd also need methods to get and set the value in aggregate form as well, of course, for when I wanted to address the content as a byte. But this didn't seem particularly elegant, and I just knew there'd be a performance penalty to pay too.
But then my new friend the Indexer came to the rescue. The mechanics of using the Indexer mean it doesn't actually care (mostly) what type of object it's the interface to, so long as your code handles the translation of the index value into something that makes sense to the underlying to-be-indexed object. So how about writing some code that turns the index into a bit reference, and then applies essentially the same logic as my bespoke GetBit() and SetBit() methods do...?
Here's what the Indexer code looks like:
Because I implemented the Indexer on the GeneralRegister base class, I also get bit-indexing on all other registers too, not just the PSR. That means it's really easy to copy bit settings from one register to another, such as in the TYA example above where we set the PSR N-flag in bit 7 to whatever the Accumulator's sign in bit 7 is. Oh, and it's a little bit faster overall, too.
Win-Win. :)
case 152: // TYA ImpliedNow they get called from lots of different places as each individual instruction wants to either test or set the value of a specific bit in the PSR. Individually, they don't amount to much of an overhead, but there are occasions when several bit-level operations need to happen in quick succession, or where a tight loop of instructions are repeated based upon the state of a PSR flag, by virtue of a BxC or BxS branch test. Every test or setting of one of these bits has to go through one or other (or sometimes both) of these methods.
...
SR = SetBit(SR, _BIT1_ALSO_SR_ZERO, A == 0);
SR = SetBit(SR, _BIT7_ALSO_SR_NEGATIVE, GetBit(A, _BIT7_ALSO_SR_NEGATIVE));
case 233: // SBC Immediate
if(GetBit(SR, _BIT3_ALSO_SR_DECIMAL))
{
... some code that handles Decimal mode subtractions
}
They're also a bit 'clunky' to use, as they need a bitmask passed in as a parameter - not the end of the world, but it does mean you have to think in terms of powers of two when setting or reading bits. Instead of saying 'set bit 7', for example, you have to say 'set the bit masked by value 2^7, or 128). Not especially intuitive - that's why I'm using constants for the bit references in the calls to the methods, as I've just got them all set-up as 1, 2, 4, ... 64, 128.
It seemed like there was a correlation between hitting bits in a byte and twiddling values in an array. You can certainly consider a byte to be nothing more than an 8-element array of bits, and so it seemed plausible that there might be a neater way of addressing an individual bit in a byte to get or set its' value. Interestingly, the designers of the .NET libraries foresaw this requirement and developed the BitArray class - sadly hampered by one or two useability flaws which make it quite arduous to use (like being able to give the BitArray object a value at initialisation, but then not being able to easily change that value later).
So I got to thinking about other ways I could address individual bits in a byte through an array-like interface. Obviously I could re-engineer the PSR class so that it really was an array internally, and then write methods to reference the elements of that array in isolation; I'd also need methods to get and set the value in aggregate form as well, of course, for when I wanted to address the content as a byte. But this didn't seem particularly elegant, and I just knew there'd be a performance penalty to pay too.
But then my new friend the Indexer came to the rescue. The mechanics of using the Indexer mean it doesn't actually care (mostly) what type of object it's the interface to, so long as your code handles the translation of the index value into something that makes sense to the underlying to-be-indexed object. So how about writing some code that turns the index into a bit reference, and then applies essentially the same logic as my bespoke GetBit() and SetBit() methods do...?
Here's what the Indexer code looks like:
// Bit indexerAnd here's what the scenarios now look like to get and set bits in the PSR:
public int this[int index]
{
get
{
// Return zero or one depending on whether the indexed bit is clear or set in the register
return (_register & (1 << index)) == 0 ? 0 : 1;
}
set
{
// Set the value of the indexed register bit according to the value provided (zero or one)
_register = value == 0 ? _register & ~(1 << index) : _register | (1 << index);
}
}
case 152: // TYA ImpliedAs you can see, it's much more intuitive to use - instead of a call to a helper method with appropriate parameters, we're now talking directly to the register object. And we're also using actual bit values to refer to the bits in the byte rather than a bitmask value - I still use constants, but they're just in the range of 0, 1, 2, ... 6, 7 instead of powers of two.
...
_SR[_BIT1_SR_ZERO] = _A.Contents == 0 ? 1 : 0;
_SR[_BIT7_SR_NEGATIVE] = _A[_BIT7_SR_NEGATIVE];
case 233: // SBC Immediate
if(_SR[_BIT3_SR_DECIMAL] == 1)
{
... some code that handles Decimal mode subtractions
}
Because I implemented the Indexer on the GeneralRegister base class, I also get bit-indexing on all other registers too, not just the PSR. That means it's really easy to copy bit settings from one register to another, such as in the TYA example above where we set the PSR N-flag in bit 7 to whatever the Accumulator's sign in bit 7 is. Oh, and it's a little bit faster overall, too.
Win-Win. :)

0 comments:
Post a Comment