#Rewriting Cuprous Logic Simulator

1 messages · Page 1 of 1 (latest)

verbal bobcat
#

For all people who doesn't know about this - it's a logic simulator inspired by Logisim, written in rust with egui

This post is about the rewrite which you can find in https://github.com/Ved-s/cuprous/tree/rewrite

Old post about the old version here: #1140876288773603438

I decided to rewrite it since first, i started it very early in my rust learning, so new code should be better, also, hopefully, better structurized.
Second, it had fundamental stuff that i didn't like in the end. For example, internally circuits are represented with at least 2 structs - one for rendering its preview and handling its placement and creation, second for doing actual logic. Also, since i wanted updates to be backwards compatible i had to write some hacks around that, which could be easily solved if I considered that in the first place.
Third reason is that it couldn't simulate complex circuits that rely on consistency, for example, a binary counter circuit will start giving wrong results after some time and the problem was that each circuit board could operate in only one of two modes - Random event ordering, which makes stuff that depends on randomness and inconsistency possible (latches), or Ordered events, which removed all randomness from the simulation but also made latches impossible to make, since they'll never settle in a stable state.
Also what i couldn't implement some stuff that i wanted due to UI style that cuprous uses - single view of the board with overlays on top, this made impossible to make multi-view UI without duplicating existing elements.

Cuprous is using #1288243173126049892 for its savestates and copystates

Currently the rewrite doesn't have a website version, the one at https://ved-s.github.io/cuprous/ is still the old version

I'll update this post with progress (when i remember to)

Updated on <t:1775964230>

#

Okay, so what i already did in rewrite:

  • UI now uses egui_dock, so users don't have to use the fixed layout i chose, also will make adding multiple views or pages easier
  • Placing and editing wires is done
    • Now it uses 8 directions instead of 4, so you can place diagonal wires
    • Now you can finally remove wires without selecting them first, by holding Shift while drawing it (this was in TODOs of the old cuprous for so long)
  • Selection for wires is mostly done, i need to implement rotated rect collision, so it will be more accurate

No circuits, no states, nothing else is done yet, though how it handles circuits will change too

#

I think i'll make possible for circuits to occupy quarters of tiles instead of only full tiles, so you can place circuits back-to-back and just for allowing tighter placement, since before they could visually be 1 tile apart but you couldn't place them closer

#

Now the problem is, how to define that quarter placement, since before circuits only had size, which is a pair of usizes, and i think you could write a 0-size circuit and it won't complain

#

so i'm thinking, either to make circuits operate on double precision (basically allow .5 coordinates and stuff) or make toggles to shift circuit by those 0.5 units but still use normal size

#

Also i don't know if i want to allow non-rectangular circuits

worn warren
#

👀

verbal bobcat
#

Implemented circuit placement, now it uses quarters of tiles to place circuit tiles into, also circuit can choose which tiles it occupies aside from generic circuit size

#

so now circuits can be any shape as long as they fit into the size they specify

#

they can do custom selection drawing too but i wanted to test it on circles but i need to implement them for my vertex renderer first

verbal bobcat
#

finally it's not a mess of weird rectangles anymore

#

even drawn it out in gimp to understand what i was doing wrong before

verbal bobcat
#

pins are implemented and now properly connect to wires

#

(screenshot with circuit debug overlay (hit F9 twice), number at the center of the qtarter is circuit id, number at the center of the tile is the connected wire)

#

and debug mode also validates if everything is correct, white text means ok

#

it actually uses rgb channels to tell which checks failed

spare lynx
#

nice work! at uni we used logisym a few years ago

verbal bobcat
#

What shape should pins be? rn it's mixed, when circuit is selected, it shows circle pins, when it's placed, pins are squares because Implementation Details

worn warren
#

I'd vouch for circles

harsh crater
#

Hexagon is the bestagon

verbal bobcat
#

though octagon would fit more

#

actually, i can make it customizeable

harsh crater
#

Make it an n-gon + global slider

verbal bobcat
#

yeee

#

there's already a custom Style passed to each draw call

#

and the only thing it has so far is selection colors

verbal bobcat
#

and my math is correct even

#

nevermind

#

it's wrong

#

no, i'm an idiot

#

it's A/H = cos(a)

#

me forgor

verbal bobcat
#

started doing automatic circuit rotation/flipping support, math is hard

#

brain melted immediately, will probably continue it later lol

verbal bobcat
#

and everything circuit needs to do is

#

ok, my brain is still fried

verbal bobcat
#

I started implementing board states, but i need to think how to run them

#

Before, it spawned a thread for each board state

#

which meant that you easily could have thousands of them

#

now i think making it spawn a thread per core and make them run different board states

verbal bobcat
#

I also need to think how to implement wire updates, since i want to pause all affected states while reading inputs

#

maybe i'll need to first collect all pins this wire connects then pause all states those pins are in

#

then do reading and writing

#

would be probably good to cache which pins are connected but it will be difficult to invalidate that

verbal bobcat
#

