Budujesz system komputerowy z JS? [Zamknięte]


10

Niedawno skończyłem książkę zatytułowaną The Elements of Computing Systems, w której budujesz działający system komputerowy od podstaw, zaczynając od podstawowych bramek logicznych, poprzez tworzenie własnego kodu maszynowego i języka asemblera, po kod pośredni, a na koniec prosty obiektowy język programowania, który kompiluje się do kodu VM. Bardzo mi się podobało i chciałbym stworzyć coś podobnego w JavaScript, ale z większą ilością funkcji. Napisałem już emulator dla maszyny Hack w 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); 
}; 
}; 

Myślałem o dodaniu takich elementów, jak system plików, dźwięk, łączność z Internetem i wyjście ekranu RGBA (obecnie jest to tylko czarno-biały). Ale jak realne byłoby to naprawdę?

Bo to, co myślę o zrobieniu zaczyna całkowicie od podstaw. Rozumiem przez to, że tworzę własny kod maszynowy, a potem pracuję w kierunku języka podobnego do C i faktycznie tworzę działające programy i inne rzeczy.


11
To jest całkowicie wykonalne. bellard.org/jslinux
Inżynier świata

4
Po prostu idź i zobacz, jak daleko zaszedłeś. Nawet jeśli nie uda ci się osiągnąć ostatecznego celu, na pewno nauczysz się ton i brzmi to tak, jakby to była twoja główna motywacja.
James

2
Nie używaj ciągów, javascript obsługuje 32-bitowe liczby całkowite i operacje bitowe na nich
Esailija

Liczba to jedyna prawdziwa „zła” część IMO.
Erik Reppen

To sprawia, że ​​chcę zapytać. Czy jakiś dynamicznie interpretowany język nigdy nie miał warstwy między nim a językiem maszynowym?
Erik Reppen

Odpowiedzi:


2

Z pewnością możesz to zrobić. Będziesz musiał zaimplementować pewne składniki systemu operacyjnego, takie jak moduł ładujący i przerwie w języku niższego poziomu.

Zobacz podejście przyjęte przez system operacyjny Singularity przez Microsoft w zakresie tworzenia systemu operacyjnego działającego na kodzie zarządzanym.

Oczywiście, nie ma wymogu, że musisz oprzeć zarządzanie pamięcią na JavaScript, możesz dodać API do zarządzania pamięcią do JavaScript. Możesz napisać kompilator dla JavaScript lub maszynę wirtualną.

Osobliwość ma dostępny kod źródłowy, dzięki czemu można uzyskać cenny wgląd w decyzje projektowe podejmowane przez Microsoft.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.