APGsembly: Difference between revisions

From LifeWiki
Jump to navigation Jump to search
{{Copyedit}}
First copy-editing pass, as per recent request
Line 1: Line 1:
{{Copyedit}}
The general purpose calculator (GPC) is a way to implement computational tasks inside Conway's Game of Life. It's Turing complete and programmed by a special-purpose programming language called APGsembly. The first computational Life patterns using this technology were constructed by [[Adam P. Goucher]] in 2010. These [[pi calculator]] and [[phi calculator]] patterns, and a related pattern programmed to grow at [[Osqrtlogt|O(sqrt(log(t)))]], had all the same basic general-purpose components that make up the GPC.
The general purpose calculator (GPC) is a way to implement computational tasks inside conway's game of life. It's turing complete and programmed by special code called APGsembly. The first calculator was written by Adam P.Gaucher in 2011, it was printing the digits of pi and phi, and it had all the basic general purpose components. A compiler was written by Dave Greene to create a state in CGOL that will correspond to APGsembly code, and a visual emulator and debugger written by Michael Simkin and Dave Greene.  


The GPC is basically finite-state machines, where each line in a program corresponds to a state, and you have JUMP instructions for every return value. Each line can trigger one or more actions and you have to make sure that you execute exactly one reaction that returns a zero/nonzero value.  
Goucher's original compiler/editor was written in DarkBasic, which became difficult to run on modern computers. In 2019 a compiler was written by [[Dave Greene]] to create a Conway's Life pattern corresponding to APGsembly code, and a visual emulator and debugger was written by [[Michael Simkin]] and Dave Greene. At that time the logic circuitry was adjusted to include a standard set of components, and the resulting "GPC" was shown to be capable of supporting any of the three programs (pi, phi, or Osqrtlogt).


== Overview ==
The base GPC pattern includes just the logic and memory circuitry; an additional subpatterns representing an APGsembly program should be attached to a GPC to produce a complete calculator, printer, or other functional pattern. The additional subpattern is basically a finite-state machine.  Each line in a program corresponds to a state, and there are JUMP instructions for each possible return value (Z or NZ), pointing to the next state that the machine should enter. Each line of code can trigger one or more commands, or "actions", and it's important to make sure that each line includes exactly one action that returns a zero/nonzero value.


The calculator has a ticking clock in form of glider gun (of period 2^22 and higher), which emits a glider each time an operation was executed with return value either Z/NZ (represented by two possible different emitted glider lanes), as result of the last command. The commands are triggered by an input glider into special computational units on specific lanes to trigger a specific action (like ADD, SUB, WRITE, READ, INC etc.), defined by the APGsembly code.  
== Overview ==
 
The GPC includes a ticking clock in the form of two synchronized glider guns of period 2^20, 2^22 or higher, depending on what components are being used (see '''SQ''' below). These guns emit a glider each time an operation has been executed with a return value of either Z or NZ, represented by a glider emitted on one of two possible output [[lane]]s, as result of the most recent output-producing action. These actions are triggered by an input glider emitted by the calculator program pattern, sent into special computational units on specific lanes to trigger a specific action (ADD, SUB, WRITE, READ, INC, etc.) defined by the APGsembly code.  


Thus the GPC has four major physical components:  
Thus the GPC has four major physical components:  
Line 17: Line 18:
== The computational cycle ==
== The computational cycle ==


Each 2^22 generations, a glider gun is initiating an action based on output from previous cycle (it waits until output has returned).
Every 2^N generations, a glider gun initiates an action based on the output from the previous cycle.  The gun waits long enough that an output has most likely returned.  If no output has in fact appeared (this can happen when retrieving data from a very long data tape, for example) the gun waits for another cycle and checks again, using a [[universal regulator]] mechanism.
* The new action could be either Z or NZ.
* The return signal is always a one-bit output value, either Z or NZ.
* Each cycle is expected to return exactly one output, either Z or NZ.
* Each cycle is expected to return exactly one such output.


== Programming code ==
== Programming code ==


