The new VHDL disassembler is here !
And the dumb testbench is a great opportunity to collect numbers and figures.
grep '[;]' all_opcodes.log |wc -l 11008 grep 'INV' all_opcodes.log |wc -l 14720
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.
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 if 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 then output_message(SLV_to_bin(diff) & "_"); mismatch := mismatch+1; else 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.
OPCODE=Op_RSVD or OPCODE=Op_INV 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.