The Instruction Set Manual is nearing completion.

As if things weren't serious enough, I'm now reviewing the Load and Store instructions. And since there is none, I removed them.

Confused ? It's normal : the YASEP has no load or store operation. But there were opcodes named after this, thinking they would make people feel more comforable. Which was not the brightest idea ever.

So I removed them and kept the aliases I had created : the Insert and Extract opcodes. As the name says, they insert and extract bytes or half-words (8 or 16 bits).

So far the YASEP had these opcodes : IB IH IHH ESB EZB ESH EZH

End of story ? NO !


Register set ports

The review of the Instruction Set Manual unearthed some concerns I had for a while : the "Load" and "Store" instructions get auxiliary data from other implicit registers. Which can create quite an electronic mess... And it's not flexible enough. It was created for the sake of load and stores, using the "register pair" system where the Address register provides its LSB to the shifting unit, so it knows how much alignment is necessary.

While reviewing the ESB / EZB instructions, I remarked that it was a one-read, one-write instruction (in FORM_RR or FORM_IR). What a waste of coding space, let's make it a RRR or IRR instruction and get rid of the implicit operand that must be fetched in the other registers. Easy, and architecturally much better.

But the Insert instructions (IB and IH) are another beast, they need 3 operands and a destination. The first operand is the register that contains the data to insert, the second is the word that will receive the data, and the 3rd operand is the implicit shift count that comes from the corresponding A register if a D register is written...

It's not cool. First there is this rule, that I thought was critical, of having only two read ports for the register set. Second, splitting the register set for performing parallel reads is a trick that can backfire mercilessly later. Going 3reads-1write would be great... At what cost ?

But wait, the YASEP is already 3reads-1write because there are the conditions to read. The microYASEP implements this by passing both halves of the extended instruction through the 2-reads register set. And there is one result that remains unused during the second cycle... That's it !
So in practice, despite the limitations, the microYASEP is a 4-reads 1-write engine. 1 read for condition, 3 reads for operands and the destination register is one of the operands. Great. Now let's create the new flags "READ_DST3" and "IMM_LSB" and change a lot of the code that is already around... Lots of work indeed.

The return of the carry flag

The YASEP has a carry flag and a zero flag so let's put them to good use.

One concern of the YASEP32 when inserting and extracting unaligned half-words, is the case when the offset is 3 bytes : only one byte is available in this case. This means that the result is partial and not working as expected. The simulator sends an error message but that's not very handy. The assembly code that detects this case could take at least a pair of instructions, then there is the leftover to align...

The little stroke of genius is to change the carry flag when such a situation occurs. Then, for the user's code, it's just a matter of a few conditional instructions to increment the pointer and store the remaining byte at the new address (or just skip the alignment sequence). Something like

 ; Unaligned write :
; memory is pointed to by A2:D2,
; the code stores 16 bits located in R1
IH A2 R1 D2 ; set the carry flag if A2's LSB are 11

EZB 1 R1 R2 CARRY ; If out-of-word then
; extract the high byte to temporary register
ADD 1 A2 CARRY ; point to the next byte
IB R2 A2 D2 CARRY ; now D2 points to the next word
; and its value, R1's high byte is inserted
; in D2's lower byte

It's a bit far fetched but it's still RISC.


Is IHH still needed ?

The instruction "Insert Halfword High" is a special case of IH that was created to supplement MOV so the user could overwrite the high half-word of a register. The intended use was this:

 ; put 12345678h in R1
MOV 5678h R1 ; LSB
IHH 1234h R1 ; MSB

A special opcode was needed because IH would get the shift from one of the A registers, or use 0, yet we needed to shift by 2 bytes...

Now we have a new IH that gets the shift amount from a register or an immediate field so things would be great in theory. In practice, there can be only one immediate number so IH is ruled out.

What we need is a MOV instruction that can shift the immediate value by 16 bits. So here we have it : MOVH. The instruction sequence is modified a bit :

 ; put 12345678h in R1
MOVH 1234h R1 ; MSB
OR 5678h R1 ; LSB
YASEP2013 looks better and better...