The code consist of operations logic per ''code name''. Each code can react differently to Z or NZ. The program consists of lines of code, each code corresponds to two lines of code (one for Z and one for NZ). The program must start with INITIAL, and will halt (if nothing is returned) or run forever if the program was written by the rules (i.e. single return per line).  
APGsembly code consists of a list of actions to be performed for each ''state ID'', for each possible return value (Z or NZ). The program consists of lines of code; each state ID corresponds to two lines of code, one for Z and one for NZ.
#The program must start with INITIAL, and will halt if it ever reaches a state where none of the actions return a Z/NZ response.
#If the program is written according the usual rules (i.e. single return per line), it will run indefinitely.
#Two or more actions with Z/NZ responses for a single state are technically illegal, and will likely but not inevitably cause chaotic explosions in the calculator pattern.


Each line of code consists of 4 parts:
Each line of code consists of 4 parts, separated by semicolons and optional whitespace:


'''CodeName; Z/NZ; NextCodeName; OP1, OP2, OP3 etc.'''
'''StateID; Z/NZ; NextStateID; Op1, Op2, Op3, etc.'''  


#'''CodeName.''' Each line has a code name.
#'''StateID.''' Each line's first element is a state ID.  This can be thought of as a line number, except that pairs of successive lines usually share the same state ID.
#'''Z/NZ.''' Each line has a policy of operations depending on returning Z or NZ from the previous cycle.
#'''Z/NZ.''' Each line's second element is either Z or NZ. Only the line matching the Z or NZ return value from the previous cycle will actually be executed.
#'''NextCodeName.''' Each line + Z/NZ defines the next execution line.
#'''NextStateID''' Each line's third element defines the state that will be executed on the next clock tick, if that line is executed.
#'''Op.''' Each line + Z/NZ defines a list of operations to be executed. The operations are inputs to the computational units. Some operations will not return anything and only change the state of the unit and some will return either Z or NZ depending on the internal state and the logic of some particular unit. It's programmer task to make sure there is exactly one return value.
#'''Op.''' Each line's fourth element defines a list of operations to be executed. The operations are inputs to the computational units. Some operations will not return anything and only change the state of the unit ; some will return either Z or NZ depending on the internal state of a particular logic unit. It's the programmer's task to make sure there is exactly one return value.
 
''NOP'' - The NOP operation is sending Z output directly.


'''Example:'''
'''Example:'''


INITIAL; Z; A2; NOP <br />
INITIAL; Z; A2; NOP
A1; Z; A2; INC T0 <br />
A1; Z; A2; INC T0
A1; NZ; A2; INC T0 <br />
A1; NZ; A2; INC T0
A2; Z; A1; READ T0, SET T0 <br />
A2; Z; A1; READ T0, SET T0
A2; NZ; A1; READ T0, SET T0 <br />
A2; NZ; A1; READ T0, SET T0


== Computational units ==
== Computational units ==


We have 6 types of units, each type has several instruction commands.
There are currently 6 types of logic units, though it is possible to add more.  Each type of logic unit has one or more actions, triggered by glider inputs on specific lanes.


# ''R'' - Sliding block register.
# ''NOP'' - The NOP operation sends a Z output directly, and takes no other action.
# ''T'' - Binary string register.
# ''R'' - sliding block register (holds a single integer value, stored in unary)
# ''ADD'' - adder.
# ''T'' - binary string register (holds an arbitrary-length string of binary digits)
# ''SUB'' - subtractor.
# ''ADD'' - adder
# ''MUL'' - we're not sure how to use.  
# ''SUB'' - subtractor
# ''SQ'' - a two dimensional (''square'') array of data.  
# ''MUL'' - ... we're not sure how to use this, but it shows up in the pi and phi calculator code, apparently as a binary-to-decimal converter.  
# ''SQ'' - a two-dimensional (''square'') array of data.  


The calculator can have arbitrary number of R and T units and a single ADD, SUB, MUL units.
The calculator can have an arbitrary number of R, T, ADD, SUB, and MUL units, a single SQ unit, and a single digit or character printer.


===R: Sliding block===
===R: Sliding block===


