IOTA-C0

From Esolang
Jump to navigation Jump to search
IOTA-C0
Paradigm(s) Imperative
Designed by User:Enoua5
Appeared in 2018
Memory system Cell based
Computational class Turing complete
Major implementations IOTA-C0 Suite
File extension(s) .c0.ic0

Introduction

IOTA-C0 is a processor specification created by User:Enoua5 in 2018. It was meant to work entirely off of computational RAM, its only native instruction being to copy the value in one memory address into another memory address. There were a few decisions in the creation of this specification that would make the IOTA-C0 very impractical to build, though it does make the programming a little easier.

Processor Documentation

Memory

Basics

RAM: 65536 16-bit addresses, from 0x0000 to 0xFFFF

Registers: 2 16-bit registers for holding data read from RAM

Layout of RAM

Section name Start address End address Read only? Description Default value
Literals 0x0000 0x7FFF YES

Because the IOTA-C0 can only work with pointers, these memory addresses hold literals, so that programs can actually use literals.

Their address in memory
Computation RAM 0x8000 0x807F

See Computational RAM

Stack A 0x8080 0x80BF YES

Values are filled from low end to high end. If all 64 are filled and a value is pushed, nothing happens If there are no values in the stack when a value is popped, returns 0x0000 and makes no change

0
Stack B 0x80C0 0x80FF YES

Values are filled from low end to high end. If all 64 are filled and a value is pushed, nothing happens If there are no values in the stack when a value is popped, returns 0x0000 and makes no change

0
Standard RAM 0x8100 0xFFFF NO Low end reserved for program; all rest is for the program's variables 0

Clock Cycle

The following procedure is run every clock cycle

  1. Copy the value in memory address 0x8000 into register 0
  2. Copy the value in the memory address pointed to by the value in register 0 into register 0
  3. Increment the value in memory address 0x8000
  4. Copy the value in memory address 0x8000 into register 1
  5. Copy the value in the memory address pointed to by the value in register 1 into register 1
  6. Increment the value in memory address 0x8000
  7. Copy the value in the memory address pointed to by the value in register 1 into the memory address pointed to by the value in register 0

Or, in less verbose terms:

  1. R[0]=M[0x8000]
  2. R[0]=M[R[0]]
  3. M[0x8000]++
  4. R[1]=M[0x8000]
  5. R[1]=M[R[1]]
  6. M[0x8000]++
  7. M[R[0]]=M[R[1]]

Computational RAM

Computation RAM is how the IOTA-C0 performs all its computation. The values in this area (0x8000-0x807F) change between clock cycles based on nearby values, following the rules detailed in the table below.

A hex number is a literal.
A hex number in brackets is a value pointed to by the number. (a pointer)
A hex number in double brackets is a value pointed to by the number at the address pointed to by the number. (a pointer pointer)

