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

local gate = {}

gate.inputCount = 2
gate.outputCount = 1

function gate.update(inputs)
    local a = inputs[1] or false
    local b = inputs[2] or false

    local result = a and b
    
    return { result }
end

return 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 end

local 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]
end

function 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
    }
end

return gate
  

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

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

https://github.com/nik251021/LogicGrid

Комментарии (2)


  1. IDma88
    29.06.2026 12:33

    Кажется в вашей программе ошибка: вместо OP.LDB, 201 нужна OP.LDB_M, 201, но такой операции нет. Если, конечно, вы считаете последовательность Фибоначчи


    1. nik2510 Автор
      29.06.2026 12:33

      Спасибо, как приеду домой перепроверю и перепишу