* Sliding block in the code is always starting from R. For example R0, R1, R2 etc.
* Sliding block registers in APGsembly code are denoted by keywords starting with the letter R -- for example, R0, R1, R2, etc.
* Sliding block has very simple logic. They represent a single number, and all you can do with them is INC (increase by 1) and TDEC (decrease by 1).<br />
* A sliding block register has very simple logic. It represents a single number, and all you can do with it is INC (increase by 1) and TDEC (test and decrease by 1).<br />


'''R: Operations:'''
'''R: Operations:'''


* INC Rx will just increase the register by 1. Will not return anything.
* ''INC Rx'' will increase the register by 1. No return signal.
* TDEC Rx will decrease the register by 1. Will return NZ if the register > 0 and Z otherwise.
* ''TDEC Rx'' will decrease the register by 1. Returns NZ if the register > 0, otherwise Z.


===T: Binary string register===
===T: Binary string register===


* The binary string registers are starting with T. For example T0, T1, ..T14 in APGsembly.
* Binary string registers in APGsembly code are denoted by keywords starting with T, short for "tape" -- for example, T0, T1, T2, etc.
* They have a "reading head". It can be moved with INC and DEC just like sliding block.
* A binary string register has a "reading head" that can be moved forward and backward along the tape with INC and DEC, just like a sliding block register.
* They can store arbitrarily-large binary strings. A program can only retrieve one bit at a time using READ command, followed by SET, RESET that can be called "WRITE 1" and "WRITE 0".
* A binary string register can store arbitrarily-large binary strings. A program can only retrieve one bit at a time using READ command, followed by SET or RESET actions.  SET and RESET might be more clearly named "WRITE 1" and "WRITE 0".


'''T: Operations'''
'''T: Operations'''


* INC Tx increase the position of reading head. Returns Z unless the space is empty then it returns NZ.
* ''INC Tx'' increases the position of reading head. Returns Z unless the space is empty then it returns NZ.
* DEC Tx decrease the position of reading head. Returns NZ unless at 0.
* ''DEC Tx'' decreases the position of reading head. Returns NZ unless at 0.
* READ Tx return the state of the binary string value located at reading head. Returns Z if the value is 0 and NZ if 1.
* ''READ Tx'' return the state of the binary string value located at reading head. Returns Z if the value is 0 and NZ if 1.
* SET Tx sets the state of the binary string to 1. Must be after READ operation which deletes the state.
* ''SET Tx'' sets the state of the binary string to 1. Must be after READ operation which deletes the state. No return signal.
* RESET Tx setse state of the binary string to 0. Must be after READ operation which deletes the state.
* ''RESET Tx'' setse state of the binary string to 0. Must be after READ operation which deletes the state. No return signal.


===ADD: adder===
===ADD: adder===
Line 85: Line 88:
One should think about the adder as having two bits A and B. Each of them has 0 or 1 option, and each of the options is an input to the adder. A input is just changing the state of the Adder unit, and B input returns the result.
One should think about the adder as having two bits A and B. Each of them has 0 or 1 option, and each of the options is an input to the adder. A input is just changing the state of the Adder unit, and B input returns the result.


* A0 is ignored case because there is nothing to change.
* ''A0'' is ignored case because there is nothing to change.
* A1 is a valid input
* ''A1'' is a valid input
* B0, B1 should come after A was initialized.
* ''B0'', ''B1'' should come after A was initialized.
* The adder returns (Ax + By + Memory) % 2
* The adder returns (Ax + By + Memory) % 2
* The adder stores Memory = (Ax + By + Prev Memory >= 2)
* The adder stores Memory = (Ax + By + Prev Memory >= 2)
Line 93: Line 96:
* If you not sure about the state of the adder just send B0 and you can be sure the Memory is cleaned.
* If you not sure about the state of the adder just send B0 and you can be sure the Memory is cleaned.


The operation code would look like ''ADD A1'' or ''ADD B0''.
'''ADD Actions'''
* ''ADD A1''
* ''ADD B0''
* ''ADD B1''


===SUB: subtractor===
===SUB: subtractor===


The subtractor works exactly as adder, just for subtracting two numbers bit by bit keeping in memory 0 or 1.  
The subtractor works exactly as adder, just for subtracting two numbers bit by bit keeping in memory 0 or 1.  
'''SUB Actions'''
* ''SUB A1''
* ''SUB B0''
* ''SUB B1''


