Coder Social home page Coder Social logo

roerohan / 8086.js Goto Github PK

View Code? Open in Web Editor NEW
18.0 6.0 8.0 1.07 MB

A basic web-based 8086 emulator built with Javascript :rocket:

Home Page: https://roerohan.github.io/8086.js

License: MIT License

HTML 6.56% CSS 0.56% JavaScript 92.88%
8086 8086-emulator javascript assembly hacktoberfest2020 hacktoberfest hacktoberfest2021

8086.js's Introduction

Issues

All Contributors


Logo

A basic web-based 8086 emulator built with Javascript.
Explore the docs »

View Demo · Report Bug · Request Feature

Table of Contents

About The Project

8086.js is a basic 8086 emulator built using Javascript, hosted at https://roerohan.github.io/8086.js/.

Built With

Getting Started

To get a local copy up and running follow these simple steps.

Prerequisites

You will need the following to be able to run the project.

Installation

  1. Clone the Repo
git clone https://github.com/roerohan/8086.js.git
  1. Install NPM packages using (npm or yarn)

Using npm

npm install

Using yarn

yarn install

Note: If installing the packages with npm you get errors use yarn to install them.

Usage

Note: 8086.js does not support all instructions, pre-processor directives and interrupts yet. You can check out the supported instructions in the switch-case here.

To run the React App locally, you can run the following command.

  1. Run the React App

Using npm

npm start

Using yarn

yarn start

Basic Workflow

The UI is split into 2 major halves, the right half is the editor and the left half is the emulator. Instructions can be written in the editor, and when they are executed, the registers and memory in the emulator get updated accordingly. There are a few steps which happen in the background to make this possible.

  1. An object of the Emulator class is exported, which is the point of interaction between the frontend and the emulation logic.

  2. First, the lexer divides the source code into tokens and sends them to a parser. The parser is responsible for extracting instructions from the tokens and converting them to a form that the CPU understands.

  3. The CPU reads the mnemonic and the operands that were sent to it by the parser, and according to these values, it executes the instructions.

Note: The communication between the parser and the CPU is NOT in terms of shellcode, i.e, opcodes and operands. The CPU recognizes an instruction by it's mnemonic, such as MOV or ADD.

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'feat: Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

You are requested to follow the contribution guidelines specified in CONTRIBUTING.md while contributing to the project 😄.

License

Distributed under the MIT License. See LICENSE for more information.

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Rohan Mukherjee

💻 📖

Rishit Bansal

💻 📖

Ritika

💻

Rob Capellini

💻

Jose M. Segura Polanco

💻

Pranav P

💻

Namit Nathwani

💻

Sanjana Rai

📖

vikitor566

💻

This project follows the all-contributors specification. Contributions of any kind welcome!

8086.js's People

Contributors

allcontributors[bot] avatar capellini avatar darkcode01 avatar namsnath avatar pranavp22 avatar ritika-07 avatar roerohan avatar sanjana-r avatar thebongy avatar vikitor566 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

8086.js's Issues

Bug related to padding in the Register component

Bug related to padding in the Register component

In the Register component, the values of the registers are displayed in hex and are padded to 4 digits using the padStart function. This works fine when the register is being displayed on the UI.

However, one of the features of 8086.js is that you can edit the value in a register and execute instructions with the updated value. Now, because of the padStart in the UI, updating a register becomes somewhat weird, since you can not delete a number (the padStart function will always ensure that there are 4 characters). So, you would have to add a 5th number to be able to delete a number that is already present.

This can possibly be resolved by using the padStart function when the user focuses out of the register box. This might be related to #18 , since the padding would vary for hex, binary, octal, and decimal numbers.

const displayReg = (r) => r.toString(16).padStart(4, '0');
return (
<div className={classes.regContainer}>
<span className={classes.label}>{name}</span>
<input
id={name}
value={displayReg(regValue)}
onChange={changeRegValue}
className={classes.register}
/>
</div>
);
}

suggestion: use `yarn` to handle dependencies.

I get those errors and alerts that are shown in the image below when I try to install the libraries with npm install I tried clearing the cache but it still did not install the libraries.

Everything worked fine when installed using yarn, my recommendation is to use yarn to manage project dependencies.

