Original strength: I wrote a disassembly tool for STM8 by hand
☼
Original
I am planning to play around with STM8 recently, just to clear my inventory, because I have bought several models of STM8 microcontrollers, but I have never used them for DIY. I am not as familiar with STM8 as STM32, the latter is a widely popular ARM core, but STM8 is an exclusive architecture of ST.
STM8 CPU is enhanced on the basis of ST7, and some people say it evolved from 6502, but I don't think so. After studying the history, I found that the three branches of 6805/6811/6809 evolved from Motorola's 6800, and 6502, a CPU with a connection to 6800, are similar to STM8 in terms of registers and instruction sets, but the differences are also great. As an 8-bit MCU, the addressing range of STM8 is as high as 16M bytes (I don't believe ST will equip 8-bit machines with more than 1M ROM or RAM), and there are many addressing modes. Indirect memory access is more complicated than x86, which is even more unbearable for those who are used to RISC CPUs. Well, although the instruction set is complex, the execution speed of STM8 is still fast. Anyway, it will not be developed purely in assembly.
ST does not provide a C compiler for STM8 (there is an assembler), so you need to use a third party. The Cosmic C compiler has a free license version that can be used, which is also recommended by ST, so I installed one to try. ST also officially supports the Raisonance compiler. In addition, IAR also has an STM8 development environment.
I tried to write a C program to test it. I can use STVP to connect to ST-Link to download the program, but I think I still need something that can disassemble and view the compilation results. There is no disassembler in the Cosmic tool chain, nor in ST's assembly tool. Since STVD can track and debug, it should have one, but I couldn't use it.
I might as well write an STM8 disassembler myself and practice how to write it.
First study the instruction set of STM8, which is a typical variable-length instruction set. Except for the prefix byte, the opcode is in one byte. So I made a table according to the manual:
The range that a byte can represent is 0x90, 0x91, 0x92, 0x72, which are used as instruction prefixes. Almost all other byte ranges are used as opcodes. Of course, many instructions have multiple addressing modes (for example, it is necessary to specify who is added to whom in addition), so more than one opcode is used. Including the addressing mode, 256 instructions are not enough, so STM8 expands by adding prefix bytes in front. An example is cut from the manual as follows (this is a variety of encodings of the XOR instruction):
the opcode plus the prefix. Writing a disassembler is a process of writing a table lookup based on the byte data stream. The table I made above only divides the distribution of instructions. The details of the addressing mode still need to be checked in the manual while writing. From the table, the high half byte of the opcode can roughly divide the instructions into several categories, and then use the low half byte to subdivide the instructions. Therefore, the first step of my program decoding is a switch-case structure to divide the tasks:
[C] Plain text view Copy code
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
int
decode_instr(unsigned
char
opcode)
{
switch
(opcode>>4)
{
case
1:
case
0x0A:
case
0x0B:
case
0x0C:
case
0x0D:
case
0x0E:
case
0x0F:
return
decode_group1(opcode);
case
0:
case
3:
case
4:
case
6:
case
7:
return
decode_group2(opcode);
case
5:
if
(Prefix==0x72)
return
|