===MUL===
===MUL===


MUL keeps inside a register a number between 0 and 10. While MUL 0 is dividing the number by 2, and MUL 1 is dividing it by 2 and adding 5. As mentioned we're not sure how it used.  
MUL keeps inside a register a number between 0 and 10. MUL 0 divides the number by 2, and MUL 1 divides it by 2 and adds 5. As mentioned we're not yet sure how exactly it is used, but it's involved with binary-to-decimal conversion in the pi and phi calculator programs.
 
'''MUL Actions'''
* ''MUL 0''
* ''MUL 1''


===SQ: a two dimensional array ===
===SQ: a two dimensional array ===
Line 107: Line 122:
* The SQ register is starting with SQ. For example INC SQ, DEC SQ, READ SQ etc. in APGsembly.
* The SQ register is starting with SQ. For example INC SQ, DEC SQ, READ SQ etc. in APGsembly.
* The SQ has two arms X and Y. Each arm can be moved with INC and DEC. For example INC SQX, DEC SQY.
* The SQ has two arms X and Y. Each arm can be moved with INC and DEC. For example INC SQX, DEC SQY.
* A program can retrieve a bit located at (X, Y) by READ command. Unlike T where you must follow with SET, RESET the SQ will erase the (X, Y) bit only if it was existing. It also has only SET SQ command.  
* A program can retrieve a bit located at (X, Y) by READ command. Unlike T where you must follow with SET, RESET the SQ will erase the (X, Y) bit only if it was existing. It also has only SET SQ command.
* This SQ unit's internal circuitrly operates fairly slowly. If an APGsembly program makes use of this component, a clock gun of at least period 2^22 is required.


'''SQ: Operations'''
'''SQ Operations'''
* INC SQX/SQY increase the position of X/Y arm. Will not return anything.
* ''INC SQX'' increases the position of the X arm. No return signal.
* DEC SQX/SQY decrease the position of X/Y arm. Returns NZ unless at 0.
* ''INC SQY'' increases the position of the Y arm. No return signal.
* READ SQ return the state of the binary value located at (X, Y). Returns Z if there is nothing and NZ otherwise.
* ''DEC SQX'' decreases the position of X arm, or if it's at 0 already, keeps it there. Returns Z if already at 0, otherwise NZ.
* SET SQ sets the state at (X, Y) to 1 (breaks if the cell is set to 1).  
* ''DEC SQY'' decreases the position of Y arm, or if it's at 0 already, keeps it there. Returns Z if already at 0, otherwise NZ.
* ''READ SQ'' returns the state of the binary value located at (X, Y). Returns Z if the current state is 0 (empty), otherwise NZ.
* ''SET SQ'' sets the state at (X, Y) to 1 (breaks if the cell is set to 1). No return signal.


===Printer===
===Printer===


The printer can print "." and digits 0-9. It will not return anything. <br />
The printer can print "." and digits 0-9. No return signal. <br />


The command is<br />
The command is<br />
Line 124: Line 142:
== Further details ==  
== Further details ==  


