Construindo um sistema de computador com JS? [fechadas]

10

Recentemente, terminei este livro chamado The Elements of Computing Systems, no qual você constrói um sistema de computador funcional desde o início, desde portas lógicas básicas até a criação de seu próprio código de máquina e linguagem Assembly, código intermediário e, finalmente, uma orientação simples a objetos. linguagem de programação que compila até o código da VM. Gostei muito e gostaria de criar algo semelhante em JavaScript, mas com mais recursos. Eu já escrevi um emulador para a máquina Hack em JS:

  // Creates a new CPU object that is responsible for processing instructions
  var CPU = function() {

var D = 0;    // D Register    
var A = 0;    // A Register
var PC = 0;   // Program counter


// Returns whether an instruction is valid or not
var isValidInstruction = function(instruction) {
    if (instruction.length != 32)
        return false;

    instruction = instruction.split(""); 

    for (var c = 0; c < instruction.length; c++)
    {
        if (instruction[c] != "0" && instruction[c] != "1")
            return false;
    }

    return true;
};  


// Given an X and Y input and 6 control bits, returns the ALU output
var computeALU = function(x, y, c) {

    if (c.length != 6)
        throw new Error("There may only be 6 ALU control bits");

    switch (c.join(""))
    {
        case "000000": return 0; 
        case "000001": return 1; 
        case "000010": return -1; 
        case "000011": return x; 
        case "000100": return y; 
        case "000101": return ~x;
        case "000110": return ~y;
        case "000111": return -x; 
        case "001000": return -y; 
        case "001001": return x+1; 
        case "001010": return y+1;
        case "001011": return x-1;
        case "001100": return y-1;
        case "001101": return x+y;
        case "001110": return x-y;
        case "001111": return y-x;
        case "010000": return x*y;
        case "010001": return x/y;
        case "010010": return y/x;
        case "010011": return x%y;
        case "010100": return y%x;
        case "010101": return x&y;
        case "010110": return x|y;
        case "010111": return x^y;
        case "011000": return x>>y;
        case "011001": return y>>x;
        case "011010": return x<<y;
        case "011011": return y<<x;

        default: throw new Error("ALU command " + c.join("") + " not recognized"); 
    }
}; 


// Given an instruction and value of Memory[A], return the result
var processInstruction = function(instruction, M) {

    if (!isValidInstruction(instruction))
        throw new Error("Instruction " + instruction + " is not valid");

    // If this is an A instruction, set value of A register to last 31 bits
    if (instruction[0] == "0")
    {
        A = parseInt(instruction.substring(1, instruction.length), 2);

        PC++; 

        return {
            outM: null,
            addressM: A,
            writeM: false,
            pc: PC
        }; 
    }

    // Otherwise, this could be a variety of instructions
    else
    {
        var instructionType = instruction.substr(0, 3);
        var instructionBody = instruction.substr(3);

        var outputWrite = false; 

        // C Instruction - 100 c1, c2, c3, c4, c5, c6 d1, d2, d3 j1, j2, j3 (000..000 x16)
        if (instructionType == "100")
        {
            var parts = [ "a", "c1", "c2", "c3", "c4", "c5", "c6", "d1", "d2", "d3", "j1", "j2", "j3" ];
            var flags = {}; 

            for (var c = 0; c < parts.length; c++)
                flags[parts[c]] = instructionBody[c]; 

            // Compute the ALU output
            var x = D;
            var y = (flags["a"] == "1") ? M : A; 
            var output = computeALU(x, y, [flags["c1"], flags["c2"], flags["c3"], flags["c4"], flags["c5"], flags["c6"]]); 

            // Store the result
            if (flags["d1"] == "1") A = output; 
            if (flags["d2"] == "1") D = output;
            if (flags["d3"] == "1") outputWrite = true; 

            // Jump if necessary
            if ((flags["j1"] == "1" && output < 0) || (flags["j2"] == "1" && output == 0) || (flags["j3"] == "1" && output > 0)) 
                PC = A;
            else
                PC++; 

            // Return output
            return {
                outM: output,
                addressM: A,
                writeM: outputWrite,
                pc: PC
            }; 
        }

        else throw new Error("Instruction type signature " + instructionType + " not recognized");
    }
}; 


// Reset the CPU by setting all registers back to zero
this.reset = function() {
    D = 0;
    A = 0;
    PC = 0;
}; 


// Set the D register to a specified value
this.setD = function(value) {
    D = value;
}; 


// Set the A register to a specified value
this.setA = function(value) {
    A = value;
}; 


// Set PC to a specified value
this.setPC = function(value) {
    PC = value;
};


// Processes an instruction and returns the result
this.process = function(instruction, M) {
    return processInstruction(instruction, M); 
}; 
}; 

Eu estava pensando em adicionar coisas como um sistema de arquivos, som, conectividade com a Internet e uma saída de tela RGBA (atualmente é apenas preto e branco). Mas quão viável isso seria, realmente?

Porque o que estou pensando em fazer é começar completamente do zero. E o que quero dizer com isso é criar meu próprio código de máquina, trabalhar até a linguagem C e criar programas de trabalho e outras coisas.

Ryan
fonte
11
É totalmente viável. bellard.org/jslinux
World Engineer
4
Apenas vá em frente e veja até onde você chega. Mesmo se você falhar em seu objetivo final, tenho certeza que aprenderá muito, e parece que essa é sua principal motivação.
James
2
Não usar cordas, suporte JavaScript 32 bit inteiros e operações bit a bit sobre eles
Esailija
Número é a única IMO real "ruim".
Erik Reppen
Além disso, isso me faz querer perguntar. Alguma linguagem dinâmica interpretada nunca teve uma camada entre ela e a linguagem de máquina?
Erik Reppen

Respostas:

2

Você certamente poderia fazê-lo. Você precisaria implementar certos componentes do seu sistema operacional, como o carregador de inicialização, e interromper em um idioma de nível inferior.

Veja a abordagem adotada pelo sistema operacional Singularity pela Microsoft sobre como desenvolver um sistema operacional executado em código gerenciado.

Obviamente, não é necessário que você tenha que instalar o gerenciamento de memória no JavaScript; você pode adicionar uma API para o gerenciamento de memória ao JavaScript. Você pode optar por escrever um compilador para JavaScript ou escrever uma máquina virtual.

A Singularity possui código fonte disponível para que você possa obter informações valiosas ao analisar as decisões de design que a Microsoft tomou.

Sam
fonte