Всем привет, недавно я написал симулятор логических гейтов или вентилей на С++ (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 что даёт довольно ощутимый прирост в производительности в отличии от отрисовки обычных примитивов.
Если кому-то интересно потыкаться самому в проекте и возможно помочь мне, вот ссылка на репозиторий гитхаб:
Автор: nik2510
