Sunday, 13 January 2013

In Which We Create A New Mnemonic


I'm working on replacing the 25-byte dirty-row table with the highly compressed 4-byte version, and adjusting / rewriting code appropriately to work with it; part of that effort gave me an opportunity to try out my new toy, LAX #$00. You might recall that I mentioned a couple of posts ago the discovery that whilst LAX Immediate is generally unstable, it actually is stable when loading zero because the bus cross-talk problem between LDA and TAX has no effect when all lines are low. So I found a bit of code that needed to set both .A and .X to zero, and whacked the new instruction in there. And, of course, DASM said "Hey, I recognise LAX, but not that addressing mode - go away you fool!".

Well, we've been here before - HLT has a similar problem, although in that case DASM doesn't recognise it at all. So what we do there is a simple DC.B #$02, which embeds the opcode as a raw hex value, and XVIC obediently halts execution with a JAM exception when it hits it. In this case, I quickly slapped-in a DC.W #$00AB to represent the instruction, ran a couple of tests, and confirmed that XVIC emulates it perfectly - in fact, it even emulates the cross-talk problem with non-zero values. Which is quite awesome, but I wasn't too keen on having those raw hex sequences spattered around in the sourcecode. What to do...?

The answer is to create a little file that holds a couple of DASM macro scripts representing the instructions for HLT and LAX #imm  which I can include in the main assembly file, and then use the macros instead of the raw hex injections - but whereas HLT is a generally-accepted 'undocumented' mnemonic, what should I name the other? I can't call it LAX, because DASM already knows about that instruction and the six stable addressing modes it supports - and I don't want to get into the dark intricacies of writing a macro that overloads an existing mnemonic, allowing the known variants through and handling my special-case situation. Way too much work!

I experimented with LAXZ (nope, too long), LAZ (doesn't mention .X), AXZ (maybe, but a bit cryptic) and finally settled on something a little different which, even though it doesn't fit the 'Load' pattern, I decided was clear and concise, differentiates it from the rest of LAX as a special case, and steers well clear of any other undocumented opcode groups. So, ladies and gentlemen, I give you Zero A and X, ZAX:

 MAC HLT
DC.B #$02 ; [0] HLT (kill CPU by breaking internal T-state register)
ENDM

MAC ZAX
DC.W #$00AB ; [2] LAX Immediate Zero (only stable when operand is zero)
ENDM

Example in real-world use, demonstrating the utter niceness of using just two bytes and two cycles to set both .A and .X to zero:

 LDA _DISPCTRL         ; [3]    ZP get display control byte
ORA #$01 ; [2] set b0 to disable screen/cursor refresh
STA _DISPCTRL ; [3] ZP set display control byte
ZAX ; [2] LAX #$00 (.A = .X = 0)
TAY ; [2]

Cool, eh? :)

No comments:

Post a Comment