Address Read only? Operation
0x8000 NO Instruction pointer
Default value: 0x8100
0x8001 NO Value becomes value|0x8000
Default value: 0x807F
0x8002 NO The value here gets written to [[0x8001]]
0x8003 NO Normal slot
0x8004 NO Value becomes value|0x8000
0x8005 NO Value becomes value|0x8000
0x8006 YES Value becomes [0x8004] if [0x8003] is not 0x0000;
Value becomes [0x8005] id [0x8003] is 0x0000
0x8007 NO Normal slot
0x8008 NO Normal slot
0x8009 NO Normal slot
0x800A YES Value becomes [0x8008] if [0x8007] is not 0x0000;
Value becomes [0x8009] id [0x8007] is 0x0000
0x800B NO Normal slot
0x800C NO Normal slot
0x800D YES Value becomes [0x800B]&[0x800C]
0x800E NO Normal slot
0x800F NO Normal slot
0x8010 YES Value becomes [0x800E]|[0x800F]
0x8011 NO Normal slot
0x8012 NO Normal slot
0x8013 YES Value becomes [0x8011]XOR[0x8012]
0x8014 NO Normal slot
0x8015 YES Value becomes ~[0x8014]
0x8016 NO Normal slot
0x8017 NO Normal slot
0x8018 YES Value becomes 0xFFFF if [0x8016]<[0x8017];
Value becomes 0x0000 otherwise
0x8019 NO Normal slot
0x801A NO Normal slot
0x801B YES Value becomes 0xFFFF if [0x8019]<=[0x801A];
Value becomes 0x0000 otherwise
0x801C NO Normal slot
0x801D NO Normal slot
0x801E YES Value becomes 0xFFFF if [0x801C]>[0x801D];
Value becomes 0x0000 otherwise
0x801F NO Normal slot
0x8020 NO Normal slot
0x8021 YES Value becomes 0xFFFF if [0x801F]>=[0x8020];
Value becomes 0x0000 otherwise
0x8022 NO Normal slot
0x8023 NO Normal slot
0x8024 YES Value becomes 0xFFFF if [0x8022]==[0x8023];
Value becomes 0x0000 otherwise
0x8025 NO Normal slot
0x8026 NO Normal slot
0x8027 YES Value becomes 0xFFFF if [0x8025]!=[0x8026];
Value becomes 0x0000 otherwise
0x8028 NO Normal slot
0x8029 NO Normal slot
0x802A YES Value becomes [0x8028]>>>[0x8029]
0x802B NO Normal slot
0x802C NO Normal slot
0x802D YES Value becomes [0x802B]>>[0x802C]
0x802E NO Normal slot
0x802F NO Normal slot
0x8030 YES Value becomes [0x802E]<<[0x802F]
0x8031 NO Normal slot
0x8032 NO Normal slot
0x8033 YES Value becomes [0x8031]+[0x8032]
0x8034 NO Normal slot
0x8035 NO Normal slot
0x8036 YES Value becomes [0x8034]-[0x8035]
0x8037 NO Normal slot
0x8038 NO Normal slot
0x8039 YES Value becomes [0x8037]*[0x8038]
0x803A NO Normal slot
0x803B NO Normal slot
0x803C YES Value becomes [0x803A]/[0x803B]
Division by 0 results in 0
0x803D NO Normal slot
0x803E NO Normal slot
0x803F YES Value becomes [0x803D]%[0x803E]
Division by 0 results in 0
0x8040 NO Normal slot
0x8041 YES Value becomes [0x8040]+1
0x8042 NO Normal slot
0x8043 YES Value becomes [0x8042]-1
0x8044 NO Normal slot
0x8045 YES Value becomes [0x8044]*-1
0x8046 NO Value becomes value|0x8000
0x8047 NO Normal slot
0x8048 YES If a non-zero value is attempted to be moved here,
[0x8047] is pushed to stack A
0x8049 NO Normal slot
0x804A YES If a non-zero value is attempted to be moved here,
[0x8049] becomes the value popped off stack A
0x804B NO Normal slot
0x804C YES If a non-zero value is attempted to be moved here,
[0x804B]|0x8000 is pushed to stack B
0x804D NO Normal slot
0x804E YES If a non-zero value is attempted to be moved here,
[0x804D] becomes the value popped off stack B
0x804F YES Returns a random value when read
0x8050 YES Normal slot
0x8051 YES Value becomes the value in [[0x8050]]
0x8052-0x807E YES Unassigned
0x807F YES If a non-zero value is attempted to be moved here, all writable memory is set to 0

Assembly Documentation

Preprocessor

A preprocessot instruction begins with a . character on its own line. The dot is followed by the command, then arguments seperated by spaces.

Commands

Command Arguments Description Technical
.const name value Creates a constant that can be called by prepending : to the front of the name.
  • name follows C variable naming rules.
  • Will replace all instances of :name with value.
.var name Declares a varible that can be called by prepending : to the front of the name.
  • Compiles into a .const declaration
  • The first .var will be given a value of 0xFFFF when compiled into a .const
  • Each successive .var will be given a value one less than the last.
.var name[number] Declares an array that can be called by prepending : to the front of the name and appending an index in brackets.
  • Compiles into .var declarations and a .const declaration
  • number is a positive integer in base 10.
  • Compiles into number .var declarations, with names from name[0] to name[number-1], and a .const declaration with a value 0x8000 less than name[0]

Preprocessor Example

If we start with the following code;

 .var variable
.var array[3]
.const constant1 10
.const constant2 42
ADD :constant1 :constant2 :array[1]
ADD :array[1] :array :variable

First, vars will be compiled into consts to get this;

 .const variable 0xFFFF
.const array[2] 0xFFFE
.const array[1] 0xFFFD
.const array[0] 0xFFFC
.const array 0x7FFC
.const constant1 10
.const constant2 42
ADD :constant1 :constant2 :array[1]
ADD :array[1] :array :variable

Then, the consts will be pasted into the code to get this;

 ADD 10 42 0xFFFF
ADD 0xFFFE 0x7FFC 0xFFFF

Assembly

  • One command per line
  • # denotes a comment
  • Any amount of whitespace can go before or after a command
  • One of more white space characters (excluding new line) can go between arguments
  • Arguments can be any dec, hex, octal, or binary number from 0x000-0xFFFF
  • dec is written as just a number (eg 42)
  • hex is written as 0x and a number (eg 0x2A)
  • octal is written as 0 and a number (eg 052)
  • binary is written as a 0b and a number (eg 0b101010)
  • * can be put before a number to to work as an address (eg *0x10 becomes 0x8010 when compiled)

