VirtualComputer

2025-12-10 0 782

Virtual Computer, Assembler, and Compiler

This project is a virtual 8 bit computer that takes a vector of bytes and runs it as instructions It includes the virtual machine, assembler, and compiler for custom assembly and high level language.

I created a blog post about this project and you can find that on Hashnode. It goes deeper into explaining the different parts of this project.

Add to Your Project

vc_8bit can be added to your Rust project with the terminal command:

cargo add vc_8bit

The code shown below assumes you are using the following modules:

use vc_8bit::{assembly, c_lang, vc_8bit::Computer};

Virtual Computer

The virtual computer works by instantiating the Computer and inserting the program into the ram as bytes.

let bytes = vec![Byte::from_string(\"11010100\"), Byte::from_string(\"1001100\")];
let mut computer: Computer = Computer::new();
computer.ram.insert_bytes(bytes);
computer.run();

The VC (Virtual Computer) is basically a big function that will take an array of bytes and run the instructions associated with the bytes. I have emulated components like a Binary Decoder, RAM, ALU, and CPU.

What the VC does is take the binary and figure out the instructions that go with it. It uses Binary Decoders in a match statement to decide what instruction it is. Every Byte is an instruction. Some examples of instructions are moving from memory to registers, adding the values from one register to another using the ALU. This is why assembly is basically binary. Maybe the binary sequence 01001110 is the MOV instruction. All an assembler does is convert the instructions like CPY, LDR, and ADD to there corrosponding bytes. It gets a little more complex than this. For this VC, the first 6 bits are for the instruction, and the last 2 bits are for the register. If this sounds interesting to you, I highly recommend watching Core Dumpped and his videos.

When working with the VC, remember the RAM has 256 byte limit because the VC is only an 8 bit computer compared to modern 64 bit computers.

Assembler

The assembler works by first assembling the code to binary. It will then turn the binary into an array of bytes.

let value = \"MOV R0 50\";

// assemble code
let contents = assembly::compile_assembly_to_binary(value.to_string());
let bytes = assembly::string_to_bytes(contents.as_str());

// run on VC
let mut computer: Computer = Computer::new();
computer.ram.insert_bytes(bytes);
computer.run();

The assembler will go line by line the code into binary. I created a custom assembly language to work with the VC.

  • HALT: Stops the program
  • STR R0 #0000000: Stores the value in the register to the address in memory
  • LDR R0 #0000000: Loads the value in the memory address to the register
  • MOV R0 #0000000: Moves a byte value into a register
  • CPY R0 R1: Copys the value of 1 register to another
  • SHR R0 #0000000: Shifts a register value by the left many times the number in the byte is
  • SHL R0 #0000000: Shifts a register value by the right however many times the number in the byte is
  • OUT R0: Outputs the value in the register to the console as a byte value
  • MSG R0: Outputs the value in the register to the console as an ASCII character
  • INC R0: Increments the value in the register
  • DEC R0: Decrements the value in the register
  • JMP #0000000: Moves the RAM index
  • JMP_NEG #0000000: Moves the RAM index if the ALU Negative flag is on
  • JMP_ZRO #0000000: Moves the RAM index if the ALU Zero flag is on
  • JMP_ABV #0000000: Moves the RAM index if neither the ALU negative flag or Zero flag is on
  • CMP_NEG R0 #0000000: Moves 11111111 to the register if the ALU negative flag is on. If not, it moves 00000000 to the register
  • CMP_ZRO R0 #0000000: Moves 11111111 to the register if the ALU zero flag is on. If not, it moves 00000000 to the register
  • CMP_ABV R0 #0000000: Moves 11111111 to the register if neither the ALU negative flag or Zero flag is on. If not, it moves 00000000 to the register
  • ADD R0 R1: Adds the byte value from registers 0 and 1 and moves the result to the first register
  • SUB R0 R1: Subtracts the byte value from registers 0 and 1 and moves the result to the first register
  • MUL R0 R1: Multiplies the byte value from registers 0 and 1 and moves the result to the first register
  • DIV R0 R1: Divides the byte value from registers 0 and 1 and moves the result to the first register
  • AND R0 R1: Does an and operation on the bytes from registers 0 and 1 and moves the result to the first register
  • OR R0 R1: Does an or operation on the bytes from registers 0 and 1 and moves the result to the first register
  • XOR R0 R1: Does an exclusive or operation on the bytes from registers 0 and 1 and moves the result to the first register
  • NOT R0: Does a not operation on the byte in register 1 and moves result to it
  • RPRT R0 #0000000: Reads the value in the port at the address and writes the value to register 0. The address needs to be 0 through 7.
  • WPRT R0 #0000000: Writes the value in register 0 to the port at the address. The address needs to be 0 through 7.

The assembler will identify integers, bytes, and hexadecimals:

MOV R0 5 ; moves 5 into R0
MOV R1 0x3A ; moves the hexadecimal 3A (integer 58) to R1
MOV R2 #00110100 ; moves the byte value 00110100 (integer 52) to R2

There is also the %ASSIGN feature which can be used as constants inside the assembly

%ASSIGN VARIABLE_ADDRESS #11110100

MOV R0 37
STR R0 VARIABLE_ADDRESS

Compiler

The compiler works by compiling the code into assembly.

let value = \"print(\'a\');\";

// compile code
let asm = c_lang::compile(value.to_string());

// assemble code
let contents = assembly::compile_assembly_to_binary(&asm);
let bytes = assembly::string_to_bytes(contents.as_str());

// run on VC
let mut computer: Computer = Computer::new();
computer.ram.insert_bytes(bytes);
computer.run();

Language

The language looks like C with a few key distinctions.

There are 3 types:

  • uint8 an unsigned 8 bit integer. Any whole number between 0 and 255.
  • bool a true of false value. Is either 00000000 or 11111111 in binary
  • char a character value. Uses the ASCII codes to convert to binary

There are 5 functions:

  • to_char(uint8) turns a number into a character. This works for numbers 0 – 9. Any number above that will get the ASCII character of that number plus 48. This is because 48 is the ASCII character for 0. Here is an example of th function: char c = to_char(7)
  • out(any) will output the byte value to the console of any type. For example, the value 5 will output 00000101.
  • print(char) will output the character to the console.
  • write_port(uint8, any) will write the byte value to the port number 0 – 7. The address needs to be a constant. For example write_port(2, \'a\') is fine but write_port(99 - 3, \'a\') and write_port(variable, \'a\') will not work.
  • read_port(uint8) will read the byte value from the port address 0 – 7. The address needs to be a constant. For example read_port(2) is fine but read_port(99 - 3) and read_port(variable) will not work.

There is only the if and while statements. The code inside of the statement needs to be seperated by commas and not semicolons. The last line inside the statement can not have a comma. The ending bracket of the statement needs to end with a semicolon. Here is what it looks like:

if (true && 0 == 0) {
    char c = \'a\',
    print(c)
};

All operators work except for the += type of operators. Just use A = A + B instead. For the << and >> operators, the right operand needs to be constant. For example, \'a\' >> 3 works but \'a\' >> 3 + 1 or \'a\' >> variable do not work.

  • ++, -- increment and decrement. Works with uint8.
  • +, -, *, / arithmatic operators. Works with uint8.
  • &&, ||, ==, != logic operators. Works with bool.
  • <<, >> bit shift operators. Shifting amount needs to be constant. Works with any type.
  • &, |, ^, ! and, or, excluseive or, and not operators. Works with any type.
  • = set variable.

There is no way to define functions in this language. Also remember there are only 256 bytes in memory to work with in the VC. This means your program must be less than 255 bytes, and any variables that you use will take up one of those bytes.

Example

This simple program took me 27 bytes to write it in assembly. The compiler was able to use 38 bytes. It\’s not the smartest compiler it works.

uint8 a = 0;

while (a < 5) {
    a = a + 1,
    char c = to_char(a),
    print(c)
}

The assembly output for this code is as follows:

MOV R0 #00000000
STR R0 #11111110 ; store created variable ; BYTE ADDRESS 4
LDR R0 #11111110 ; load variable ; value left
MOV R1 #00000101 ; value right
SUB R0 R1
CMP_NEG R0 ; compare
CPY R3 R0 ; copy value right ; get value for statement
MOV R2 0 ; set R2 to 0
SUB R2 R3 ; check if statement is true
JMP_ZRO 37 ; jump if false
LDR R0 #11111110 ; load variable ; value left
MOV R1 #00000001 ; value right
ADD R0 R1 ; math
STR R0 #11111110 ; store variable
LDR R3 #11111110 ; load variable
MOV R2 48 ; 48 is ascii \'0\'
ADD R3 R2 ; get ascii
CPY R0 R3 ; move value to correct register
STR R0 #11111101 ; store created variable
LDR R2 #11111101 ; load variable
MSG R2 ; print value
JMP 4 ; jump back to start ; BYTE ADDRESS 38
HALT

The binary code that was assembled from this:

110010000000000011000000111111101100010011111110110010010000010100010001111100001100111100000000110010100000000000011011111010100010010111000100111111101100100100000001000000011100000011111110110001111111111011001010001100000000111011001100110000001100000011111101110001101111110111011110111010000000010011111111

下载源码

通过命令行克隆项目:

git clone https://github.com/JBrosDevelopment/VirtualComputer.git

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 VirtualComputer https://www.zuozi.net/33179.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务