Instruction sets are an important part of the processor architecture. The Instruction Set has two development aspects, including the CISC (Complex Instruction Set) represented by x86 and the Proteus (simplified instruction set) represented by arm and MIPS ). The goal of CISC is to use at least one or more commands to implement common functions as much as possible. Therefore, the execution circuit corresponding to the command is often complex and focuses on the implementation of hardware functions; instead, it breaks down complex execution circuits, that is, it uses as simple as possible multiple commands to describe the function, and software to reduce hardware complexity, therefore, the requirements for the compiler are relatively high. The command length of CISC is variable, and the execution cycle is not fixed, while the period of the command is fixed, and is often a single cycle. A large number of registers are also a feature of the Proteus.
The focus of this article is not to compare the details of the CPU commands, but to introduce the encoding and decoding of CPU commands. We all know that the CPU assembly line execution process includes finger fetch, decoding, execution, access, and write-back (see blog: CPU command line execution ), however, many people only understand these steps in terms of concept. It is necessary to elaborate on these steps in detail to understand the design and implementation of CPU commands.
We all know that C language is a highly abstract method for solving real problems and processes. Its Syntax mainly includes numerical values, logical operations, and branch control transfer. Numeric operations are addition, subtraction, multiplication, and Division (comparison is also subtraction), logical operations are and, Or, non, XOR, and so on, Branch Control Transfer includes if/else, for, while and other syntaxes. The Assembly Language is a machine-level understanding and construction of the C language. Its commands also include numerical values, logical operations, and branch control transfer. However, a single line of C language may require multiple Assembly commands. At the same time, because the instruction is in the memory, and the CPU access register is much faster than the access memory, the CPU operations are generally carried out in the register, therefore, the assembly language generally needs to add memory and register direct data loading/storage commands. The CPU only recognizes binary input. Therefore, the assembly language can be used as a pseudo-code on the hardware layer, which is easy for developers to note. It is also a low-level language.
Instruction encoding is the process from an assembly language to a binary machine code. It is implemented by the assembler (the compiler converts the C language into an assembly language ). Assume that a simple CPU only supports four functions:
1) Add Rd, RS, RN. The result is RD = Rs + rn.
2) subtract sub Rd, RS, Rn and the result is RD = RS-RN.
3) data transmission mov RD and Rs. The result is RD = Rs.
4) data loading LDR Rd, [RS]. The structure is to assign the address value of the RS register in the memory to RD.
How to encode it?
1) First, the command is divided into two parts: the operation code and the operand. The operation code represents the command function, such as ADD and sub, which represents a specific circuit in the CPU, for example, add represents the addition circuit, sub represents the subtraction circuit, and operand represents the input and output of the function, corresponding to the input and output of the circuit.
2) There are currently four functions, which require at least two bits for encoding. For example, 00 indicates add, 01 indicates sub, 10 indicates mov, and 11 indicates LDR;
3) The operands are encoded. Assume there are 8 registers in total. The RD, RS, and Rn are all one of them, that is, the range of D, S, and N is 0 to 7, it requires at least three bits for encoding. For example, 000 represents r0, 001 represents R1, and so on. 111 represents r7.
To implement the above four functional commands, a total of 2 + 3 + 3 + 3 = 11 bits are required for encoding. For example, sub R6, R1, R2, that is, R1 minus R2 value is assigned to R7, And the encoding is 01 110 001 010.
After understanding the instruction encoding, the Instruction Decoding should be better understood. According to the current program count register PC (assuming that the hardware circuit requires R7 is the register PC) value from the memory machine code command, the value of this machine code is 01 110 001 010. The next process is decoding, that is, sending the first two bits 01 to the decoder and selecting the subtraction circuit; 110: decoding is set to R6, and 001 decoding is set to R1, 010 select R2. for decoding and then execute the command. The execution is the subtraction unit circuit, which computes two inputs (R1, R2) and assigns the result to r6.
The fetch and decoding operations are completed by the CPU control unit (Cu). The execution is completed by Alu (logical operation unit). We can see that ALU is a collection of many types of circuits. The Design of CPU commands is closely related to the instruction code.
The arm and MIPS CPUs are both 32-bit characters long, so the instruction code is 32 bits, which can support and express more functions (operation code) and registers (operands ). For example, if the arm system is R0 to R15, four bits are needed to represent it. Of course, the arm register also has the group concept, that is, the registers that the CPU may see in different working modes may be different, such as R13 and R14. During decoding, not only the instruction operand is used as the input, but also the value of the Current Status Register as the input.
What is the reason for the 16-bit instruction set? It is because the same C language code Can Save 30% of the amount of code by coding with 16-bit instructions than 32-bit encoding. The less code, the less memory occupied, the lower the natural cost. In the MCU field, it is generally cost-sensitive, so 16 is widely used in the MCU field.
The Instruction Design of arm and MIPs is based on 32-bit, and its execution is also 32-bit. How can we implement 16-bit instruction sets in a 32-bit instruction set? We all know the 20% principle, that is, 80% of the instruction usage will reach 20%, So we encode the instruction (which is a subset of the 32-bit instruction, naturally, a small number of BITs can be used for encoding. When using a 16-bit command, we can force it to use only some registers, then, register encoding can be performed with less bits. The 16-bit instruction set can be considered as a subset of the 32-bit instruction set. In the decoding phase, the CPU first converts 16 to the corresponding 32-bit instruction set, and then performs decoding and execution.
Arm's 16-bit instruction set is the thumb instruction set, and MIPS's 16 is the mips16 instruction set. For the seamless switch between the 32-bit Instruction Set and the 16-bit instruction set, see another blog post: automatic switch between the 32-bit and 16-bit instruction sets.