I thought that i should post about this in a weekly What's everyone working on this week thread on r/rust and that was a great timing lol

worn warren
#

heheeee

verbal bobcat
#

I think i'll split cuprous into separate crates at some point

#

rn i'm thingking of making cuprous-backend, separate cuprous-circuitsand main crate will be the frontend

#

and first two should have a feature to enable/disable rendering functionality

worn warren
#

Oooo that sounds nice

verbal bobcat
#

i can't decide how state simulation should work

#

and i also need to think how multiple states should run on a single thread

#

it's too complex to think about rn

#

and i can't copy old code because it assumes each state has its own thread

#

also old code could run multiple threads per one state, they'll just lock on eachother but i don't want to allow it now

spare lynx
verbal bobcat
#

it just spawns a new thread for each board state

#

if you're referring to also old code could run multiple threads per one state, you probably can't do that from UI, but code didn't have any checks to prevent that, as i remember

spare lynx
verbal bobcat
#

i wrote that 10 months ago, i have no idea why i wrote it like that

#

i have no idea why i did weird stuff back then

spare lynx
#

the worst code is own code from the past

verbal bobcat
#

true true

#

i think i'll need to mention that project is being rewritten in another branch in the readme

spare lynx
#

I suggest working on some refactorings. This is a great way to create abstractions and gain understanding for a new design without changing behavior.

verbal bobcat
spare lynx
#

ah, from scratch! so in the new branch how does it work? any links?

verbal bobcat
#

it's in the rewrite branch of the same project

#

i forgot how to english, jeez

verbal bobcat
#

can place wires, circuits, select them, delete and that's pretty much it

spare lynx
#

In principle there is a clock cycle that triggers a discrete change in all the components at the same time, tracking dependencies between components.
I would not simulate that with multiple threads!

#

ignoring the clock, you could simulate a single state first

verbal bobcat
#

constant tickrate will limit max speed components could run with

spare lynx
#

it's not constant if it only depends on the calculation of the past state to feed into the new one

#

e.g if you have a clock component you could stop, step, select an appropriate tickrate for eye inspection

harsh crater
verbal bobcat
#

cuprous runs on events, not clock

#

(also it has a clock component)

spare lynx
#

a clock tick is usually modelled as an event, but not multithreaded

verbal bobcat
#

no, the whole thing runs on events

#

and single board in single state is not multithreaded

spare lynx
#

is there an event for each wire changing 0/1?

harsh crater
verbal bobcat
#

which can trigger other circuit pins, which will queue their circuits to update

spare lynx
#

a simulator would take the button click as a change in the bit value so during the next clock cycle the board will see a 1 and propagate the state to the rest of the components all in one thread

verbal bobcat
#

i don't get why you need to tick the simulation

#

when you can do everytghing immediately

spare lynx
#

you need to define an observable state that is consistent

#

I think many things will work but it's not guaranteed if you change things unorderedly

verbal bobcat
#

that reminds me that i will need to implement debugging and stepping

spare lynx
#

otherwise you wouldn't be simulating but reimplementing

spare lynx
verbal bobcat
#

no?

#

are you talking about how board simulation should work or about how to make something within that simulation

spare lynx
#

first one

verbal bobcat
#

then no, first version ran fine without it

spare lynx
#

when you change a value it is immediately reflected right?

verbal bobcat
#

correct

spare lynx
#

but how do you know the state changes were fully propagated?

verbal bobcat
#

it doesn't

#

it just executes until there's nothing to execute

#

then it's waiting until there is stuff to execute

spare lynx
#

imagine each component has a 1s delay, then you see some inner workings in real time

#

but the delay isn't real in a simulation, everything happens all at once so that the next cycle you can expect what to find

#

I would like to point out that single thread should be easier

verbal bobcat
#

each state simulation is singlethreaded

#

it's just that there could be multiple boards with multiple states running at the same time

spare lynx
#

everything is a component with inputs and outputs (e.g a gate, a board, multiple connected boards)

#

so I suggest a simple call instead of threads that require you to do get_state() afterwards with no guarantees

verbal bobcat
#

i don't understand (sorry, it's also too late, that could be too)

spare lynx
#

it's 11 am for me lol

verbal bobcat
#

00:47 for me, midnight

spare lynx
#

get some rest!

#

come back in a few hours and I prepare tea and cookies

verbal bobcat
#

also that won't be a few hours lol, that will be at least 11

spare lynx
#

let's see... a gate is a pure function, right?

verbal bobcat
#

also, i don't want rewrite to be less performant than the previous version

verbal bobcat
#

currently, a gate is a mess

#

and gates also support wire bundles (wire signals that have multiple other signals in them)

spare lynx
#

Maybe modelling that will help, as you only need a few impls. The gate output at some point depends only on the inputs at that point

verbal bobcat
spare lynx
#

the state of the circuit is the bit value of each wire at that time

verbal bobcat
#

(also, not bits)

#

Bundle is essentially a Box<[WireState]>

spare lynx
#

bit you could separate the state from the logic gate simulation