In this table:

  • An argument prepended with : will default to being prepended with *, even if this is not put there in the program. This cannot be turned off.
  • An argument in brackets means that it is optional. A section of compilation in brackets means that it will only be present if the optional argument is present
Command Arguments Mnemonic Description Compiles into
NOP None No Operation Does nothing

0000 0000

MOV :N M Move Copy M into address N

NNNN MMMM

JMP N Jump Jump execution to address N

8046 NNNN 8000 8046

QJP :N Quick Jump (Can't take literals) Jump execution to the address in address N

8000 NNNN

SET N M Set Set the value in memory address N to M

8001 NNNN 8002 MMMM

STA N Set Address Like SET, but without changing the value currently being used

8001 NNNN

STV N Set Value Like SET, but without changing the address currently being used

8002 NNNN

TNA N M L [:K] Ternary Address If N is nonzero, set the value in memory address K to :M; else set it to :L

8003 NNNN 8004 MMMM 8005 LLLL [KKKK 8006]

TRN N M L [:K] Ternary If N is nonzero, set the value in memory address K to M; else set it to L

8007 NNNN 8008 MMMM 8009 LLLL [KKKK 800A]

AND N M [:L] And Write the result of the bitwise-and operation between N and M to memory address L

800B NNNN 800C MMMM [LLLL 800D]

ORR N M [:L] Or Write the result of the bitwise-or operation between N and M to memory address L

800E NNNN 800F MMMM [LLLL 8010]

XOR N M [:L] Exclusive Or Write the result of the bitwise-xor operation between N and M to memory address L

8011 NNNN 8012 MMMM [LLLL 8013]

NOT N [:M] Not Write the result of the bitwise-not operation of N to memory address M

8014 NNNN [MMMM 8015]

LST N M [:L] Less Than If M is less than M, set the value in memory address L to 0xFFFF; else set it to 0

8016 NNNN 8017 MMMM [LLLL 8018]

LOE N M [:L] Less Than or Equal If M is less than or equal to M, set the value in memory address L to 0xFFFF; else set it to 0

8019 NNNN 801A MMMM [LLLL 801B]

GRT N M [:L] Greater Than If M is greater than M, set the value in memory address L to 0xFFFF; else set it to 0

801C NNNN 801D MMMM [LLLL 801E]

GOE N M [:L] Greater Than or Equal If M is greater than or equal to M, set the value in memory address L to 0xFFFF; else set it to 0

801F NNNN 8020 MMMM [LLLL 8021]

EQU N M [:L] Equal If M is equal to M, set the value in memory address L to 0xFFFF; else set it to 0

8022 NNNN 8023 MMMM [LLLL 8024]

NEQ N M [:L] Not Equal If M is not equal to M, set the value in memory address L to 0xFFFF; else set it to 0

8025 NNNN 8026 MMMM [LLLL 8027]

SHR N M [:L] Shift Right Shifts N right by M bits and saves the value in memory address L

8028 NNNN 8029 MMMM [LLLL 802A]

ASR N M [:L] Arithmatic Shift Right Shifts N right by M bits arithmatically and saves the value in memory address L

802B NNNN 802C MMMM [LLLL 802D]

SHL N M [:L] Shift Left Shifts N left by M bits and saves the value in memory address L

802E NNNN 802F MMMM [LLLL 8030]

ADD N M [:L] Add Add N and M, saving the result in memory address L

8031 NNNN 8032 MMMM [LLLL 8033]

SUB N M [:L] Subtract Subtract M form N, saving the result in memory address L

8034 NNNN 8035 MMMM [LLLL 8036]

MUL N M [:L] Multiply Multiply N by M, saving the result in memory address L

8037 NNNN 8038 MMMM [LLLL 8039]

DIV N M [:L] Divide Divide N by M, saving the result in memory address L. Division by zero results in a 0.

803A NNNN 803B MMMM [LLLL 803C]

MOD N M [:L] Modulo Divide N by M, saving the remainder of result in memory address L. Modulo by zero results in a 0.

803D NNNN 803E MMMM [LLLL 803F]

INC N [:M] Increment Add 1 to N, saving the result in memory address M

8040 NNNN [MMMM 8041]

DEC N [:M] Decrement Subtract 1 from N, saving the result in memory address M

8042 NNNN [MMMM 8043]

NEG N [:M] Negative Multiply N by -1 (i.e. 0xFFFF), saving the result in memory address M

8044 NNNN [MMMM 8045]

ADR N [:M] Address Use bitwise-or with N and 0x8000 (i.e. make a litteral into an pointer), saving the result in memory address M

8046 NNNN [MMMM 8046]

PSH N Push Push the value N onto stack A

8047 NNNN 8048 0001

POP [:N] Pop Pop a value off of stack A and save it in memory address N

804A 0001 [NNNN 8049]

PSA N Push Address Use bitwise-or with N and 0x8000 (i.e. make a litteral into an pointer), and push the result onto stack B (the call-stack)

804B NNNN 804C 0001

POA [:N] Pop Address Pop a value off of stack B (the call-stack), and the it in memory address N

804E 0001 [NNNN 804D]

RND :N Random Get a random number and save it in memory address N

NNNN 804F

GET :N [:M] Get Copy the value pointed to by the value in memory address N and copy it into memory address M

8050 NNNN [MMMM 8051]

LBL :N Label Save the address of the next command in memory address N

NNNN 8000

CAL N Call Jump execution to memory address N, pushing the memory address of the next command onto stack B (the call-stack)

8031 0008 8032 8000 804B 8033 804C 0001 8046 NNNN 8000 8046

RET None Return Pop a pointer off stack B (the call-stack) and jump exectuation to it.

804E 0001 8000 804D

HLT None Halt Set all writable RAM to 0, stopping execution.

807F 0001

Postprocessor

A postprocessor instruction begins with a . character on its own line.
All postprocessor instructions and targets are ignored by the assembler.

Command Arguments Description Technical
.lbl name Will create a label which can be jumped to by the JMP command. Will replace all instances of &name with the address of the next instruction in memory

Example Programs

Fill

Fills the memory with 0x0F0F

#uses only draft 1
SET  0x0200  0x0F0F
ADR  0x0108
MOV  0x01FF *0x0046
INC *0x0001  0x0001
QJP  0x01FF

Fibonacci

Calculates the Fibonacci sequence

#uses only draft 2, which added more instructions
#initial state
MOV 0x200 1
MOV 0x201 1
#locations of the most recent numbers
ADR 0x200 0x1FE
ADR 0x201 0x1FF
#location of the next number
STA 0x202
#start the loop
LBL 0x1FB
  #add the two numbers together
  GET 0x1FE 0x1FC
  GET 0x1FF 0x1FD
  ADD *0x1FC *0x1FD
  #write the sum to the referenced address
  STV *0x33
  #increment the pointers
  INC *0x1FE 0x1FE
  INC *0x1FF 0x1FF
  #the address of DFA
  INC *0x1 0x1
  #jump to the start of the loop
QJP 0x1FB

Factorial

Calculates the factorials for the numbers 1 through 8

#uses draft 3, which added pre and post processor
JMP &start_program

.var results[8]

.var n
.var tot
.lbl fact
  #init factorial
  MOV :tot 1
  
  #start the body of the function
  .lbl fact_body
  
  #check if n is at or below 1
  .var fact_reached_1
  LOE :n 1 :fact_reached_1
  
  #if it is, exit the function
  .var fact_jump_loc
  TNA :fact_reached_1 &fact_ret &fact_mult 
:fact_jump_loc
  QJP :fact_jump_loc
  
  #otherwise, tot=tot*(n--)
  .lbl fact_mult
  MUL :n :tot :tot
  DEC :n :n
  
  #recursion!
  CAL &fact_body

  #the exit
  .lbl fact_ret
  RET  
  
.lbl start_program
#for i=1
.var i
MOV :i 1
.var for_loop
LBL :for_loop
  #i<=8
  .var end_of_array
  LOE :i 8 :end_of_array
  .var for_jump
  TNA :end_of_array &continue_for &exit_for :for_jump
  QJP :for_jump
  
  .lbl continue_for
  #get i factorial into tot
  MOV :n :i
  CAL &fact
  
  #put it into results
  .var addr
  ADD :results :i :addr
  DEC :addr :addr
  ADR :addr :addr
  SET :addr :tot
  
  #i++
  INC :i :i
QJP :for_loop
.lbl exit_for

.lbl exit_program
JMP &exit_program

The Future

I am considering creating another similar processor specification, the IOTA-C1. If I decide to go with it, the C1 would improve upon many of the C0's shortcomings.

  • The C0's GET and SET commands require a memory look-up, which cannot be reasonably done from the C-RAM of a physical processor. Therefore, those commands would have to be replaced or removed entirely. I don't know what to replace them with though.
  • The C0 has no interactive IO. The C1 would add a few bytes of C-RAM for the purpose of communicating with external devices.
  • The HLT command was put in before the LBL command was added. It doesn't provide any reasonable purpose now, and should be removed for the C1.
  • The C0 is very limited on memory. The C1 could (though this is more questionable) provide a way to bank-swap sections of RAM. It is possible that the literals section could be used for this purpose, but I'm not so sure of the idea of losing access to literals in order to save more data.