You can see the discussions and examples as well you can ask question in [https://www.conwaylife.com/forums/viewtopic.php?f=2&t=4196&sid=3194b56e4730fe694ebecca64e511a69 this] conwaylife.com forum thread.<br /><br />
For further discussion and examples, or to ask questions, see [https://www.conwaylife.com/forums/viewtopic.php?f=2&t=4196&sid=3194b56e4730fe694ebecca64e511a69 this conwaylife.com forum thread].
 
[https://github.com/dvgrn/b3s23life/tree/master/calculator Here] you can download the compiler and debugger.
[https://github.com/dvgrn/b3s23life/tree/master/calculator Here] you can download the compiler and debugger.

Revision as of 02:52, 2 December 2019

The general purpose calculator (GPC) is a way to implement computational tasks inside Conway's Game of Life. It's Turing complete and programmed by a special-purpose programming language called APGsembly. The first computational Life patterns using this technology were constructed by Adam P. Goucher in 2010. These pi calculator and phi calculator patterns, and a related pattern programmed to grow at O(sqrt(log(t))), had all the same basic general-purpose components that make up the GPC.

Goucher's original compiler/editor was written in DarkBasic, which became difficult to run on modern computers. In 2019 a compiler was written by Dave Greene to create a Conway's Life pattern corresponding to APGsembly code, and a visual emulator and debugger was written by Michael Simkin and Dave Greene. At that time the logic circuitry was adjusted to include a standard set of components, and the resulting "GPC" was shown to be capable of supporting any of the three programs (pi, phi, or Osqrtlogt).

The base GPC pattern includes just the logic and memory circuitry; an additional subpatterns representing an APGsembly program should be attached to a GPC to produce a complete calculator, printer, or other functional pattern. The additional subpattern is basically a finite-state machine. Each line in a program corresponds to a state, and there are JUMP instructions for each possible return value (Z or NZ), pointing to the next state that the machine should enter. Each line of code can trigger one or more commands, or "actions", and it's important to make sure that each line includes exactly one action that returns a zero/nonzero value.

Overview

The GPC includes a ticking clock in the form of two synchronized glider guns of period 2^20, 2^22 or higher, depending on what components are being used (see SQ below). These guns emit a glider each time an operation has been executed with a return value of either Z or NZ, represented by a glider emitted on one of two possible output lanes, as result of the most recent output-producing action. These actions are triggered by an input glider emitted by the calculator program pattern, sent into special computational units on specific lanes to trigger a specific action (ADD, SUB, WRITE, READ, INC, etc.) defined by the APGsembly code.

Thus the GPC has four major physical components:

  1. Clock.
  2. Programming code.
  3. Computational unit array.
  4. Printer and SQ

The computational cycle

Every 2^N generations, a glider gun initiates an action based on the output from the previous cycle. The gun waits long enough that an output has most likely returned. If no output has in fact appeared (this can happen when retrieving data from a very long data tape, for example) the gun waits for another cycle and checks again, using a universal regulator mechanism.

  • The return signal is always a one-bit output value, either Z or NZ.
  • Each cycle is expected to return exactly one such output.

Programming code

APGsembly code consists of a list of actions to be performed for each state ID, for each possible return value (Z or NZ). The program consists of lines of code; each state ID corresponds to two lines of code, one for Z and one for NZ.

  1. The program must start with INITIAL, and will halt if it ever reaches a state where none of the actions return a Z/NZ response.
  2. If the program is written according the usual rules (i.e. single return per line), it will run indefinitely.
  3. Two or more actions with Z/NZ responses for a single state are technically illegal, and will likely but not inevitably cause chaotic explosions in the calculator pattern.

Each line of code consists of 4 parts, separated by semicolons and optional whitespace:

StateID; Z/NZ; NextStateID; Op1, Op2, Op3, etc.

  1. StateID. Each line's first element is a state ID. This can be thought of as a line number, except that pairs of successive lines usually share the same state ID.
  2. Z/NZ. Each line's second element is either Z or NZ. Only the line matching the Z or NZ return value from the previous cycle will actually be executed.
  3. NextStateID Each line's third element defines the state that will be executed on the next clock tick, if that line is executed.
  4. Op. Each line's fourth element defines a list of operations to be executed. The operations are inputs to the computational units. Some operations will not return anything and only change the state of the unit ; some will return either Z or NZ depending on the internal state of a particular logic unit. It's the programmer's task to make sure there is exactly one return value.

Example:

INITIAL; Z; A2; NOP
A1; Z; A2; INC T0
A1; NZ; A2; INC T0
A2; Z; A1; READ T0, SET T0
A2; NZ; A1; READ T0, SET T0

Computational units

There are currently 6 types of logic units, though it is possible to add more. Each type of logic unit has one or more actions, triggered by glider inputs on specific lanes.

  1. NOP - The NOP operation sends a Z output directly, and takes no other action.
  2. R - sliding block register (holds a single integer value, stored in unary)
  3. T - binary string register (holds an arbitrary-length string of binary digits)
  4. ADD - adder
  5. SUB - subtractor
  6. MUL - ... we're not sure how to use this, but it shows up in the pi and phi calculator code, apparently as a binary-to-decimal converter.
  7. SQ - a two-dimensional (square) array of data.

The calculator can have an arbitrary number of R, T, ADD, SUB, and MUL units, a single SQ unit, and a single digit or character printer.

R: Sliding block

  • Sliding block registers in APGsembly code are denoted by keywords starting with the letter R -- for example, R0, R1, R2, etc.
  • A sliding block register has very simple logic. It represents a single number, and all you can do with it is INC (increase by 1) and TDEC (test and decrease by 1).

R: Operations:

  • INC Rx will increase the register by 1. No return signal.
  • TDEC Rx will decrease the register by 1. Returns NZ if the register > 0, otherwise Z.

T: Binary string register

  • Binary string registers in APGsembly code are denoted by keywords starting with T, short for "tape" -- for example, T0, T1, T2, etc.
  • A binary string register has a "reading head" that can be moved forward and backward along the tape with INC and DEC, just like a sliding block register.
  • A binary string register can store arbitrarily-large binary strings. A program can only retrieve one bit at a time using READ command, followed by SET or RESET actions. SET and RESET might be more clearly named "WRITE 1" and "WRITE 0".

T: Operations

  • INC Tx increases the position of reading head. Returns Z unless the space is empty then it returns NZ.
  • DEC Tx decreases the position of reading head. Returns NZ unless at 0.
  • READ Tx return the state of the binary string value located at reading head. Returns Z if the value is 0 and NZ if 1.
  • SET Tx sets the state of the binary string to 1. Must be after READ operation which deletes the state. No return signal.
  • RESET Tx setse state of the binary string to 0. Must be after READ operation which deletes the state. No return signal.

ADD: adder

One should think about the adder as having two bits A and B. Each of them has 0 or 1 option, and each of the options is an input to the adder. A input is just changing the state of the Adder unit, and B input returns the result.

  • A0 is ignored case because there is nothing to change.
  • A1 is a valid input
  • B0, B1 should come after A was initialized.
  • The adder returns (Ax + By + Memory) % 2
  • The adder stores Memory = (Ax + By + Prev Memory >= 2)
  • The memory bit is always stored in the unit when existent.
  • If you not sure about the state of the adder just send B0 and you can be sure the Memory is cleaned.

ADD Actions

  • ADD A1
  • ADD B0
  • ADD B1

SUB: subtractor

The subtractor works exactly as adder, just for subtracting two numbers bit by bit keeping in memory 0 or 1.

SUB Actions

  • SUB A1
  • SUB B0
  • SUB B1

MUL

MUL keeps inside a register a number between 0 and 10. MUL 0 divides the number by 2, and MUL 1 divides it by 2 and adds 5. As mentioned we're not yet sure how exactly it is used, but it's involved with binary-to-decimal conversion in the pi and phi calculator programs.

MUL Actions

  • MUL 0
  • MUL 1

SQ: a two dimensional array

  • The SQ register is starting with SQ. For example INC SQ, DEC SQ, READ SQ etc. in APGsembly.
  • The SQ has two arms X and Y. Each arm can be moved with INC and DEC. For example INC SQX, DEC SQY.
  • A program can retrieve a bit located at (X, Y) by READ command. Unlike T where you must follow with SET, RESET the SQ will erase the (X, Y) bit only if it was existing. It also has only SET SQ command.
  • This SQ unit's internal circuitrly operates fairly slowly. If an APGsembly program makes use of this component, a clock gun of at least period 2^22 is required.

SQ Operations

  • INC SQX increases the position of the X arm. No return signal.
  • INC SQY increases the position of the Y arm. No return signal.
  • DEC SQX decreases the position of X arm, or if it's at 0 already, keeps it there. Returns Z if already at 0, otherwise NZ.
  • DEC SQY decreases the position of Y arm, or if it's at 0 already, keeps it there. Returns Z if already at 0, otherwise NZ.
  • READ SQ returns the state of the binary value located at (X, Y). Returns Z if the current state is 0 (empty), otherwise NZ.
  • SET SQ sets the state at (X, Y) to 1 (breaks if the cell is set to 1). No return signal.

Printer

The printer can print "." and digits 0-9. No return signal.

The command is
OUTPUT x

Further details

For further discussion and examples, or to ask questions, see this conwaylife.com forum thread.

Here you can download the compiler and debugger.