Hi OpenRISC gurus:

I am having some trouble with the Carry and Overflow flags in the multiply 
instructions.

ORBIS32 specifies the following multiply instructions:
  l.mul   (signed)
  l.muli  (signed, immediate)
  l.mulu  (unsigned)

The "OpenRISC 1000 Architecture Manual" does not specify how to calculate the 
carry and overflow flags for those instructions:

  32-bit Implementation:
  SR[OV] < - overflow
  SR[CY] < - carry

As already discussed in this forum, when running the test suite under or1ksim 
you get different Carry and Overflow results to the or1200 Verilog simulation. 
I guess this issue hasn't really mattered that much in the past because the C 
language (and probably our GCC port) does not usually need those flags. I'm 
also guessing that nobody has tried to run hand-written arithmethic software on 
both the simulator and the or1200 CPU at the same time.

I would like to support the l.mulX instructions on my OR10 CPU, which is 
targeted at FPGAs. Most FPGAs (I have a Xilinx Spartan-6) have built-in 
multipliers, so I would like to conserve resources by using them instead of 
implementing multiplication logic with flip-flops or whatever.

I didn't want to invest much time into this problem, so I thought I could use 
just one signed 33x33->66 bit multiplier for both signed and unsigned integers. 
For signed numbers, I could sign-extend 32-bit integers to 33 bits, for 
unsigned numbers, I could just prepend an extra zero bit. I could derive the 
Carry and Overflow flags from the 66-bit result. I could think harder about it 
and optimise further at a later point in time. I was also planning to add a 
Special Purpose Register and store the high-order 32 bits from the final 64-bit 
result, as discussed in this Forum a few days ago. If I had to calculate the 
full 64 bits, I might as well make them all available to the software.

However, I hit the following test case:

  l.mul -2 * -3 ( 0xfffffffe * 0xfffffffd )

which yields 0x0000000000000006, but or1ksim wanted the Carry flag set in this 
case.

It turns out that, for l.mul (and probably for l.muli too), or1ksim calculates 
the Carry flag as if the multiplicands had been unsigned (it actually performs 
the multiplication twice, one with signed integers, one with unsigned 
integers). This is what l.add does, it sets the Carry flag as if the integers 
had been unsigned, and the Overflow flag as if the integers had been signed. 
However, for l.mulu, or1ksim always clears the Overflow flag.

I looked at the Intel 8086 user manual, and the Carry and Overflow flags are 
set to the same value for both the signed and unsigned multiplication 
instructions. The "OpenRISC 1000 Architecture Manual" states for l.mul "Both 
operands are treated as signed integers.", so setting Overflow and Carry to the 
same value would also make sense for OpenRISC.

I could use an unsigned multiplicator, but that would mean converting to and 
from 2's complement when multiplying signed integers, which adds unnecessary 
extra logic.

I wonder if we could change the OpenRISC specification (and or1ksim's 
implementation) to make our lives easier.

Has anybody got any more thoughts on this?

Thanks,
  rdiez
_______________________________________________
OpenRISC mailing list
[email protected]
http://lists.openrisc.net/listinfo/openrisc

Reply via email to