The BTT instruction on the open8 differs from that of the V8/ARClite.
The V8 version of the instruction uses the subop to create a mask to test the desired bit of R0, and the inverse of the bit is set into the Z Flag:
BTT n Z = R0 & (1 << n) ? 0 : 1 N = R07 & (1 << n)
On the Open8, the subop is used to address the register file, and the Z and N flags are set according to the value of Rn:
BTT n Z = (Rn == 0) N = Rn7
The publicly available description of the BTT instruction for the V8 gives the operation as:
"if R0#=0, Set Z else clear Z"
Indicating the nth bit of R0, not the nth register in the register file, is the correct source to test.
The corrected VHDL would look something like this:
<p> <blockquote> <br> when ALU_BTT => <blockquote> -- Tests if bit n R0 is set or cleared. No change to R0, Flags N, Z <br> -- Flag N is set to R0(7), Flag Z is inverse of R0(Index) <br> Temp := "0" & Regfile(ACCUM); <br> Flags_D(FL_ZERO) <= '0'; <br> if( Temp(Index) = 0 )then <blockquote> Flags_D(FL_ZERO) <= '1'; <br> </blockquote> end if; <br> Flags_D(FL_NEG) <= Temp(7); </blockquote> </blockquote> <p> NB: I haven't compiled or tested this yet.This compiles - I apologize in advance for my VHDL skills...I'm sure there is a one-liner that does the same as the case statement, below.
<blockquote> when ALU_BTT => -- Tests if bit n R0 is set or cleared. No change to R0. Flags N, Z <br> -- Flag N is set to R0(7), Flag Z is inverse of R0(Index) <blockquote> Temp := "0" & not Regfile(0); <p> Flags_D(FL_NEG) <= '0'; <p> case Index is <blockquote>when 0 => <blockquote>Flags_D(FL_ZERO) <= Temp(0); </blockquote> when 1 => <blockquote>Flags_D(FL_ZERO) <= Temp(1); </blockquote> when 2 => <blockquote> Flags_D(FL_ZERO) <= Temp(2); </blockquote> when 3 =><blockquote> Flags_D(FL_ZERO) <= Temp(3);</blockquote> when 4 =><blockquote> Flags_D(FL_ZERO) <= Temp(4);</blockquote> when 5 =><blockquote> Flags_D(FL_ZERO) <= Temp(5);</blockquote>when 6 =><blockquote> Flags_D(FL_ZERO) <= Temp(6);</blockquote>when 7 =><blockquote> Flags_D(FL_ZERO) <= Temp(7);</blockquote> </blockquote> end case; <p> if (Temp(7) = '0') then <blockquote> Flags_D(FL_NEG) <= '1'; </blockquote> end if; </blockquote> </blockquote>From the look of it, and I haven't tested it yet, I would think you could reduce this to:
when ALU_BTT => Flags_D(FL_ZERO) <= not Regfile(0)(Index); Flags_D(FL_NEG) <= Regfile(0)(7);
This assigns Z = !R0(n), where n = subop/index, and N = R0(7).
I believe you are correct - again, I'm not a VHDL programmer - I can read it, but have no claims to writing it.
Incidentally, I have gnu binutils ported to the open8/v8/arclite, and am working through some linker issues this week, as well as starting the port of gcc.
I'm not terribly fluent in Verilog yet, so I'm not clear what is going on with the N flag, but I believe the Z flag is now working correctly, based on what you have found with the original core.
I have uploaded a corrected version to my web host, so I'm going to close this bug for now. If the N bit acts funny, open a new bug, and I'll try to translate the Verilog again.