好的,我来试着翻译一下...
首先是架构。冯诺伊曼(Von Neumann)与哈佛(Harvard)之间的区别。哈佛结构拥有用于代码和数据的不同内存,而冯诺伊曼则没有。哈佛结构被许多微控制器所使用,并且是我熟悉的架构。
那么从基本的哈佛体系结构开始,您会拥有程序存储器。当微控制器首次启动时,它会执行位于零号内存位置的指令。通常,这是一个跳转到地址命令,其中主代码开始。
现在,当我说指令时,我指的是操作码。操作码是编码成二进制数据的指令 - 通常为8或16位。在某些架构中,每个操作码都是硬编码的,具有特定的含义;在其他架构中,每个位可重要(即,第1位表示检查进位,第2位表示检查零标志等)。因此有操作码,然后有操作码的参数。跳转指令就是一个操作码,以及一个8、16或32位的内存地址,代码会“跳转”到该地址处。也就是说,控制权将被转移到该地址处的指令。这通过操作一个包含下一条要执行的指令地址的特殊寄存器来实现。因此,要跳转到内存位置0x0050,它将用0x0050替换该寄存器的内容。在下一个时钟周期中,处理器将读取该寄存器并定位内存地址并执行那里的指令。
执行指令会导致机器状态的改变。有一个常规状态寄存器,记录有关上一条命令操作的信息(即,如果是加法,则是否需要进位,是否有相应的位等)。还有一个“累加器”寄存器,用于放置指令的结果。指令的参数可以放在几个通用寄存器之一中,也可以放在累加器中或内存地址(数据或程序)中。不同的操作码只能对某些位置中的数据执行。例如,您可能能够将来自两个通用寄存器的数据相加,并将结果显示在累加器中,但不能将来自两个数据内存位置的数据相加,并将结果显示在另一个数据内存位置中。您必须将要使用的数据移动到通用寄存器中,进行加法运算,然后将结果移动到所需的内存位置。这就是为什么汇编语言被认为难以理解的原因。存在着与架构设计的状态寄存器一样多的状态寄存器。更复杂的架构可能会有更多的寄存器,以允许更复杂的命令。更简单的架构可能没有这些。
还有一个称为堆栈的内存区域。对于某些微控制器(如8051),它只是内存中的一个区域。在其他情况下,它可能具有特殊的保护。有一个名为堆栈指针的寄存器,记录着堆栈顶部的内存位置。当您从累加器中“推送”数据到堆栈时,“顶部”内存地址会增加,并且将来自累加器的数据放入先前的地址中。从堆栈中检索或弹出数据时,执行相反的操作:堆栈指针递减,将数据从堆栈中取出并放入累
现在我也大概讲述了指令是如何“执行”的。这时,你需要深入数字逻辑——类似于 VHDL 的东西,比如多路复用器、译码器和真值表等等。这是设计的真正细节,有点棘手。如果你想将内存位置的内容“移动”到累加器中,你需要确定寻址逻辑、清除累加器寄存器、对内存位置处的数据进行与运算等等。把所有这些放在一起看会让人望而生畏,但是如果你已经分别使用 VHDL 或任何数字逻辑方式完成了某些部分(例如寻址、半加器等),你可能知道需要哪些操作。
这与 C 有什么关系呢?编译器将接受 C 指令并将其转换为一系列操作码,以执行所需操作。所有这些基本上都是十六进制数据——一堆由 1 和 0 组成的数据,它们被放置在程序内存的某个位置。这是通过编译器/链接器指令完成的,该指令告诉哪个内存位置用于哪个代码。它被写入芯片上的闪存中,然后当芯片重新启动时,它会跳转到代码内存位置 0x0000 并跳转到程序内存中代码的起始地址,然后开始执行操作码。