From 629a203f73d923fe8c99213d54c8ae417f0fe24b Mon Sep 17 00:00:00 2001 From: Bagomot Date: Mon, 11 Jun 2018 11:05:53 +0400 Subject: [PATCH] Added cpu code and examples --- .gitignore | 2 + source/app.d | 25 ++++- source/j1_cpu.d | 266 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+), 3 deletions(-) create mode 100644 source/j1_cpu.d diff --git a/.gitignore b/.gitignore index eec6d03..3ec9aa9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ __dummy.html *.o *.obj __test__*__ + +*.exe \ No newline at end of file diff --git a/source/app.d b/source/app.d index c3eec7f..514b619 100644 --- a/source/app.d +++ b/source/app.d @@ -1,6 +1,25 @@ -import std.stdio; +import j1_cpu; void main() { - writeln("Edit source/app.d to start your project."); -} + J1_CPU j1 = new J1_CPU; + + uint16[32_768] ram = new uint16[32_768]; + + ram[0] = 0x4003; // call 3 вызвать подпрограмму по адресу 3 + ram[1] = 0x8008; // push 8 положить 8 на стек + ram[2] = 0x0000; // halt остановить программу + ram[3] = 0x8001; // push 1 положить 1 на стек + ram[4] = 0x8002; // push 2 положить 2 на стек + ram[5] = 0x8003; // push 3 положить 8 на стек + ram[6] = 0x6146; // >r скопировать вершину стека данных в стек возвратов + ram[7] = 0x6180; // swap поменять местами два верхних элемента стека данных + ram[8] = 0x6b89; // r> поместить вершину стека возвратов в стек данных + ram[9] = 0x7180; // swap поменять местами два верхних элемента стека данных + + j1.setMemory(ram); + j1.executeProgram(); + + j1.print; + +} \ No newline at end of file diff --git a/source/j1_cpu.d b/source/j1_cpu.d new file mode 100644 index 0000000..09814d7 --- /dev/null +++ b/source/j1_cpu.d @@ -0,0 +1,266 @@ +import std.stdio; +import std.conv : to; + +// 16-разрядное беззнаковое целое +alias int16 = short; +// 16-разрядное беззнаковое целое +alias uint16 = ushort; + +class J1_CPU +{ + private + { + enum RAM_SIZE = 32_768; + // стек данных + uint16[33] dataStack; + // стек вызовов + uint16[32] returnStack; + // память + uint16[RAM_SIZE] RAM; + // указатель на вершину стека данных + int16 dataPointer; + // указатель на вершину стека вызовов + int16 returnPointer; + // счетчик инструкций + uint16 programCounter; + + // маски для различения типов инструкций j1 + enum J1_INSTRUCTION : uint16 + { + JMP = 0x0000, + JZ = 0x2000, + CALL = 0x4000, + ALU = 0x6000, + LIT = 0x8000 + }; + + // маски для различения аргументов инструкций j1 + enum J1_DATA : uint16 + { + LITERAL = 0x7fff, + TARGET = 0x1fff + }; + + // исполнение команд АЛУ + auto executeALU(uint16 instruction) + { + uint16 q; + uint16 t; + uint16 n; + uint16 r; + + // вершина стека + if (dataPointer > 0) + { + t = dataStack[dataPointer]; + } + + // элемент под вершиной стека + if (dataPointer > 0) + { + n = dataStack[dataPointer - 1]; + } + + // предыдущий адрес возврата + if (returnPointer > 0) + { + r = returnStack[returnPointer - 1]; + } + + // увеличить счетчик инструкций + programCounter++; + + // извлечение кода операции АЛУ + uint16 operationCode = (instruction & 0x0f00) >> 8; + + // опознание операций + switch (operationCode) + { + case 0: + q = t; + break; + case 1: + q = n; + break; + case 2: + q = to!uint16(t + n); + break; + case 3: + q = t & n; + break; + case 4: + q = t | n; + break; + case 5: + q = t ^ n; + break; + case 6: + q = to!uint16(~to!int(t)); + break; + case 7: + q = (t == n) ? 1 : 0; + break; + case 8: + q = (to!int16(n) < to!int16(t)) ? 1 : 0; break; case 9: q = n >> t; + break; + case 10: + q = to!uint16(t - 1); + break; + case 11: + q = returnStack[returnPointer]; + break; + case 12: + q = RAM[t]; + break; + case 13: + q = to!uint16(n << t); + break; + case 14: + q = to!uint16(dataPointer + 1u); + break; + case 15: + q = (n < t) ? 1 : 0; break; default: break; } // код действия с указателем на стек данных // (+1 - увеличить указатель, 0 - не трогать, -1 уменьшить (= 2 в двоичном коде)) uint16 ds = instruction & 0x0003; // код действия с указателем на стек возвратов // (+1 - увеличить указатель, 0 - не трогать, -1 уменьшить (= 2 в двоичном коде)) uint16 rs = (instruction & 0x000c) >> 2; + + // код действия с указателем на стек данных + // (+1 - увеличить указатель, 0 - не трогать, -1 уменьшить (= 2 в двоичном коде)) + uint16 ds = instruction & 0x0003; + // код действия с указателем на стек возвратов + // (+1 - увеличить указатель, 0 - не трогать, -1 уменьшить (= 2 в двоичном коде)) + uint16 rs = (instruction & 0x000c) >> 2; + + switch (ds) + { + case 1: + dataPointer++; + break; + case 2: + dataPointer--; + break; + default: + break; + } + + switch (rs) + { + case 1: + returnPointer++; + break; + case 2: + returnPointer--; + break; + default: + break; + } + + // флаг NTI + if ((instruction & 0x0020) != 0) + { + RAM[t] = n; + } + + // флаг TR + if ((instruction & 0x0040) != 0) + { + returnStack[returnPointer] = t; + } + + // флаг TR + if ((instruction & 0x0080) != 0) + { + dataStack[dataPointer-1] = t; + } + + // флаг RPC + if ((instruction & 0x1000) != 0) + { + programCounter = returnStack[returnPointer]; + } + + if (dataPointer >= 0) + { + dataStack[dataPointer] = q; + } + } + } + + public + { + auto execute(uint16 instruction) + { + // опознать тип инструкции + uint16 instructionType = instruction & 0xe000; + // операнд над которым осуществляется инструкция + uint16 operand = instruction & J1_DATA.TARGET; + + // распознать конкретную инструкцию процессора + switch (instructionType) + { + // безусловный переход + case J1_INSTRUCTION.JMP: + programCounter = operand; + break; + // переход на адрес, если на вершине стека 0 + case J1_INSTRUCTION.JZ: + if (dataStack[dataPointer] == 0) + { + programCounter = operand; + } + dataPointer--; + break; + // передать управление на адрес + case J1_INSTRUCTION.CALL: + returnPointer++; + returnStack[returnPointer] = to!uint16(programCounter + 1); + programCounter = operand; + break; + // выполнить инструкцию АЛУ + case J1_INSTRUCTION.ALU: + executeALU(operand); + break; + // положить на стек литерал + case J1_INSTRUCTION.LIT: + operand = instruction & J1_DATA.LITERAL; + dataPointer++; + dataStack[dataPointer] = operand; + programCounter++; + break; + default: + break; + } + } + + this() + { + this.RAM = new uint16[RAM_SIZE]; + + this.dataPointer = -1; + this.returnPointer = -1; + this.programCounter = 0; + } + + void print() + { + dataStack.writeln; + //returnStack.writeln; + } + + void executeProgram() + { + while (RAM[programCounter] != 0) + { + execute(RAM[programCounter]); + print; + } + } + + void setMemory(uint16[32_768] ram) + { + this.RAM = ram; + } + + auto getMemory() + { + return RAM; + } + } +} -- 2.45.2