Wirefunge

From Esolang
Jump to navigation Jump to search

Wirefunge is a language created by User:Patashu in 2011 as a way to represent a circuit in ASCII that reads from stdin and writes to stdout (as well as reads/writes to a file optionally) in groups of 8 bits that are put/get whenever respective signals are fired. Starting from explicit input terminals where stdin, fstream and clock come in, paths are followed along the direction of wires into other circuit elements, where all remaining adjacent wires are marked as outputs of those elements, and the process continued until the entire circuit is parsed, and then simulated until stopped by a signal.
Currently, every ASCII character has a use.

A wirefunge program has the following parameters:

  • an stdin stream
  • an stdout stream
  • an fin and fout stream
  • read/write/append file mode
  • a mode for interpreting input and output (default ascii):
    • binary expects and prints bits as 0-1
    • hexadecimal expects and prints bits as 0-f, truncating a leading 0x if present
    • decimal interprets its input as a decimal number, rewrites it in two's compliment and reads off bits, outputting the result
    • ascii just reads the raw bits of its input and writes them to output

Draft Spec

Wiring

- / | \ are wires segments.
A signal on a wire segment will propagate instantly in the direction(s) indicated by it - a signal out a will reach 1, but a hypothetical signal from 1 would fall off the wire and never create an output;

    1
    |
    |
   /
a-/

It will go both ways if it didn't come from one of the ends:
a will signal to 1 and 2 but 1 and 2 can't signal to a

  1
a-|
  2

* is a hub, a special kind of wire - it sends signals only onto wires that point onto it. This is also the behaviour of logic gates and other elements. Here, a can signal 1 but 1 can't signal a.

 \|/
1-* a
 /|/
  |

Wires can be crossed as follows:

\/
/\

Input

If an input appears more than once, its value is the same for all of them.

a-h are the 8 bits of the current stdin character, most significant bit first
A-H are the 8 bits of the current fin character, most significant bit first.
1-8 are the 8 bits of the current stdout character, most significant bit first
@ outputs 0 and toggles after every simulation iteration (clock)
$ outputs 0 and rises when a read fails and falls when a read succeeds
9 outputs 0 and toggles after every read
0 outputs 0 and toggles after every write
' always outputs 0
" always outputs 1
I-Z signal the last value pushed onto their respective wireless channel (18 in total)

If not all 8 of a-h / A-H / 1-8 are present, then it will only put and get that many bits at a time.

Output/Timing

<, when it rises, gets the next stdin char into a-h
>, when it rises, puts 1-8 on stdout
(, when it rises, gets the next fin character into A-H
), when it rises, puts 1-8 on fout
{, when it rises, moves the fin pointer to the start of the previous line
}, when it rises, moves the fin pointer to the start of the previous line
[, when it rises, moves the fin pointer one character back
], when it rises, moves the fin pointer one character forward
%, when it rises, ends the program
i-z, when an input to them toggles, pushes the new value onto their respective wireless channel (18 in total)

If % is not present, the program ends when a read fails or when 3 iterations in a row cause nothing to change (? triggering and not changing its output counts as a change).

Operation

Inputs and outputs of logic gates are determined by first following all inputs to logic gates they enter, marking all those entrances as inputs. This is done in simultaneous generations. Once a gate has enough inputs (or/and/xor/nor/nand/xnor require 2 or more, 'output' elements will never stop accepting inputs, everything else requires 1 or more) remaining adjacent wires and elements become outputs of those gates, and wires followed to other logic gates they reach, becoming inputs to them and so on. If a gate goes over its minimum in a generation, all of the connections made will be admitted - but if you expect synchronization and don't get it or vice versa, your circuit will be wired unexpectedly.

It takes one iteration for outputs of a circuit element to propagate - thus, every iteration consists of following each input to each output and priming inputs for next propagation.

To allow circuits to be more compact, circuit elements act like hubs; pieces of wire must point directly into an element to become outputs of it as well as inputs, so you can do things like:

a--
b--
c--

If it is still the case that two signals travel onto a piece of wire, 1s take priority over 0s.

Solving Wiring Loops

But wait - what about circuits that (immediately or eventually) feed input into output?

    *-*
    | |
a---`-*---1

a will send a signal to `, priming that wire as input 1 - and then it will wait forever in the circuit mapping stage, not knowing which of the remaining wires is intended to be input 2!

To solve this, an element will send 'probe' signals down all adjacent wires. If they fall into the abyss (don't reach any other element) BUT another element can send a signal onto it, this must be an input - but it won't be activated immediately. To allow for easier synchronization of multi-input elements, it won't decide that the remaining wires are outputs until at least one input has propagated to it normally. So, redesign the circuit like this:

    |--
    | |
a---`-*---1

` probes north, and finds that it must be an input.
a sends a signal to `, linking a as an input to `.
` now sees it has enough inputs, and makes east its output - linking that to 1 and `.

(A consequence of this is that an output wire should never lead into nothing. If you need a dummy output, delimit it with an element that needs at least one input and output - an element with less wires than minimum ports will see that it is useless and not be simulated. For example, if you put a . above the | in the previous example then it would once again never complete its wiring, because it would think north is a dummy output)

Logic Gates

A logic gate with 3+ inputs will treat 3+ 1s the same as it treats 2 1s.

_ for buffer
! for not
+ for or
& for and
^ for xor
~ for nor
` for nand
= for xnor

Memory elements

, for lever (toggle output state when any input rises)
# for mod 3 toggle (toggle output state every 3 toggles of inputs) (shift+3)
. for metastable element (propagates 1s for exactly one iteration no matter how long they last)
; for dam (propagates 1s that last more than one iteration)
: for pulse dam (propagates 1s that last exactly one iteration)
? for random bit dispenser (randomize output when any input rises)

Latin-1 memory elements

Because ASCII doesn't have enough characters for me:

×£¥¦§¨ª©®¯°´µ¶·¸ºøæÆÐÞßĐ
¡ for edge detector (sends 1 for one iteration when any input toggles)
¢ for capacitor (when input rises, start counting. when input falls, send 1 for the same length)
¿ for random clock (randomized output every iteration. like a random bit dispenser with two inputs that alternate rising)
½ for mod 2 toggle (toggle output state every 2 toggles of inputs)
¼ for mod 4 toggle (toggle output state every 4 toggles of inputs)
¾ for 3/4 toggle (toggle output state for 3 toggles, then skip the fourth)

Latin-1 wiring

÷ for omnidirectional crossover (signals moving onto it go in the same direction, allowing multiple wires to intersect)
¹ ² ³ next to any element indicates that it expects that many inputs, and will wait for that number before designating the remaining connections as outputs.
¬ next to any element indicates that its outputs will be NOTed before being sent.
± next to any element indicates that its inputs will be NOTed before being sent.
Ø is a NOTing hub - it acts like a hub in that it has no delay, except signals passing across it are NOTed.
¤ is a NOTing crossover
« next to any piece of wire/element indicates that this acts as an input for any elements it connects to - it will not be designated an output
» next to any piece of wire/element indicates that this acts as an output for any elements it connects to - it will not be designated an input

Example Programs

Cat

a1 b2 c3 d4 $%

e5 f6 g7 h8 @-_<
            |
            !
            >

Wirefunge Minimal

Obviously required:

  • - | for wiring and splitting, but will you also need / \ for handling the Wire-crossing problem?
  • a 1, for input and output bit by bit
  • < > for getting and putting
  • ` for arbitrary boolean logic

How many of these are needed?:

  • @ 0 9 for clocking (it seems at least one of these is required to prevent the circuit from being static, as it won't be externally clocked)
  • ' " for creating 0 and 1 (rather create a NAND memory cell and initiate it with 0 or 1 and use that forever?)
  • memory elements for timing (don't THINK any of these are needed...)