GithubHelp home page GithubHelp 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 Issues

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.

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');

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,
}));
});

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.

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;
}

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 ๐Ÿฅบ

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.

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.

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.

Implement absolute imports

Implement absolute imports

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

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()));

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

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>
);
}

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.