Всем привет, недавно я написал симулятор логических гейтов или вентилей на С++ (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://habr.com/ru/articles/1053312/