Симулятор логических схем с программируемыми гейтами на Lua

от автора

Всем привет, недавно я написал симулятор логических гейтов или вентилей на С++ (sfml для графики + sol2 для интеграции луа скриптов), которые можно программировать на луа таким образом: «`

local gate = {}gate.inputCount = 2gate.outputCount = 1function gate.update(inputs)    local a = inputs[1] or false    local b = inputs[2] or false    local result = a and b        return { result }endreturn gate

Этот код отвечает за гейт и (Когда 2 входа активны выход равняется true, если хоть один не активен то равен false.). И так-же бинды гейтов к клавишам:

«`

local binds = {    ["Num1"] = "scripts/gates/and.lua",    ["Num2"] = "scripts/gates/or.lua",    ["Num3"] = "scripts/gates/xor.lua",    ["Num4"] = "scripts/gates/not.lua",    ["Num5"] = "scripts/gates/halfadder.lua"}return binds

Для бинда клавиш вам лишь нужно указать цифру на клавиатуре, и путь к реализации гейта на луа.

Так-же мне стало интересно, смогу ли я на одном гейте запустить что-то на подобии процессора, и у меня получилось. Вот скрипт на луа:

«`

local gate = {}gate.inputCount = 1   gate.outputCount = 8  local PC     = 0        local REG_A  = 0        local REG_B  = 0        local ZERO_F = false    local lastClk = false local memory = {}for i = 0, 255 do memory[i] = 0 endlocal OP = {    NOP  = 0x00,     LDA  = 0x01,     LDB  = 0x02,     ADD  = 0x03,     SUB  = 0x04,     ANA  = 0x05,     ORA  = 0x06,     STA  = 0x07,     LDA_M= 0x08,     JMP  = 0x09,     JZ   = 0x0A, }local program = {    OP.LDA, 0,          OP.STA, 200,        OP.LDA, 1,          OP.STA, 201,            OP.LDA_M, 200,      OP.LDB,   0,        OP.ADD,                 OP.LDB,   201,      OP.ADD,                 OP.STA,   202,          OP.LDA_M, 201,      OP.STA,   200,      OP.LDA_M, 202,      OP.STA,   201,          OP.LDB,   0,        OP.ADD,             OP.JZ,    0,            OP.JMP,   8,    }for i = 0, #program - 1 do    memory[i] = program[i + 1]endfunction gate.update(inputs)    local clk = inputs[1]        if clk and not lastClk then        local opcode = memory[PC]                if opcode == OP.NOP then            PC = (PC + 1) % 256                    elseif opcode == OP.LDA then            REG_A = memory[(PC + 1) % 256]            PC = (PC + 2) % 256                    elseif opcode == OP.LDB then            REG_B = memory[(PC + 1) % 256]            PC = (PC + 2) % 256                    elseif opcode == OP.ADD then            REG_A = (REG_A + REG_B) % 256            ZERO_F = (REG_A == 0)            PC = (PC + 1) % 256                    elseif opcode == OP.SUB then            REG_A = (REG_A - REG_B) % 256            if REG_A < 0 then REG_A = REG_A + 256 end            ZERO_F = (REG_A == 0)            PC = (PC + 1) % 256                    elseif opcode == OP.ANA then            local res = 0            local a, b = REG_A, REG_B            for bit = 0, 7 do                if (a % 2 == 1) and (b % 2 == 1) then res = res + 2^bit end                a, b = math.floor(a / 2), math.floor(b / 2)            end            REG_A = res            ZERO_F = (REG_A == 0)            PC = (PC + 1) % 256                    elseif opcode == OP.STA then            local addr = memory[(PC + 1) % 256]            memory[addr] = REG_A            PC = (PC + 2) % 256                    elseif opcode == OP.LDA_M then            local addr = memory[(PC + 1) % 256]            REG_A = memory[addr]            ZERO_F = (REG_A == 0)            PC = (PC + 2) % 256                    elseif opcode == OP.JMP then            PC = memory[(PC + 1) % 256]                    elseif opcode == OP.JZ then            if ZERO_F then                PC = memory[(PC + 1) % 256]            else                PC = (PC + 2) % 256            end        else            PC = 0        end                print(string.format("[8-bit CPU] PC: 0x%02X | OP: 0x%02X | REG_A: %d | REG_B: %d | ZF: %s",             PC, opcode, REG_A, REG_B, tostring(ZERO_F)))    end        lastClk = clk        return {        (math.floor(REG_A / 1) % 2) == 1,        (math.floor(REG_A / 2) % 2) == 1,        (math.floor(REG_A / 4) % 2) == 1,        (math.floor(REG_A / 8) % 2) == 1,        (math.floor(REG_A / 16) % 2) == 1,        (math.floor(REG_A / 32) % 2) == 1,        (math.floor(REG_A / 64) % 2) == 1,        (math.floor(REG_A / 128) % 2) == 1    }endreturn gate  

Как я и говорил, код проекта написан на языке С++ с помощью библиотек SFML, sol2 с системой сборки CMake. Проект в данный момент довольно сырой хоть и рабочий, позволяет соединять между собой разные логические вентили и в теории запускать что-то довольно мощное. Отрисовка работает через sf::VertexArray что даёт довольно ощутимый прирост в производительности в отличии от отрисовки обычных примитивов.

Если кому-то интересно потыкаться самому в проекте и возможно помочь мне, вот ссылка на репозиторий гитхаб:

https://github.com/nik251021/LogicGrid

ссылка на оригинал статьи https://habr.com/ru/articles/1053312/