参考资料:Operating Systems Foundations with Linux on the Raspberry Pi
CPU模型
- 由ARM CPU可知,我们可以对CPU进行仿真
- 由计算和信息可知,计算对应于CPU、处理器,信息对应于内存、存储器,并且计算的本质是利用物理规律,进行信息处理
- 因此,我们可以将内存、存储器作为中心,同时将CPU、处理器作为改变内存、存储器状态的计算单元
- 我们有如下的存储层次结构。在这里,我们只考虑寄存器、内存
- 寄存器(Register)
- 缓存(Cache)
- 内存(Memory)
- 外存(Storage)
指令集架构和微架构
- 在从数字电路到CPU中,我们对ARM CPU的部分指令进行硬实现。在这里,我们对ARM CPU的部分指令进行软实现
- 硬件/软件接口(指令集架构)
- 操作码(Opcode)
- opcode和ARM指令集一致
- 为了方便起见,指令格式和ARM指令集不一致
- 第0~7位 –> opcode
- 第8~15位 –> argument1
- 第16~23位 –> argument2
- 第24~31位 –> argument3
- 寄存器文件(Register File)
- ARM指令集的寄存器文件包含16个寄存器,其中R0~R12是通用寄存器,R13是栈指针(Stack Pointer,SP),R14是链接寄存器(Link Register,LR),R15是程序计数器(Program Counter,PC)
- 操作码(Opcode)
- 硬件(微架构)
- 配置(Configuration)
- 为了方便起见,存储的单位是指令,而不是字节
- 因为一条指令为32位 = 4B,所以内存大小为1024 * 4B = 4KB
- 程序代码的加载地址为CODE_ADDRESS = 0
- 指令周期(Instruction Cycle)
- 取指(Fetch)
- 从寄存器文件,读取PC
- 从内存,读取指令
- PC加1
- 译码(Decode)
- MOV、MVN包含opcode、argument1、argument2
- 其他指令包含opcode、argument1、argument2、argument3
- 执行(Execute)
- MOV、MVN只支持寄存器-立即数(Register-Immediate)
- 其他指令只支持寄存器-寄存器-寄存器(Register-Register-Register)
- 取指(Fetch)
- 配置(Configuration)
// ----- Hardware/Software Interface (Instruction Set Architecture) -----
* Opcode
* Register File
// Opcode
* And, Exclusive Or, Subtraction, Reverse Subtraction, Addition
* Or, Move, Bit Clear, Move Not
AND = 0; EOR = 1; SUB = 2; RSB = 3; ADD = 4
ORR = 12; MOV = 13; BIC = 14; MVN = 15
// Register File
* General Purpose
* Stack Pointer (SP)
* Link Register (LR)
* Program Counter (PC)
R0 = 0; R1 = 1; R2 = 2; R3 = 3; R4 = 4; R5 = 5; R6 = 6; R7 = 7; R8 = 8; R9 = 9; R10 = 10; R11 = 11; R12 = 12
SP = 13
LR = 14
PC = 15
REGISTER_FILE_SIZE = 16
register_file = [0] * REGISTER_FILE_SIZE
// ----- Hardware (Micro-Architecture) -----
* Configuration
* instruction_cycle()
* fetch()
* decode()
* execute()
// Configuration
MEMORY_SIZE = 1024
memory = [0] * MEMORY_SIZE
CODE_ADDRESS = 0
// (register_file, memory) -> ()
def instruction_cycle(register_file, memory):
// Fetch
instruction = fetch(register_file, memory)
// Decode
(opcode, arguments) = decode(instruction)
// Execute
execute(opcode, arguments, register_file)
// (register_file, memory) -> (instruction)
def fetch(register_file, memory):
instruction = 0
// Get program counter
program_counter = register_file[PC]
// Get instruction
instruction = memory[CODE_ADDRESS + program_counter]
print("[Fetch]")
print(f"instruction: 0x{instruction:08x}")
print()
// Add program counter by 1
register_file[PC] += 1
return instruction
// (instruction) -> (opcode, arguments)
def decode(instruction):
opcode = 0
arguments = ()
// Get opcode
opcode = instruction & 0xFF
print("[Decode]")
print(f"opcode: 0x{opcode:02x}")
// Get arguments
if (opcode == MOV) or (opcode == MVN):
argument1 = (instruction >> 8) & 0xFF
argument2 = (instruction >> 16) & 0xFF
print(f"argument1: 0x{argument1:02x}")
print(f"argument2: 0x{argument2:02x}")
print()
arguments = (argument1, argument2, None)
else:
argument1 = (instruction >> 8) & 0xFF
argument2 = (instruction >> 16) & 0xFF
argument3 = (instruction >> 24) & 0xFF
print(f"argument1: 0x{argument1:02x}")
print(f"argument2: 0x{argument2:02x}")
print(f"argument3: 0x{argument3:02x}")
print()
arguments = (argument1, argument2, argument3)
return (opcode, arguments)
// (opcode, arguments, register_file) -> ()
def execute(opcode, arguments, register_file):
// Register-Immediate
if (opcode == MOV) or (opcode == MVN):
(rd, imm, _) = arguments
if opcode == MOV:
register_file[rd] = imm
else:
register_file[rd] = ~imm
// Register-Register-Register
else:
(rd, rn, rm) = arguments
op1 = register_file[rn]
op2 = register_file[rm]
if opcode == AND:
register_file[rd] = op1 & op2
elif opcode == EOR:
register_file[rd] = op1 ^ op2
elif opcode == SUB:
register_file[rd] = op1 - op2
elif opcode == RSB:
register_file[rd] = op2 - op1
elif opcode == ADD:
register_file[rd] = op1 + op2
elif opcode == ORR:
register_file[rd] = op1 | op2
else:
register_file[rd] = op1 & (~op2)
运行程序
- 软件(程序)
- 汇编器(Assembler)
- 直接将指令翻译为二进制,不支持伪指令、标号
- 加载器(Loader)
- 直接将二进制加载到CODE_ADDRESS = 0,不支持多个程序的链接
- 运行(Run)
- 程序(Program)
- 汇编(Assemble)
- 加载(Load)
- 启动(Boot)
- 打印(Print)
- 汇编器(Assembler)
- 运行结果
- 程序有3条指令,打印结果为R3 = 42
- MOV, R1, 21
- MOV, R2, 21
- ADD, R3, R1, R2
- 取指、译码结果如下,它类似于小端存储
- 0x 00 (None) — 15 (21) — 01 (R1) — 0d (MOV)
- 0x 00 (None) — 15 (21) — 02 (R2) — 0d (MOV)
- 0x 02 (R2) — 01 (R1) — 03 (R3) — 04 (ADD)
- 程序有3条指令,打印结果为R3 = 42
// ----- Software (Program) -----
* run()
* assembler()
* loader()
* instruction_cycle() --> Hardware (Micro-Architecture)
// (register_file, memory) -> ()
def run(register_file, memory):
// Program
program_assembly = [
[MOV, R1, 21],
[MOV, R2, 21],
[ADD, R3, R1, R2]
]
// Assemble
program_binary = assembler(program_assembly)
// Load
loader(program_binary, memory)
// Boot
register_file[PC] = 0
while register_file[PC] < len(program_assembly):
instruction_cycle(register_file, memory)
// Print
print("The result is " + str(register_file[R3]))
// (program_assembly) -> (program_binary)
def assembler(program_assembly):
program_binary = []
for instruction in program_assembly:
// Get opcode
opcode = instruction[0]
// Get arguments
if (opcode == MOV) or (opcode == MVN):
argument1 = instruction[1]
argument2 = instruction[2]
argument3 = 0
else:
argument1 = instruction[1]
argument2 = instruction[2]
argument3 = instruction[3]
instruction_binary = opcode + (argument1 << 8) + (argument2 << 16) + (argument3 << 24)
program_binary.append(instruction_binary)
return program_binary
// (program_binary, memory) -> ()
def loader(program_binary, memory):
program_counter = 0
for instruction_binary in program_binary:
memory[CODE_ADDRESS + program_counter] = instruction_binary
program_counter += 1
// Run program
run(register_file, memory)
// ----- Run Program -----
$ python ./bare_bones_model.py
[Fetch]
instruction: 0x0015010d
[Decode]
opcode: 0x0d
argument1: 0x01
argument2: 0x15
[Fetch]
instruction: 0x0015020d
[Decode]
opcode: 0x0d
argument1: 0x02
argument2: 0x15
[Fetch]
instruction: 0x02010304
[Decode]
opcode: 0x04
argument1: 0x03
argument2: 0x01
argument3: 0x02
The result is 42