Sunday 16 June 2013

Instruction Set

One thing I've learnt about messing around with retrocomputing is when you dig into something, never assume the designer was sober or sane.

There are design decisions that make you think "What ?" on a regular basis. Mixing up connections for no apparent reason. Sometimes the whole design is bonkers - for example the "Invisible Alien Neutralizer".

When I reversed engineered the BIOS in the Odyssey 2 years ago, there was a bit of code that had me baffled, it was bit hacking in an incomprehensible manner. I couldn't step through it and in the end just marked it 'unknown purpose'. Another fellow filled in the gaps later on. It was a routine to calculate the exclusive or of 2 bytes. Which would be fine if the 8048 in the Odyssey 2 didn't actually have an Exclusive Or instruction built in. 

The SM510 is actually relatively sensible.  Still there are wierd things.

The person who designed it has an obsession with "T" in mnemonics. So in the branching code it is used for Transfer (what everyone else calls branch or jump) - T (transfer in page) or TL (Transfer long). Subroutines are indicated with an "M" - I guess for Memory (of return address) so you get TM (see later) and TML (Transfer memory long). Everyone else uses Jump, Jump Subroutine, Branch, Call, but what the heck. Transfer if used is used for register to register transfer (e.g. TAX in the 6502). These conventions date back to things like the 4004 and the TMS1000 in Microcomputing and further back - the PDP-8 has skip instructions.

This wouldn't have been so bad if all the skip instructions didn't begin with T as well. So you have TC (test on carry), TAM (test A = memory) and so on. Everyone else in the world uses variants on SKIP for skip tests SKZ, SKIPZ and so on, but this lot use TA0 (test accumulator is zero). Some of them are backwards (TC tests if carry is zero for example .....). I'm seriously considering producing an alternate mnemonic set just to make it clearer. The indirect jump is not "JIN" or something like that but "ATPL" (A transfer to P-Lower) which isn't actually what it does anyway. (it transfers into the lower 4 bits only).

On the subject of subroutines, what do you think RTN0 and RTN1 do ? Return 0 and 1 ? Wronnnnng. RTN0 is return. RTN1 is return and skip. The COP series (NS 4 bitters) has the same thing but uses RET and RETSK.

Then there's ADD11. Now, I thought this was a copier smear when I saw this first, but it's in all the documents. Have a guess at what it does ?

Nope, it doesn't ADD11. It has nothing at all to do with 11, or two 1's (Though there is an ADX 11 which does add the constant 11 - the X is probably for consistency with LAX 11 which is load 11 constant, wich still doesn't explain the X anyway). 

The stock Add (add memory to A) is called ADD - it just adds it and changes nothing else. ADD11 is add with carry in, carry out and skip on carry. I did wonder if it was related to the opcode value, but as that's 09 that's somewhat unlikely.

Why not ADC, ADCSK or something that gives some resemblance to what the opcode actually does ?


Then there's TM. It took me ages to figure out what this actually does. According to the data sheet it does:

TM x      C0-FF   R<-S<-PC+1,PU<-0,PM<-0
                  PL<-x(I5-I0),PU<-y(I7-I6)
IDX yz    00-FF   PL<-z(I5-I0),PM<-(0100) base2

which is pretty obvious ...... no (the datasheet doesn't tell you what x,y,z are). And it says it's a two byte instruction. It isn't. Well, it sort of is, it's just the two bytes are nowhere near each other. Most two byte instructions are consecutive.

It describes it as an indexed jump, which means whoever wrote it didn't know the difference between indexing and indirection. I figured it out with the help of the Patent and deductive reasoning.

What it actually is is a one byte subroutine call. The TM x (e.g. TM 20) refers to a byte in Page 0. This byte is split into two bits - the lower 6 bits go to the program counter, the upper 2 bits have 16 added to them and go in the page register. 

This baffled me for ages because the instruction set actually has a two byte long subroutine call (TL) which on the face of it does the same thing. The advantage that the TM call has is that each call uses only one byte of code memory - and one byte of memory in page 0 which is the indirect address - but the byte in page 0 is only required once. So if you call the same subroutine 10 times you use 11 bytes, whereas TL uses 20.

The instruction does a second fetch at the point of the comma in the middle line. Of course, it doesn't bother to say this.

There is an example of it in the datasheet which takes half a page to make this utterly unclear.

Finally the leap of faith. There are two different 3A opcode instructions (ADX 10 and DC). Both add 10 to the accumulator and leave the carry flag unchanged. One skips on carry. The other doesn't. You can't really miss them in the datasheet as they are seperated by one instruction. Well, Sharp, which one is it ?

I hate to guess, but I've gone for the 'skip on carry' one because all the other add constant instructions are skip on carry out. It would be mind numbing to have an add constant instruction which skipped on carry for every value other than 10 being added.

But that gets back to the start ; don't assume sobriety or sanity. In the absence of a Sharp SM5 programmers guide though, in this case I have to.

No comments:

Post a Comment