品牌网站建站,做网站的软件叫什么,工程综合承包,电子商务网站前台业务系统主要是没想到这篇文章持续了这么久#xff0c;越学越深#xff0c;愣是又买了一本书《计算机系统概论》#xff0c;当然#xff0c;也看完了#xff0c;受益匪浅。
系统化的学习才是正确的学习方式#xff0c;我大学就没看到过这本书#xff0c;如果早点看到#xff0c;可能…没想到这篇文章持续了这么久越学越深愣是又买了一本书《计算机系统概论》当然也看完了受益匪浅。
系统化的学习才是正确的学习方式我大学就没看到过这本书如果早点看到可能会更好一些当然现在也不晚。
我主要是学习其中原理本质不至于迷失在书中要偏向于实践。
资源环境
LC-3 是一个16位地址空间的虚拟机。
1. 地址空间 0-UInt16.MaxValue (0xFFF)。
2. 通用寄存器8个R0-R7
3. 三个标志寄存器,N ,P, Z
4. PC 寄存器
5. 指令集长度16位操作码固定前四位
6. 支持函数调用指令集
一共16条指令可用14条。
1. BR 条件分支
2. ADD 加法
3. LD Load 加载
4. ST store 存储
5. JSR 跳转到寄存器
6. AND 与运算
7. LDR 加载寄存器
8. STR 存储寄存器
9. RTI 备用
10. NOT 取反
11. LDI 间接寻址 加载
12. STI 存储间接寻址
13. Jump (RET) 跳转 返回
14. reserved 备用
15. LEA 加载偏移寄存器
16. TRAP 中断系统函数调用解析操作
首先通过生成命令汇编asm to bin or obj 文件其实他们的内容是一致的。 第一行指令是汇编指令.ORIG的起始地址所以要先把它提取出来。 其他命令都按照下表的格式进行解析 格式也很简单前四个位是命令头直接匹配后面按照条件位或者寄存器位分割即可。
我这边主要是对 bin文件直接读取省的 obj 文件进制互转了。为了容易理解。 需要处理的命令
在上篇文章所介绍的LC3Edit 软件里输入下边的汇编代码这是第一步。
.ORIG x3000
LEA R0, HELLO_STR
PUTs
HALT
HELLO_STR .STRINGZ Hello World!
WIDTH .FILL x4000
.END汇编的主要含义是加载字符串 hello world! 打印出来然后停止运行。
然后按照2点击 to ASM 汇编然后第三步3就会提示0错误0异常然后第四步就会输出相应的编译文件。
我只选择 hello.bin文件进行解析当然你解析其他相关文件也是一样的逻辑。只是会复杂一些。
bin文件格式如下: 整体逻辑
环境
定义了 内存大小和寄存器以及系统函数调用
public string[] Memory new string[UInt16.MaxValue];
public DictionaryRegisters, UInt16 Reg new DictionaryRegisters, UInt16();
public DictionaryTrapSet, Action Traps new DictionaryTrapSet, Action();/// summary
/// 寄存器定义
/// /summary
public enum Registers
{R0 0, R1, R2, R3, R4, R5, R6, R7, R8, PC
}public UInt16 PC
{get{return Reg[Registers.PC];}set{Reg[Registers.PC] value;}
}/// summary
/// 标志寄存器
/// /summary
public enum FlagRegister
{/// summary/// 正数/// /summaryPOS 1,/// summary/// 0/// /summaryZRO,/// summary/// 负数/// /summaryNEG
}public enum TrapSet
{/// summary/// 从键盘输入/// /summaryTRAP_GETC 0x20,/// summary/// 输出字符/// /summaryTRAP_OUT 0x21,/// summary/// 输出字符串/// /summaryTRAP_PUTS 0x22,/// summary/// 打印输入提示读取单个字符/// /summaryTARP_IN 0x23,/// summary/// 输出字符串/// /summaryTRAP_PUTSP 0x24,/// summary/// 退出程序/// /summaryTRAP_HALT 0x25,
}
/// summary
/// 标志寄存器
/// /summary
public FlagRegister COND { get; set; }//系统调用函数注册
Traps.Add(TrapSet.TRAP_GETC, Trap_GETC);
Traps.Add(TrapSet.TRAP_OUT, TRAP_OUT);
Traps.Add(TrapSet.TRAP_PUTS, TRAP_PUTS);
Traps.Add(TrapSet.TARP_IN, TRAP_IN);
Traps.Add(TrapSet.TRAP_PUTSP, TRAP_PUTSP);
Traps.Add(TrapSet.TRAP_HALT, TRAP_HALT);/// summary
/// 指令集
/// /summary
public enum InstructionSet
{/// summary/// 条件分支/// /summaryBR 0,/// summary/// 加法/// /summaryADD 1,/// summary/// load/// /summaryLD 2,/// summary/// store/// /summaryST 3,/// summary/// 跳转到寄存器/// /summaryJSR 4,/// summary/// 与运算/// /summaryAND 5,/// summary/// 加载寄存器/// /summaryLDR 6,/// summary/// 存储寄存器/// /summarySTR 7,/// summary/// 备用/// /summaryRTI 8,/// summary/// 取反/// /summaryNOT 9,/// summary/// 间接寻址 加载/// /summaryLDI 10,/// summary/// 存储 间接寻址/// /summarySTI 11,/// summary/// 直接跳/// /summaryJMP 12,/// summary/// reserved/// /summaryRES 13,/// summary/// 加载偏移地址/// /summaryLEA 14,/// summary/// 陷阱中断系统函数调用/// /summaryTRAP 15
}入口
入口比较简单直接加载虚拟机执行。
VM VM new VM();
VM.LoadBin(File.ReadAllLines(hello\hello.bin));
VM.Run();
Console.WriteLine(LC_3 !);解析
解析就是把每个命令都解析到具体的命令对象上
public void LoadBin(string[] bincode)
{var ORIG_Base Convert.ToUInt16(bincode.First(), 2);var ORIG ORIG_Base;foreach (var item in bincode.Skip(1)){Memory[ORIG] item;ORIG;}PC ORIG_Base;
}执行
直接执行解析出来的命令集合
从内存中取数据
public void Run()
{IsRuning true;while (IsRuning){var info Memory[PC];var cmd GetCommand(info);switch (cmd.InstructionSet){case InstructionSet.ADD:Add((ADDCommand)cmd);break;case InstructionSet.AND:And((ANDCommand)cmd);break;case InstructionSet.NOT:Not((NOTCommand)cmd);break;case InstructionSet.BR:BR((BRCommand)cmd);break;case InstructionSet.JMP:Jump((JMPCommand)cmd);break;case InstructionSet.JSR:Jump_Subroutine((JSRCommand)cmd);break;case InstructionSet.LD:Load((LDCommand)cmd);break;case InstructionSet.LDI:Load_Indirect((LDICommand)cmd);break;case InstructionSet.LDR:Load_Register((LDRCommand)cmd);break;case InstructionSet.LEA:Load_Effective_address((LEACommand)cmd);break;case InstructionSet.ST:Store((STCommand)cmd);break;case InstructionSet.STI:Store_indirect((STICommand)cmd);break;case InstructionSet.STR:Store_register((STRCommand)cmd);break;case InstructionSet.TRAP:Trap((TRAPCommand)cmd);break;#region 未用case InstructionSet.RTI:break;case InstructionSet.RES:break;#endregion}PC;}Console.WriteLine(虚拟机停止了运行!);
}指令解析统一化
public class ANDCommand : ACommand
{public ANDCommand() : base(InstructionSet.AND){bitInfo.AddInfo(nameof(this.InstructionSet), 15, 12);bitInfo.AddInfo(nameof(this.DR), 11, 9);bitInfo.AddInfo(nameof(this.SR1), 8, 6);bitInfo.AddInfo(nameof(this.IsImmediateNumber), 5, 5, nameof(this.ImmediateNumber), nameof(this.SR2));bitInfo.AddInfo(nameof(this.ImmediateNumber), 4, 0);bitInfo.AddInfo(nameof(this.SR2), 2, 0);}/// summary/// 目的寄存器/// /summarypublic Registers DR { get; set; }/// summary/// 源寄存器1/// /summarypublic Registers SR1 { get; set; }public bool IsImmediateNumber { get; set; }/// summary/// 源寄存器2/// /summarypublic Registers SR2 { get; set; }public UInt16 ImmediateNumber { get; set; }
}初始化的时候根据指令集的前四位操作码直接定位到命令对象对象就会按照指令本身的各个位的含义去初始化各个寄存器等信息。
在解析的时候只需要 GetCommand(info); 即可
public static ACommand GetCommand(string item)
{InstructionSet set (InstructionSet)Convert.ToInt32(new string(item.Take(4).ToArray()), 2);ACommand aCommand null;switch (set){case InstructionSet.BR:{aCommand new BRCommand();aCommand.BinToCommand(item);}break;case InstructionSet.ADD:{aCommand new ADDCommand();aCommand.BinToCommand(item);}break;case InstructionSet.LD:{aCommand new LDCommand();aCommand.BinToCommand(item);}break;case InstructionSet.ST:{aCommand new STCommand();aCommand.BinToCommand(item);}break;case InstructionSet.JSR:{aCommand new JSRCommand();aCommand.BinToCommand(item);}break;case InstructionSet.AND:{aCommand new ANDCommand();aCommand.BinToCommand(item);}break;case InstructionSet.LDR:{aCommand new LDRCommand();aCommand.BinToCommand(item);}break;case InstructionSet.STR:{aCommand new STRCommand();aCommand.BinToCommand(item);}break;case InstructionSet.RTI:{aCommand new RTICommand();aCommand.BinToCommand(item);}break;case InstructionSet.NOT:{aCommand new NOTCommand();aCommand.BinToCommand(item);}break;case InstructionSet.LDI:{aCommand new LDICommand();aCommand.BinToCommand(item);}break;case InstructionSet.STI:{aCommand new STICommand();aCommand.BinToCommand(item);}break;case InstructionSet.JMP:{aCommand new JMPCommand();aCommand.BinToCommand(item);}break;case InstructionSet.RES:{aCommand new RESCommand();aCommand.BinToCommand(item);}break;case InstructionSet.LEA:{aCommand new LEACommand();aCommand.BinToCommand(item);}break;case InstructionSet.TRAP:{aCommand new TRAPCommand();aCommand.BinToCommand(item);}break;}return aCommand;
}指令函数示例
其实就是对特定逻辑操作的封装指令基础操作跟之前的几乎一样。
ADD
public void Add(ADDCommand command)
{if (command.IsImmediateNumber){Reg[command.DR] (ushort)(Reg[command.SR1] command.ImmediateNumber);}else{Reg[command.DR] (ushort)(Reg[command.SR1] Reg[command.SR2]);}Console.WriteLine(${command.DR} : {Reg[command.DR]});Update_flags(Registers.R0);
}AND
public void And(ANDCommand command)
{if (command.IsImmediateNumber){Reg[command.DR] (ushort)(Reg[command.SR1] command.ImmediateNumber);}else{Reg[command.DR] (ushort)(Reg[command.SR1] Reg[command.SR2]);}Console.WriteLine(${command.DR} : {Reg[command.DR]});Update_flags(Registers.R0);
}NOT
public void Not(NOTCommand command)
{Reg[command.DR] (ushort)~Reg[command.SR];Update_flags(Registers.R0);
}JUMP
public void Jump(JMPCommand command)
{PC Reg[command.BaseR];
}Trap
public void Trap(TRAPCommand command)
{Traps.TryGetValue((TrapSet)command.Trapverct, out var action);action?.Invoke();
}运行结果 可喜可贺终于搞出来了。
总结
只能说获益匪浅很多东西就算是很简单你也得动手敲一遍它就成了技能而不仅仅留存在书和脑海的记忆中。
做完一件事情再继续做下一件事情这就是计算机的原理。
当然LC-3细节还有很多没有补足我想对我来讲最重要的事它物理组件之间的逻辑关系而不是其他。
代码地址
https://github.com/kesshei/VirtualMachineDemo.git
https://gitee.com/kesshei/VirtualMachineDemo.git
阅
一键三连呦感谢大佬的支持您的支持就是我的动力!