#

as in create a unit test that doesn't spawn threads and checks just pure gates

verbal bobcat
#

i don't get the point of this

#

i want to rewrite the parts i wanted to rewrite in the original thing

#

not create a new thing that works differently

spare lynx
verbal bobcat
#

that is a different problem?

#

to reduce number of threads to the number of cores

#

not to eliminate them completely

#

so it won't spawn 639 threads, for example

spare lynx
#

A logic simulator (just like any old computer) needs only one process, right?
So there is something odd in your use of threads, and it would make things much easier to develop and evolve single threaded, then focusing on the necessary optimizations.
I don't agree that single threading will penalize performance.

verbal bobcat
#

example, each cell runs on a separate thread and will definitely be faster than evaluating each cell sequentially on one thread

verbal bobcat
spare lynx
#

threading is not free!

verbal bobcat
#

also, it's almost free

spare lynx
#

as a simulator you evaluate a single state transition (e.g 1 asm op in one gate).
this is orders of magnitude smaller than threading

#

and if it were easy to thread I would go with it but it definitely isn't. i.e not free

verbal bobcat
#

it's way slower than that

#

it doesn't optimize or compile or do anything with gates

#

they're just circuits

#

executing thousands of asm instructions

spare lynx
#

maybe I'm not being helpful wrt your current goals

verbal bobcat
#

gates can be as simple as taking 2 binary inputs and producing a binary outputs to circuits taking a lot of inputs with nested signals, producing a single nested output

#

there's even no limit on how many inputs you can set, it's limited by your architecture and RAM

spare lynx
#

fn (bit, bit) -> bit?

verbal bobcat
#

but before that's called it does alot of things to extract that

#

(extra bool is for one optional toggle in gate properties, for example, how multi-input xor/xnor should behave)

spare lynx
#

do you have a method that would allow you to do something like

(gate1 + gate2) >> gate3

verbal bobcat
#

no, only way is to place them on the board and connect them with wires

spare lynx
#

do you see useful to have such an abstraction?
it would connect stateless components such as gates into larger stateless components

#

which you can aggresively parallelize

verbal bobcat
#

yes, if i'd implement hdl support

#

also, gates can have state

spare lynx
#

circuits can have states

#

the state of the simulation running on a network of stateless components

verbal bobcat
#

state of the wires, to be exact

#

and pins

spare lynx
#

which are defined exactly by the inputs to the whole board

verbal bobcat
#

no

spare lynx
#
  • the old states
verbal bobcat
#

they also depend on previous state

spare lynx
#

yes

verbal bobcat
#

if you do stuff like latches

spare lynx
#

previous states = clock = out of scope

verbal bobcat
#

(which is the main reason of the rewrite)

spare lynx
verbal bobcat
#

there's state

#

Life cell needs a state

#

and this circuit in the middle is a toggle latch

spare lynx
#

I can think of a simple trick to reduce threads if you don't create them for stateless logic gates

verbal bobcat
#

nah, there will be a fixed number of threads

#

they'll just run tasks from different states each

spare lynx
#

I would double check that this is a proper simulation that will work in all cases since concurrent state propagation is different than the real circuits you model

verbal bobcat
#

it couldn't even simulate in single thread properly

#

same reason for a rewrite

#

random mode simulation was too chaotic

#

but it's essential for stuff like latches that depend on randomness

spare lynx
#

rewriting from scratch is pretty hard. refactoring the old code could be easier because you can easily check you don't change behavior.

verbal bobcat
#

refactoring old code means i have to make it compatible with older savefiles

#

and there's already a ton of hacks for that

#

because there was no savefile versioning

#

and serde is bad at determining how to deserialize data based on that data

spare lynx
#

lol

verbal bobcat
#

you can't say "if this fails to deserialize, try an older format instead"

spare lynx
#

write many tests and make sure you have the simulation fundamentals right

verbal bobcat
#

nah again, my plan is to implement simulation and some circuits to simulate, then experiment with simulation

spare lynx
#

I don't see the difference. something like effort?

#

I'm saying that during your rewrite you would move fast with unit tests focusing on the fundamentals before threading

verbal bobcat
#

not doing anything on this rn, haven't decided how wire updating should work

#

on one side, it's as simple as enumerating all pins on the wire, reading all inputs and writing all outputs

#

but, pins can be of Custom type

#

that means they need to have a &mut WireState access while reading and can redirect those reads/writes to other wires

#

in previous version, there were separate custom_read(...) and custom_write(...) methods on circuits and they recursively propagated those to other wires

#

but they also need to be able to propagate those to the wires in other board states

#

i was thinking of trying to lock those other states, so they don't run while update propagation occurs

#

but this can deadlock if both states will try interacting with each other's wires

#

also i haven't decided if i want to recursively propagate those calls or do one recursive call to collect all connected pins and then do signal manipulation

#

i'll probably do that, but that may add overhead on simple cases which don't need that

#

so i'll need to make it check first if wire has custom pins connected

#

or cache that

#