Screen Shot 2020-09-24 at 10 24 31 PM

Parser does not recognize relative addressing, and pre-processor directives

Parser does not recognize relative addressing and pre-processor directives

Addressing types

As of now, the parser is very simple and recognizes only Immediate, Register and Direct (Memory) addressing, as you can see in lexer.js. The goal is to support all types of addressing supported by Intel 8086.

Pre-processor directives

The parser does not support pre-processor instructions such as assume, or segments such as the data and the code segment. Support for this is essential for users to be able to create named procedures and store strings, etc. in the data segment.

Instruction validation

Currently, the parser does not do a lot of syntax validation, in parser.js. This might allow instructions such as:

add bx,           ; Notice the trailing comma

Stronger syntax checking needs to be implemented.

parse() {
this.rawInstructions.forEach((instruction) => {
if (instruction.length > 4) {
throw new SyntaxError();
}
if (instruction.length > 2
&& instruction[2].name !== 'SEPARATOR') {
throw new SyntaxError();
}
this.instructions.push(new Instruction({
mnemonic: instruction[0],
op1: instruction[1] || null,
op2: instruction[3] || null,
}));
});

Logo for 8086.js

Logo for 8086.js

This one is about design. 8086.js needs a logo and a favicon (could be the same).

  • The logo will be added to the README.md
  • The favicon will be placed in the public directory.

Please place both (or one if they're the same) the files in the public directory and PR to the dev branch 🥺

Site does not display errors

Site does not display errors

Currently, if the bot runs into an error (that is thrown by the parser or the CPU), it is not caught and displayed on the frontend. The errors are just logged on the console in production.

Ideas

  • A new component would need to be added for displaying errors.
  • Errors could be displayed as a pop up on the top right of the website. We're open to positioning of this pop-up on the UI.
  • You could consider creating a new Redux slice for errors.

Add more 8086 Instructions

Add more Instructions

Currently, 8086.js can only execute the instructions in the switch-case below. However, support needs to be added for the remaining instructions to make it more usable.

Also, some instructions are not implemented properly, which maybe be because of one of the following reasons.

  • They do not set the right flags
  • They do not check the operand sizes before executing the operation.

These need to be fixed to make it behave more like an Intel 8086.

Currently implemented instructions

The following is a list of instructions that have been implemented. They have been written in src/emulator/cpu/core.js, and they use the Addressing class from addressing.js in the same folder.

Note: Relative addressing has not been implemented yet.

switch (mnemonic.value) {
case 'MOV':
if (op1.size < op2.size) {
throw SyntaxError(`Can't move larger ${op2.size} bit value to ${op1.size} bit location`);
}
setAddr(op1, getAddr(op2));
break;
case 'JS':
if (regs.flags.getFlag(flags.sign) === 1) {
ip = getAddr(op1) - 1;
}
break;
case 'JNS': {
if (regs.flags.getFlag(flags.sign) === 0) {
ip = getAddr(op1) - 1;
}
break;
}
case 'JO': {
if (regs.flags.getFlag(flags.overflow) === 1) {
ip = getAddr(op1) - 1;
}
break;
}
case 'JNO': {
if (regs.flags.getFlag(flags.overflow) === 0) {
ip = getAddr(op1) - 1;
}
break;
}
case 'JP':
case 'JPE':
{
if (regs.flags.getFlag(flags.parity) === 1) {
ip = getAddr(op1) - 1;
}
break;
}
case 'JNP':
{
if (regs.flags.getFlag(flags.parity) === 0) {
ip = getAddr(op1) - 1;
}
break;
}
case 'ADD':
if (!op2) {
let s = op1.size === 8 ? regs.AX.get('l') : regs.AX.get();
s += getAddr(op1);
regs.AX.set(s);
} else {
let s = getAddr(op1);
s += getAddr(op2);
setAddr(op1, s);
}
break;
case 'DIV':
if (op1.size === 8) {
const al = regs.AX.get('l') / getAddr(op1);
const ah = regs.AX.get('l') % getAddr(op1);
regs.AX.set(al, 'l');
regs.AX.set(ah, 'h');
} else {
const ax = regs.AX.get() / getAddr(op1);
const dx = regs.AX.get() % getAddr(op1);
regs.AX.set(ax);
regs.DX.set(dx);
}
break;
case 'MUL':
if (op1.size === 8) {
const prod = regs.AX.get('l') * getAddr(op1);
regs.AX.set(prod);
} else {
const prod = regs.AX.get() * getAddr(op1);
regs.AX.set(prod);
// Store higher bits in DX
}
break;
case 'AND':
setAddr(op1, getAddr(op1) & getAddr(op2));
break;
case 'OR':
setAddr(op1, getAddr(op1) | getAddr(op2));
break;
case 'SUB': {
const s1 = getAddr(op1);
const s2 = getAddr(op2);
const ans = s1 - s2;
setAddr(op1, ans);
break;
}
case 'CMP': {
const s1 = getAddr(op1);
const s2 = getAddr(op2);
if (s1 === s2) {
regs.flags.setFlag(flags.zero);
regs.flags.unsetFlag(flags.carry);
} else if (s1 > s2) {
regs.flags.unsetFlag(flags.zero);
regs.flags.unsetFlag(flags.carry);
} else {
regs.flags.setFlag(flags.carry);
regs.flags.unsetFlag(flags.zero);
}
break;
}
case 'NOT': {
setAddr(op1, ~getAddr(op1));
break;
}
case 'JMP': {
ip = getAddr(op1) - 1;
break;
}
case 'JE':
case 'JZ':
{
if (regs.flags.getFlag(flags.zero) === 1) {
ip = getAddr(op1) - 1;
}
break;
}
case 'JNE':
case 'JNZ':
{
if (regs.flags.getFlag(flags.zero) === 0) {
ip = getAddr(op1) - 1;
}
break;
}
default:
break;
}

Implement interrupts and show output on the display

Implement interrupts and show output on the display

We're aiming to support interrupts on 8086.js! The parser can currently recognize INT as a mnemonic. The CPU is required to understand that the INT mnemonic stands for an interrupt. Once this is done, features such as writing output to the display in the UI, taking user input, and exiting the program, etc. can be implemented.

We would prefer a separate class for interrupts.

UI Responsiveness and Theming

UI Responsiveness and Theming

Responsiveness

The bot is deployed here, and as you would notice, it isn't very responsive, and doesn't scale too well according to screensize, especially on mobile phones. This might be a useful reference.

Theming

The scrollbars on the page do not go well with the dracula theme that has been used for the UI.

Update dependencies and test

This project has not been maintained for a while, so it's running older versions of a lot of libraries such as React.

These packages need to be updated, and the functionality needs to be tested after updating these packages.

Theme switcher for the entire page

Theme switcher for the entire page

Thanks to @DarkCode01 , we have a theme switcher implemented for the Editor (#40 ). However, it would be amazing to have a theme switcher for the entire page!

This is probably a good example of what we're looking for.

The goal is that when you switch from say the dracula theme to the github theme, the entire page should be colored like the github theme and not just the Editor component.

Implement absolute imports

Implement absolute imports

Instead of using relative paths for importing files, use absolute imports.

Options to show registers in different number systems

Options to show registers in different number systems

The numbers on the UI are shown as hexadecimal numbers. A useful feature would be to have a dropdown somewhere on the UI to change the number system in which the registers are displayed. Possible alternatives to hexadecimal numbers would be

  • Binary numbers
  • Octal numbers
  • Decimal numbers

const displayReg = (r) => r.toString(16).padStart(4, '0');

Feature to step back one instruction, and execute all instructions

Feature to step back one instruction, and execute all instructions

The bot can only execute instructions one by one currently. Features to execute all instructions at once, and step back an instruction to see the state would be useful for debugging!

Step back

  • A possible solution for this would be storing all the states in a redux slice and reinitializing registers and memory according to it's previous state.

Execute all

  • Right now, instructions are executed with the help of the stepClick function below, which is triggered by clicking the next step button on the UI.
  • For executing all instructions, a possible solution would be to call emulator.cpu.step() repeatedly until the last instruction is reached.

const stepClick = () => {
loadCode();
emulator.cpu.step();
dispatch(updateRegisters(emulator.getRegisters()));

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.