Opcode space statistics

A project log for YGREC8

A byte-wide stripped-down version of the YGREC16 architecture

yann-guidon-ygdesYann Guidon / YGDES 11/20/2023 at 17:530 Comments

The new VHDL disassembler is here !

And the dumb testbench is a great opportunity to collect numbers and figures.

[ASM]$ grep '[;]' all_opcodes.log |wc -l
[ASM]$ grep 'INV' all_opcodes.log |wc -l

This means that among the 65536 possible instructions, 22% may be re-attributed later, but more importantly, this disassembler provides a clearer picture of how the decoder will work later to detect invalid opcodes.

The INV opcode only accounts for 4096 instances, and the reserved opcode 1011 has 4096 more. That's 8192 so far. Oh and there are unused opcodes in the 1010 range.

The above count also includes all the undefined PF fields, as well as some unused bits in the extended opcode range. All those "holes" in the opcode map are flagged with a comment so they can be conveniently tallied.

I have also seen that the CALL imm4 instructions look quite dumb but you never know, some "negative addresses" might be trampolines for functions later, and these short forms allow conditional execution. This proves that "going with the architecture", instead of following the quantitative approach of Patterson & Hennessy, can give rise to new coding patterns, structures and interesting techniques.

Vive l'orthogonalité !


And there is more redundancy :

The assembler checks the immediate value first and if it fits in Imm4 (when applicable), promotes the instruction to Imm4cnd (for the 10 core opcodes). This means to for 10 opcodes, the range -8 to +7 of the Imm8 form is not used. This means 16*10 = 160 unused opcodes.


Update !

The new assembler forces Imm4 to be signed, but the disassembler generates a positive value so only values 0 to 7 are aliased between Imm4 and Imm8, 80 redundant opcodes only (though it still is 160 if the disassembler did output signed numbers and the program counts 640).

The opcode scan identifies 15743 exceptions to the bijection rule. This includes redundancies, reserved opcodes and unaffected bits.

        diff := instruction_word xor instruction_assembled;
        if diff/="0000000000000000" then
           not (diff ="0000111000000000" and i<38976) and --imm4-imm8 confusion for SRI=0..7
           not (diff ="0000000001000000" and instruction_word(15 downto 12)="1010") and -- reserved bit>
           not (i >= 41728 and i <= 41983) and -- reserved extended opcodes, RR
           not (i >= 42752 and i <= 45055) and -- reserved extended opcodes, IR and unused IR bits
           not (instruction_word(15 downto 12)="1011") and -- RSVD opcode
           not (instruction_word(15 downto 12)="1110" and     -- PF opcode
                instruction_word(11 downto 10)                  -- IR, IR2
              & instruction_word( 5 downto 3)/="00000") and     -- SRI
           not (instruction_word(15 downto 12)="1111")   -- reserved opcode
            output_message(SLV_to_bin(diff) & "_");
            mismatch := mismatch+1;
            exceptions := exceptions+1;
          end if;
        end if;


The new scanner contains some logic that skips the invalid opcodes, which also doubles as a definition of invalid instructions for later.

or (OPCODE=Op_PF and   -- PF opcode with IR or IR2 or SRI not cleared
      instruction_word(11 downto 10) & instruction_word( 5 downto 3) /= "00000")
or (OPCODE=Op_EXT1 and
     (( instruction_word(11)='1' or instruction_word(9 downto 8)="11" )   -- 10 EXT1 reserved opcodes
  or  ( instruction_word(10)='0' and instruction_word(6)='1'))) -- unused bit when SRI

The other exceptions are harmless issues of Imm4/Imm8 aliasing or NEVR condition.

The logic complexity is reasonable.