make Wire have a any_custom_pins bool and recalculate that when pins attach/detach from it

verbal bobcat
#

but idk if that can even happen

verbal bobcat
verbal bobcat
#

it literally runs it in the ui thread for now

#

but now i think i can start adding buttons and gates to check how simulation is working

#

circuit api is nicer now

verbal bobcat
#

ig this is frozen for now, while i'm doing other coding stuff

worn warren
#

What other thing are you doing?

verbal bobcat
#

continuing making an app for my friend, a stream dashboard and he want to control audio levels from it

#

so now i;m implementing pulseaudio protocol and then windows mmapi

worn warren
#

Huh, not pipewire?

#

Also what about alsa

verbal bobcat
#

i'm using pulseaudio and it's mostly for me to test stuff

worn warren
#

i c

verbal bobcat
#

i chose to make this complex thing even though implementing only winfdows support would be much easier

#

and there wasn't a good crate for it, so i'm writing it almost from scratch too

#

almost because there is a crate, pulseaudio, but it's synchronous and doesn't want they way i'd like stuff to work

#

and the app is a weird abomination of tokio in "backend" part and egui in the frontend

verbal bobcat
#

i came up with a simple solution to the randomization problem

#

since irl circuits take essentially random time to react, i'll make circuit events delayed a little, it will use linear VecDeque for the event list, but will insert new events at a random position in a certain range

verbal bobcat
#

i spent too much time on this generic mess so i can chain paths neatly

#

for some reason i did two paths before, no idea why now

verbal bobcat
#

Ow gate

verbal bobcat
#

Potion Craft allows you to move views with WASD, i became addicted to that, so i added this

#

also added camera velocity when dragging and releasing

#

i'm procrastinating on implementing savestates and copy/paste grrr

#

and using my new format for this

verbal bobcat
#

i may have found part of a solution on how to make circuits lose signals when sending then from one state to another

#

just make it first collect all the wires in all circuits that need to be updated then lock those wires, so all operaions that would write to the will have to wait, and only then write there

#

but that means it should also lock pin values

#

or, hm

#

right

#

pin values might change after it used them in the wire value calculation

#

so then setting a pin should be an event

#

which could be delayed because of locking

#

or

#

when triggering a pin value change, it will check if the wire is locked

#

if it is, it will queue an event that will wait for the unlock

#

hm

#

i think trying to update a wire that is locked should just push the update back into the queue

#

and that all is just to make the engine multithreaded

#

all of this will be disabled on wasm or singlethreaded mode

#

watch me not getting a single step closer to implementing this

#

lol

#

i want to implement saving and copying first

#

so i can at least build the circuit that checks for simulation consistency faster

verbal bobcat
#

heheheheeeee

#

it's at least twice as space effective as ron

#

without value optimizations from cuprous itself

#

like skipping None fields and such

#

welp, it was all pointless cus gzipping ron gives getter space efficiency

#

/s

#

but, now when i have some data, i can make an editor for it

verbal bobcat
#

i'll be doing loading properly now

#

in older cuprous, i had to do a hack in some circuits cus everything was loading at the same time

verbal bobcat
#

first commit in apparently 7 months

verbal bobcat
#

suddenly circuits need to manage alot of custom data

verbal bobcat
verbal bobcat
#

i don't know how to make transistors work

#

i need something that can have its output be None

#

so they can be connected to a bus

#

io don't know if i want to copy how old transistors worked cus those were mimicking PNP and NPN irl transistors, but only in what signal activates them and their design

#

regardless of their type, they passed any signal through when active

#

irl transistors don't work like this, i think

#

i think i'll just rename them to something like "Signal gate" and change the design

#

and maybe add a flag that makes them active on low

#

for future backwards compatibility

#

also i'm procrastinating on making circuit attributes work

#

for attributes, i think i'll make circuit give a &dyn AttributeAccess or something like this

#

and it will have fn attribute_by_id(&str) -> &dyn Attribute

#

instead of doing it old way, where attributes were a Vec<Box<dyn Attribute>> attached to circuits

#

and circuits had to read and downcast them

verbal bobcat
#

maybe a buffer with a signal on the side

#

and also regular buffers and error filters

#

error filters can look like diodes

verbal bobcat
#

I'm reading the book that was posted in one of the programming channels and keep thinking about cuprous.

I will need to make circuits connect wires across different boards at some point and i'm thinking about a mechanism to prevent a board changing abother board's wires while that board is running in a different thread

#

So, i'm thinking to make everything in the board state to be held under one Mutex

#

and if a board wants access to another board's state, it will have to lock that board's state first

#

and if that state is currently running, to signal it to stop and to give its state lock to some shared lock pool

#

and execute the state that was asking for the lock

#

Also all states of all boards should be held in a single place

#

so i won't need to write two ids everywhere (board id, state id)

#

Circuit pins then will get a new pin type WirePass or smth similar, it probably will still call a signal update on the circuit, but it will also vall a new circuit method that will return the state id and the wire to which this pin leads

#

actually, wait

#

