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