to collect the list of wires in all states a signal should pass through, state needs to be locked

#

actually, if wire value calculation will need a new state to be locked, it can give all locks back to the pool and ask for more

#

hm

#

but then other tasks may lock those and modify the state which may modify where circuits point their wires!

#

fuck

#

actually

#

state locks can be marked how many times they were used by other tasks

#

and if the count doesn't match, recalculate

#

and the state machine can make a tree of states that reference other states to invalidate only some of the states

#

and none of this is useful yet since there's no way to create new boards

#

and it still runs singlethread

#

soooo i'm using this post to write to future me ideas on how to design it when time comes

verbal bobcat
#

I also think of making savestate be a directory of files

#

and an archive when explicitly saved

#

so you can add circuit boards to your project by just movinf a board file into autosave directory

#

it will take a bit more space but maybe that would be useful?

#

and if one file gets corrupted, it won't destroy the entire project

#

also yea, i should make it support multiple projects

#

instead of just loading last autosave

verbal bobcat
#

I finally started writing something and the snow storm cuts off electricity

#

also I have a better idea what to do with event randomization

#

the engine won't do any randomization itself

#

but some things that can happen somewhat in parralel, will get randomized

#

like wire updates its state, then queues updates for connected circuits in random order

verbal bobcat
#

Maybe i should also make boards fully locked

#

instead of board components being locked separately

#

that's a mouthful

verbal bobcat
#

hm

#

maybe tasks will have epochs

#

and tasks from same epoch can be executed in random order

#

since it can track which tasks made which other tasks

verbal bobcat
#

i don't think i need to make it execute tasks in same epoch in random order

#

but

#

i will make it add tasks with random epoch offset

verbal bobcat
#

if i reset the simulation state, it converges to a stable random state

#

hopefully it's not too random to break circuits

#

like first version did

verbal bobcat
# verbal bobcat it works

(i broke save/loading while chaging internals but copy-pasting still works (cus it doesn't preserve those details), so i've copied that circuit, saved it in a vscode tab and pasting every run to test it lol)

verbal bobcat
#

it becomes unstable when too much stuff is happening

#

not good

#

actually

#

hm

#

it's just slow

#

and if you clock something too fast before it finished updating, it obviously misbehaves

#

and it's slow because it does N runs per frame

#

and that value is fixed

#

and if i make it run at most 10ms per frame then it's very fast

#

and consistent

#

it lags rendering stuff that i'm throwing at it in debug mode

#

but if i move it all offscreen and run it as fast as i can, it's still consistent

#

i'm testing it by connecting a bunch of flip-flops together on one clock line so they will all change state on clock rising

#

and so far they're all in sync

#

would have desynced already on the old version

#

though technically, in old version i made a 4-bit counter, copied it and connected the copy on same clock line

#

so that if the simulation is correct, they will both output the same value

#

but i think 90 flipflops is more load than 2 4bit counters

verbal bobcat
#

i was thinking how to implement saving and loading from multiple sources

#

at some point i was even thinking of creating a VFS system that allows mounting filesystems at different paths

#

since i also want to later add circuits that allow interacting with outside files and sockets

#

and was thinking to make /project to point to currently opened project wherever it is, /egui to be used as egui's dyn Storage for its persistense and /simulation for stuff that will be accessible to the simulation

#

and then user would be able to mount like (external) /tmp/.X11-unix to /simulation/x11

#

is that too overkill?

#

or all those things can be separate

#

but then some files that are accessible to the simulation should be saved into the project

#

but then i want to be able to turn off autosaves so nothing is overwritten on disk

#

so everything should be saved in-memory until saved externally

#

but then what if files are big

#

aaaaaaaaaaaaaaaaaa

#

but then on web it's all in-mamory anyways

#

i should not think of this now

#

ans make it a problem only when i'll add those things

rancid forge
#

How it's going?

verbal bobcat
#

i need to write an interface to be able to save projects on web into localStorage, on native into a directory and into an archive

#

and i want a project to be split into multiple files

#

and i'm somehow procrastinating on that

verbal bobcat
#

TODO

  • Better error handling, separate window with errors for each task, with actions for that task
  • Document all keyboard interactions
  • Proper UI docking
  • Saving/Loading projects
    interface should support saving/loading from localStorage, filesystem, 7z archive
  • Create copies of blueprints or save them in a separate menu
  • Multithreading
  • Bundles
    recusrive gate handling, same as old
  • User circuits
  • User circuit designer
  • Placeable shapes, both in board editor and designer
  • Circuit wire passthrough, connecting multiple wires together
  • LED
  • Custom shapes for LEDs and buttons
  • Keybinds
  • Settings menu
    egui style, wire colors, other styles
  • ROM generator
  • Flip and rotate paste
  • Stack multiple pastes?
  • Pull multiple wires at the same time in the same direction
    maybe by holding a modifier
  • Moving circuits without deleting and replacing
  • Circuit widgets
    like button circuit's pressable button
  • Circuit display names?
  • Debugging circuits
    pause the simulation, step, run until ...

Future:

  • Load pre-rewrite data

Smoldata:

  • Data versioning
  • Write single RawValue into the file
#

alotta stuff

#

and in far future i also want interaction with hosts's files, sockets, maybe playing audio?

#

how should custom shapes work

#

maybe selecting from a list of shapes first

#

like (rounded?)Rectangle, n-gon, circle

#

then make it rotatable and squishable

#

should rounded n-gons exist?

#

should i put myself through pain of calculating all that lol

rancid forge
#

Treat this as just a statistic which is a suggestion for the order of implementing stuff

verbal bobcat
#

by rom generator i meant that it generates a pasteable circuit that has an address input and data output

#

made of gates

#

or maybe transistors and pullups

#

i do want to make rom and ram circuits that read from files too

rancid forge
verbal bobcat
#

i'll do both at some point

rancid forge
#

Sure it would be more educational but I would recommend to first make it work then make it right

verbal bobcat
#

for some things I want a magic box and a bunch of gates for others

#

file rom/ram depend on implementing a way to change circuit's properties

verbal bobcat
#

it's a bit more complicated than just exposing the values

#

values can change circuit's size

#

and it should check that it doesn't collide with other circuits, if so, roll back the value, then if any pins were moved, reconnect them to wires

rancid forge
verbal bobcat
#

technically you will be able to make it yourself

#

but with alot of overhead depending on the size

#

LEDs will have widgets, which is basically the led itself without the base, you can then expose them on your user circuit

#

and for rgb, you can layer multiple of them on top probably?

#

to make 8 color led, you'd stack 3 leds with transparent/red, transparent/green and transparent/blue colors

#

and I think egui allows you to make colors additive in its color picker UI

rancid forge
verbal bobcat
#

that's from the old version

#

and those are leds arranged in a grid in the designer

#

though there were issues with them slightly overlapped even when positioned perfectly

rancid forge
#

I think it would be simpler to just implement it into cuprous. When the rewrite will be complete I can help

verbal bobcat
#

it's technically possible to make cuprous load modules

#

it's definitely possible on native, but on webassembly it will be complicated

#

and modules will be able to add custom circuits

#

a lot of circuit interface is dyn traits

#

and adding circuits to the ui for the user to select isn't a fixed list either

rancid forge
rancid forge
verbal bobcat
#

problem is, api is somewhat synchronous

#

if it calls circuit_update, it expects everything to run inside that call

#

and write all tasks to the &mut task list it gives

#

hm

#

can you load multiple webassembly modules into same memory space?

#

so they can share it

#

if you can even, on native you'll need webassembly to have access to your host's memory

#

ig you can isolate everything and make host and module only excange messages via a queue

rancid forge
rancid forge
#

Don't communicate by sharing data, share data by communicating

verbal bobcat
#

but then you will be blocking the state execution by waiting for response from a module

#

i guess it actually doesn't matter in wasm

#

it's single threaded anyway

rancid forge
verbal bobcat
#

i mean they it will run with thread pooling anyway

#

but how to signal to yield then

rancid forge
verbal bobcat
#

no, the state engine calls circuit.update_signals(), it returns something to signal the state that it's waiting for the queue

rancid forge
#

Tbh is it even a problem? Can you think of an example where a custom component would compute for so long that it would block for a noticeable amount of time?

verbal bobcat
#

technically module might not even respond to the request

#

and then it will hang forever

rancid forge
verbal bobcat
#

hm

#

make the only valid message be a response to the request being sent?

#

module also should be able to make requests to the host

#

also some methods on circuits are called every frame

rancid forge
#

I would make the custom component api like this

enum ComponentDisplay {
 Simple { text: Cow<'static, str> },
 Complex(Framebuffer)
}

trait Component {
  fn on_inputs_change(inputs: HashMap<InputId, bool>, config: &Config) -> (HashMap<OutputId, bool>, ComponentDisplay); 
}
verbal bobcat
#

that's not how circuits work in cuprous though

#

I think i want module api to expose circuit trait

#

and hide all communication logic

rancid forge
verbal bobcat
#

button

#

its internal state changes when user clicks

rancid forge
verbal bobcat
#

it's more complicated than that again

#

button's drawing logic does a egui interaction

#

and its onclick does the button click logic

#

circuits have access to egui when drawn

#

and a ton more stuff

#

and yes, that means circuits can render UI elements on them

#

which is effectively what button does

#

and wrapping egui into a module api sounds like a nightmare

#

maybe only simple stuff

#

like interacting and painting shapes

verbal bobcat
#

and another another late thing: implement loading pre-rewrite stuff

rancid forge
#

@verbal bobcat How do you resolve this?

verbal bobcat
#

eframe failed to initialize window, somehow?

rancid forge
#

I'll try the wgpu backend

verbal bobcat
#

i think it requires opengl

#

you can try setting RUST_LOG=TRACE envvar

#

if i even set up the logger there

#

i don't remember

verbal bobcat
#

i need to stop thinking into the future and seeing how much more is there to implement

verbal bobcat
rancid forge
#

No

verbal bobcat
#

you can add env_logger to the project and call env_logger::init(); at the start of main, then run it with RUST_LOG=TRACE env set

rancid forge
#

I think I'll write something like a programming language where you specify it like

component Nand(a: 1, b: 1) -> out: 1 {
 And foo;
 a -> foo.a;
 b -> foo.b;
 Not bar;
 foo.out -> bar.in;
 bar.out
 
}
#

Though well I am busy with Pokisona rn

verbal bobcat
#

dadsdy were writing a HDL that i wanted to implement in cuprous

#

never got to it

#

having a HDL implemented into cuprous would be cool

#

esp that it will be faster than simulating circuits and wires

graceful junco
#

deleting wires would be cool /silly

verbal bobcat
#

you delete them by holding shift

graceful junco
#

documenting keybinds would be nice 😭

verbal bobcat
#

there's nothing telling that yet

#

yeah

graceful junco
#

I‘ve been using Sebastian Lagues logic sim

#

but it‘s very barebone

#

I really liked cuprous when I tried it

verbal bobcat
#

there needs to be a bot that allows pinning messages for thread ops

verbal bobcat
#

it works

#

now i need to write the part where it checks if circuits updated their geometry or pins

#

and either updates the geometry or displays an error

#

and it should also show in the world where errors happened

#

i also had to modify my custom box macro

#

to properly handle lifetimes

#

and it was a mess

#

with hacks to work around compiler not understanding my intentions

rancid forge
verbal bobcat
#

you can use the web version

rancid forge
rancid forge
verbal bobcat
#

yes

verbal bobcat
#

Random engine mode breaks alot

#

web version is just slower

verbal bobcat
#

but not now

rancid forge
#

I haven't figured out how you move stuff

verbal bobcat
#

cut and paste

rancid forge
verbal bobcat
#

and in the pre-rewrite version the only way to remove wires is to select them and delete

rancid forge
verbal bobcat
#

it's complicated to implement moving in my case

rancid forge
#

If you receive a mouse event at the place where a logic gate lies, start watching mouses position and when it drops change the position of the logic gate

verbal bobcat
#

not only change the position, but verify that it doesn't collide with any other circuit, copy its tiles to the new location, move pins, disconnect pins, remove wires if needed, connect pins in the new place

rancid forge
#

Wires don't need to be an object in cuprous at all. They can just be straight lines. While it might be more disorganized, it's way more simple to implement

rancid forge
verbal bobcat
#

i will implement this later

#

actually, you'd want to move a bunch of circuits and wires at the same time usually

rancid forge
verbal bobcat
#

moving wires will be harder to implement though

rancid forge
verbal bobcat
#

wires wom't be simple lines from A to B

rancid forge
verbal bobcat
rancid forge
verbal bobcat
#

wires can split and merge when moved

#

and in cuprous a wire is a collection of lines that somehow connect

rancid forge
verbal bobcat
#

if you output a False and a True into a wire, you'll get Error

verbal bobcat
#

you can only output a value if wire has None

#

or same value

#

i think it was done like that in Logisim

#

and cuprous is logisim but faster and more efficient

#

and not java

#

one of the reasons why working with circuits and wires is so complicated is that when you open a circuit board, behind the scenes it computes a tile map of all wires and circuits so it can quickly fetch anything by position

#

circuit board in the backend doesn't store any of that, it doesn't need that for the simulation

#

it stores only minimal info to reconstruct this tile map

#

and changing a circuit board in any way must keep this tile map valid but also update the backend

#

i think Logisim didn't do that so fetching anything required iterating over the long list of stuff and seaching for matches

#

and it's noticeable when you build circuits big enough

#

you have to wait seconds just to place a single wire

#

here's how wire data is stored in this map

#

value in the middle of a tile is wire id of the intersection

#

values at the edges are distances to the next intersection in that direction

#

and circuit tilemap too

#

except circuit tiles are actually quarters

#

so you can stack circuits tighter

#

also i remembered that i need to make geometry of gates better fit the shape of the gate

#

and not just being a box

rancid forge
#

It's low performance cost

#

It isn't 1980's

verbal bobcat
#

really

#

it's not that simple

#

and it takes more time for bigger circuits

#

and more memory

verbal bobcat
#

i think i'll need to change how board editing works internally

#

i think i want a separate "lowlevel" editor

#

that operates on the internal tilmap

#

and the highlevel which you tell to do complicated stuff with the lowlevel

#

since now i want to have low-level access to the structure

#

i think

#

for the properties editor i want it to check which circuits need to change their geometry, remove them from the tilemap, and try placing them again with new geometry

#

but i'm not sure where the implementation should be

#

problem is, circuits are locked during property changing and i will need to pass them to the editor somehow

verbal bobcat
#

and lowlevel only works with its tilemap

verbal bobcat
#

so much duplicated code

verbal bobcat
#

and it seems that nothing was broken in progress

#

well, i hope at least

verbal bobcat
#

most thinking intensive 67 lines and it's not even done

#

and my brain is alrady melted

verbal bobcat
#

an hour later, it's still not done

verbal bobcat
#

oh

worn warren
#

...fuck, posts don't have individual permissions 🗿

#

welp

#

rip

verbal bobcat
#

i could make a bot for it maybe

#

i wonder if any of rusts discord libraries support passive interactions

#

where discord sends a POST to your server instead of a websocket message

#

actually, i won't need a library for this, not that complex

#

or can this be integrated into ai-chan @worn warren? and if i could help with that

worn warren
undone lintelBOT
worn warren
verbal bobcat
#

how

#

also i made messages ephemeral so they won't spam with errors or status messages

verbal bobcat
#

ah, you probably left the old one running

#

that would make sense

verbal bobcat
#

made errors display in-world aswell

#

and not spam lol

#

like this

worn warren
undone lintelBOT
verbal bobcat
#

so new one errored

worn warren
#
2025-11-10T21:49:54.331807Z ERROR ai_chan::commands::threadpin: Cannot respond to message command: Interaction has already been acknowledged.
```ok makes sense ![dawae](https://cdn.discordapp.com/emojis/1215396892683272233.webp?size=128 "dawae") I'll test without
#

yay :D

#

Ok amazing

#

I'll merge that

undone lintelBOT
verbal bobcat
#

worksss

#

nice

rancid forge
graceful junco
#

physics

rancid forge
verbal bobcat
#

only one tile can exist in a certain spot

rancid forge
verbal bobcat
#

too complex already

verbal bobcat
#

properties window is working

#

woo

rare pulsar
#

:o

verbal bobcat
#

how compatible old components to the new engine:

#

(so not at all)

verbal bobcat
#

does clock's pwm needs to be configurable?

#

does anyone even need that

#

since technically you can make it with two clocks and some logic

#

(pwm in the old version referred to pulse width, what % of the cycle time signal should be on)

#

i think i will just skip pwm

#

can always add it later

#

also will need to implement transparent attribute for smoldata_derive to skip writing this

verbal bobcat
#

i need to figure out what theme for components i want

#

clock done and pushed!

verbal bobcat
#

i should add an oscilloscope

spiral mirageBOT
#

wohooii!

narrow bison
#

Oh hey this is pretty cool

#

I now get notifications, will watch

verbal bobcat
#

I'm thinking what i want to do next

#

there's a whole todo list pinned in this channel

#

though tbh i want to make a component to interact with outside sockets

#

like writing to stdout or reading from stdin

#

but that's a complicated component, so at some point i'll need to make a datasheet system

#

but i also need to implement transistors to make tristate logic possible

#

and make things like RAM circuits more compact

#

also need to make gates have multiple inputs

#

and make their inputs invertable

#

though there's a problem with invertable inputs - the circles that indicate inversion take space

#

so i'll need to move something to fit them

#

in the existing gate designs those circles move the tip of the gate a little back

verbal bobcat
#

big boi

verbal bobcat
#

AAAAAA it works, it writes to stdout!!!!

#

(there is a ton of stuff going in the background to make it asynchronous)

#

and it reads as well!

#

ah, with stdin, there's no way to cancel a stdin read operation, at least not easily

#

so reconnecting to stdin will eat some input

#

specificaly it will eat one stdin read, so one line 64 bytes max

verbal bobcat
#

i need to make or find a program to convert a truth table to a bunch of binary expressions

verbal bobcat
#

lol

#

i'll need to draw a better component

#

maybe show tx ready / rx ready as little leds on the chip

#

and show which side is which

proud wharfBOT
#

fuck yeah omg

#

that is so cool

verbal bobcat
verbal bobcat
#

i made a program that takes a truth table and a list of expressions and verifies that they produce the correct output, then tried to make a smallest possible circuit that returns bytes for Hello, world! when given a byte index

#

(ABCD input index MSB to LSB, a-g is output bits, MSB to LSB)

#

though it probably will be such a mess ig i build that with logic gates

#

(also it doesn't count inverting a variable as operation since it gets reused multiple times anyway)

#

now it does, so that would be 40 gates total

#

though actually probably less since cuprous has nands nors and xnors

#

2 less(

#
ABCD abcdefg
0000 1001000
0001 1100101
0010 1101100
0011 1101100
0100 1101111
0101 0101100
0110 0100000
0111 1110111
1000 1101111
1001 1110010
1010 1101100
1011 1100100
1100 0100001

v = A!B
w = v!D
x = C ^ D
y = B ^ C
z = B!x

a = !(B(A | x))
c = D((A ^ B) & !y)
d = !A(!D!(BC) | Dy) | w
e = !A(D | y) | vC | w
f = !Az | v!C

g = (!C!D | ce) ^ (!A!B!C)
b = c | e | B

if someone wants to build it themselves

#

because i need to sleep already

#

i spent 4 hours of my life compacting a truth table(

verbal bobcat
#

Would be fun to connect this to shapez 2 wiring