Synergy Computer v.1.0 (29-bit, 1.5hz)

  • Synergy
    31st Mar 2015 Member 15 Permalink

     

    Synergy Computer v.1.0 

     

    https://powdertoy.co.uk/Browse/View.html?ID=1761441

     

    ~1761441

     

    Specifications:

     

    • 29-bit architecture.
    • 31 instructions
    • Runs at 1.5hz on average
    • 255 RAM addresses (8 frame read/write)
    • 889 ROM addresses (8 frame read/write)
    • Fully functional piston/DRAY based display, originally designed by Sandwichlizard, and heavily modified by me.
    • 29-bit Binary > BCD converter
    • 29-bit BCD > Binary converter
    • 2 frame per bit adder subtractor. 
    • 10 registers

     

    Possible future changes/additions:

     

    • negative  handling
    • random number generator
    • improvements to IF statement (allow user defined args).
    • Storing program data in RAM instead of ROM. I want to create 2-dimensional RAM first.
    • INPUT CHAR/INT --> RAM (without using a register value to define RAM address)
    • WRITE CONSTANT --> REG
    • IF <= JUMP
    • IF >= JUMP
    • Expanding ROM. The Y address only uses 3 of the 5 alocated bits. I could expand the ROM from 889 addresses to 3937. 
    • Expanding to 15 (or possibly even 63) registers.
    • Possibly changing the ALU instructions so that REGA and REGB can both be defined in ARGA. Thus giving space to define a destination register in ARGB. Currently, all ALU operations are A ? B --> A.

     

    Instruction Architecture:

     

    Instructions are 29 bits in length. This is because FILT technology holds 30 wavelengths. The 30th bit (leftmost) is used to represent 0.

     

    The first 5 bits are control bits:

    [00000][...................][....................]

      

    The next 12 bits are ARGA:

    [........][000000000000][...................]

     

    The final 12 bits are ARGB:

    [........][...................][000000000000]

     

     

    Assembler:

     

    Drrs has kindly created an assembler for this computer. The assembler along with usage instructions can be found here: https://github.com/harddal/SYNASM

     

    Using the assembler:

     

    1. Transfer assembler contents into your Powder Toy .exe folder. 

    2. Create a file in this folder with the .scm extention. 

    3. Open file using a text editor (ie. notepad++)

    4. Write assembly code. (syntax specifications found in above link) 

    5. Open the assembler (SYNASM.exe)

    6. type the filename (*.scm)

    7. If the file assembles successfully, a *.sc file of the same name will be created in the Powder Toy .exe folder. This file will contain all the assembled binary information for all of the instructions.

     

    Example program: 

     

    DCO "@cTHIS PROGRAM WILL GENERATE THE FIBONACCInSEQUENCE...nn" ; ends at 14.
    DB 0x1, 0x0 ; puts 0 in RAM1
    DB 0x2, 0x1 ; puts 1 in RAM2
    LD 0x1, 0x1 ; loads RAM1 to register1
    LD 0x2, 0x2 ; loads RAM2 to register2
    ADD 0x1, 0x2 ; adds register 1 and register 2
    DIR 0x1, NUL ; displays the result from register 1
    DCO "@, " ;
    ADD 0x2, 0x1 ; adds register 2 and register 1
    DIR 0x2, NUL ; displays the result from register 2
    DCO "@, " ;
    JMP 0x7, 0x13 ; jumps back to the first addition

     

     

    LUA script for importing *.sc information into Synergy Computer:

     

    Urumasi has created some LUA script that will allow you to import the *.sc file into Synergy Computer's ROM. The script sends the first instruction of the program to the address 001110000001 (c7, r1), the second instruction to 001110000010 (c7, r2) and so on. The 128th line of the program will flow over onto 001100000001 (c6, r1), and so on. This computer does not shift columns automatically, so you will be required to use JMP commands on r127 of each collumn. (ie. from c7, r127: JMP 0x6, 0x1 ;)

     

    http://pastebin.com/4XVTqJ2j

     

    Using the LUA script: 

     

    1. Move .lua file to Powder Toy folder. Rename it synergy.lua. (or anything really)

    2. Open Synergy Computer, and type <dofile("synergy.lua")> into the LUA console

    3. Enter the name of the .sc program (without the .sc extention). 

     

     

    Instructions (as named by oldmud0):

     

    00001: DB

    • Write to RAM with constant.
    • ARGA = RAM address
    • ARGB = Constant value

     

    00010: SR

    • Store to RAM from REG
    • ARGA = RAM address
    • ARGB = REG address

     

    00011: LD

    • Load to REG from RAM
    • ARGA = RAM address
    • ARGB = REG address

     

    00100: MOV

    • Copy data from REG to REG
    • ARGA = REGA address (copied)
    • ARGB = REGB address (pasted)

     

    00101: ADD 

    • ADD REGA, REGB --> REGA
    • ARGA = REGA address
    • ARGB = REGB address

     

    00110: SUB

    • SUB REGA FROM REGB --> REGA
    • ARGA = REGA address
    • ARGB = REGB address

     

    00111: SUBC 

    • SUBTRACT COLOR REGB FROM REGA --> REGA
    • ARGA = REGA address
    • ARGB = REGB address

     

    01000: INC 

    • INCREMENT REGA --> REGA
    • ARGA = REGA address
    • ARGB = null

     

    01001: DEC

    • DECREMENT REGA --> REGA
    • ARGA = REGA address
    • ARGB = null

     

    01010: SHR

    • RIGHT SHIFT REGA --> REGA
    • ARGA = REGA address
    • ARGB = null

     

    01011: SHL 

    • LEFT SHIFT REGA --> REGA
    • ARGA = REGA address
    • ARGB = null

     

    01100: NOT 

    • NOT REGA --> REGA
    • ARGA = REGA address
    • ARGB = null

     

    01101: NAND

    • NAND REGA, REGB --> REGA
    • ARGA = REGA address
    • ARGB = REGB address

     

    01110XOR

    • XOR REGA, REGB --> REGA
    • ARGA = REGA address
    • ARGB = REGB address

     

    01111OR

    • OR REGA, REGB --> REGA
    • ARGA = REGA address
    • ARGB = REGB address

     

    10000AND

    • AND REGA, REGB --> REGA
    • ARGA = REGA address
    • ARGB = REGB address

     

    10001: DCO 

    • Output to display from ROM [CHAR]
    • ARGA = CHAR data. 2x6-bit addresses
    • ARGB = CHAR data. 2x6-bit addresses

    Charset addresses:

     

     

    10010: DCR 

    • Output to display from REGA [CHAR]
    • ARGA = REGA address
    • ARGB = null

     

    10011: DCM 

    • Output to display from RAMA [CHAR]
    • ARGA = RAMA address
    • ARGB = null

     

    10100: DCP 

    • Output to display from RAM(REGA) [CHAR]
    • Uses the value stored in REGA as a pointer for RAM. 
    • ARGA = REGA address
    • ARGB = null

     

    10101: LDP 

    • Load to register from RAM(REGA) --> REGB
    • Uses the value stored in REGA as a pointer for RAM. 
    • ARGA = REGA address
    • ARGB = REGB address

     

    10110: SP

    • Store to RAM(REGA) from REGB
    • Uses the value stored in REGA as a pointer for RAM. 
    • ARGA = REGA address
    • ARGB = REGB address

     

    10111: JNE

    • IF REG1 != REG2, JUMP
    • This instruction will always compare information in REG1 and REG2. I hope to improve this in the future to allow any registers to be compared.
    • ARGA = null
    • ARGB = ROM address. This address does not use the 2 most significant bits.

     

    Unused:  

    [00][...][.......]

     

    Specifies the collumn for ROM address. 1-7 This computer uses 127x7 ROM. Thus, two addresses required:

    [..][000][.......]

     

    Specifies the row for the ROM address. 1-127:

    [..][...][0000000]

     

    11000: JE

    • IF REG1 == REG2, JUMP
    • Same as above.

     

    11001: JMP

    • Unconditional JUMP. 
    • Same as above.

     

    11010: ICP

    • Store to RAM(REGA) from display input [CHAR]
    • Stores CHAR data entered by the user, to RAM. 
    • Uses the value stored in REGA as a pointer for RAM. 
    • ARGA: REGA address
    • ARGB: null

     

    11011: DIR

    • Output to display from REGA [INT]
    • Sends integer data to display.
    • ARGA: REGA address
    • ARGB: null

     

    11100: DIM

    • Output to display from RAMA [INT]
    • Sends integer data to display from RAM
    • ARGA: RAMA address
    • ARGB: null

     

    11101: DIP

    • Output to display from RAM(REGA) [INT]
    • Outputs integer data to the display from RAM(REGA).
    • Uses the value stored in REGA as a pointer for RAM. 
    • ARGA: REGA address
    • ARGB: null

     

    11110: IIP

    • Store to RAM(REGA) from user input [INT]
    • Allows the computer to interpret integer data entered by the user.
    • Uses the value stored in REGA as a pointer for RAM. 
    • ARGA: REGA address
    • ARGB: null

     

    111111: RST

    • RESET
    • Somewhat of a redundant instruction. May be removed in the future.
    • ARGA: null
    • ARGB: null

     

     

    Edited 24 times by Synergy. Last: 9th May 2015
  • oldmud0
    4th Apr 2015 Member 1 Permalink

    Well, I'd say those instructions are ill-named. Or rather, not named at all. ;)

    Here's my proposed named opcode list:

     

    00000: NOP

    00001: DB

    00010: SR

    00011: LD

    00100: MOV

    00101: ADD

    00110: SUB

    00111: SUBC

    01000: INC

    01001: DEC

    01010: RSH

    01011: LSH

    01100: NOT

    01101: NAND

    01110: XOR

    01111: OR

    10000: AND

    10001: DCO (display character rOm)

    10010: DCR (display character Register)

    10011: DCM (display character raM)

    10100: DCP (display character Pointer)

    10101: LDP

    10110: SP

    10111: JNE

    11000: JE

    11001: JMP

    11010: ICP (input character pointer)

    11011: DIR

    11100: DIM

    11101: DIP

    11110: IIP (input integer pointer)

    11111: RST

     

    ...in case you are making an assembler, either in or out of TPT.

     

    I am also wondering if you are ever going to add an INT (interrupt) opcode to alleviate the number of opcodes needed. You could also use this to communicate with peripherals like CRAY printers.

     

    I also have a hunch: could you do addition and multiplication with FILT?

    Edited 5 times by oldmud0. Last: 4th Apr 2015
  • drrs
    5th Apr 2015 Member 0 Permalink

    I have to say great work! I am currently getting some practice programming your computer.

     

    EDIT:

     

    I have made a simple adder that gets 2 numbers from the "keyboard", adds them, and displays the result. The problem is that it doesn't seem to add the numbers correctly. No matter what I input I always get 32 as the output. I used Oldmud0's naming convention for the pseudo-ASM code that I retyped in binary and converted to decimal to set the filt's ctype with the prop tool. Any help would be appreciated, note that I am a noob when it comes to this type of low level programming.

     

    DB 0x0, 0x0 ; Store value 0x0 to adress 0x0
    LD 0x0, EAX ; Move value 0x0 to register 0
    IIP EAX, NUL ; Get input and write to ram at 0x0
    DB 0x0, 0x1 ; Store value 0x1 to adress 0x0
    LD 0x0, EAX ; Move value 0x1 to register 1
    IIP EAX, NUL ; Get input and write to ram at 0x1
    LD 0x0, EAX ; Move contents of adress 0x0 to register 0
    LD 0x1, EBX ; Move contents of adress 0x1 to register 1
    ADD EAX, EBX ; Add the contents of registers 0 and 1 together
    DIR EAX, NUL ; Display contents of register 0

     

    Instructions converted to binary and decimal to set filt ctype:

     

    1000000000000000000000000 ; 16777216
    11000000000000000000000000 ; 50331648
    11110000000000000000000000000 ; 503316480
    1000000000000000000000001 ; 16777217
    11000000000000000000000000 ; 50331648
    11110000000000000000000000000 ; 503316480
    11000000000000000000000000 ; 50331648
    11000000000001000000000001 ; 50335745
    101000000000000000000000001 ; 83886081
    11011000000000000000000000000 ; 452984832

     

    EDIT:

    I have also gotten a compiler for the assembly code thrown together in c++. It takes in the assembly and spits out the binary instructions that can be loaded with the lua script that is posted in the comments on the save.

    Edited 13 times by drrs. Last: 5th Apr 2015
  • Synergy
    5th Apr 2015 Member 0 Permalink

    Wow I would be interested to see that :)

     

    As for addition. Hmm, If it's outputting 32 all the time, it could be that it's adding 31 and 1. 31 is the default FILT value if I remember correctly.

     

    I would do something like (excuse me for not using the syntax yet).

     

    write 10 to RAM1.

    load RAM1 -> REG1

    input int to RAM(REG1) (so it sends the value to RAM10)

    write 11 to RAM1

    load RAM1 -> REG1

    input int to RAM(REG1) (so it sends the second value to RAM11)

    RAM10 -> REG1

    RAM11 -> REG2

    ADD REG1, REG2

    OUTPUT REG1.

     

    Try this and let me know if you're still getting 32. I think the problem is that RAM addresses begin at 1 (stupid I know), and you thought they began at 0. Is that what was stopping it from working?

     

    @oldmud0 (View Post)

     

    Thanks for that! I've never created such a thing before, so I would have to learn how first. It looks like there's more capable people than myself like drrs looking into it. As for interupt, that would be interesting. I don't think there are any computers in PT that have an interupt yet. It's difficult to implement I think.

    Edited once by Synergy. Last: 5th Apr 2015
  • drrs
    5th Apr 2015 Member 0 Permalink

    I think I implemented what you said correctly but the addition is still off. It works but 2+3 comes out to 4 and 5 + 4 comes out to 7. It is adding the numbers but something is making the result come out smaller than it should be. Here is the code, I seperated the 29 bit groups for easy reading:

     

    00001 000000000001 000000001010
    00011 000000000001 000000000001
    11110 000000000001 000000000000
    00001 000000000001 000000001011
    00011 000000000001 000000000001
    11110 000000000001 000000000000
    00010 000000001010 000000000001
    00010 000000001011 000000000010
    00101 000000000001 000000000010
    11011 000000000001 000000000000

     

    Here is the source to my compiler and the download link. It uses the keywords Oldmud posted and recognizes EAX and EBX as the first two of the 10 registers. To use just give it the name of a file with the SYNASM code (thats what I am calling it) and it will generate a *.sc file with the binary instructions. Note that it isn't totally bug free but seems to work pretty well if the code is formatted correctly. It will probaly require the Visual Studio 2013 redistributable to run.

     

    Source: http://pastebin.com/nrH6RDX0

    EXE: https://drive.google.com/file/d/0B9aPKDgFnabZVTlXVkh6bHUwTXM/view?usp=sharing

     

    I can make a small guide of how to write the assembly code if you want.

    Edited 4 times by drrs. Last: 5th Apr 2015
  • Synergy
    5th Apr 2015 Member 0 Permalink

    00010 000000001010 000000000001
    00010 000000001011 000000000010

     

    these two instructions should be 00011. If you're loading to registers from RAM. I think that's what is wrong.

     

    Yes it would be very helpful if you showed me how it's formatted :p Particularly the DCO instruction.

     

    Hmm something is strange. I could be wrong, but I think that lua script is deleting or modifying something. For whatever reason, it sends the address to the registers without the 0 bit activated. Which is strange, since the code in my computer does this operation hundreds of times, and the 0 bit is always activated. 

     

    I think I found it. The real problem is that the lua script doesn't add the 0 value to the instructions. So we need to modify the lua script to always add the 30th bit. Once this is done, everything should work fine. The problem was, that without the 30th bit set to 1, the register address XOR demultiplexor was trying to XOR 1000000000000000000000000000001, when it was recieving 000000000000000000000000000001.

     

    In the meantime, I will just add a piece of FILT somewhere to manually add the bit back in.

     

     

    Edited 6 times by Synergy. Last: 5th Apr 2015
  • EE
    5th Apr 2015 Banned 1 Permalink
    This post is hidden because the user is banned
  • Factorial
    5th Apr 2015 Banned 0 Permalink
    This post is hidden because the user is banned
  • drrs
    5th Apr 2015 Member 0 Permalink

    Once I fixed those two commands it worked, thanks! As for the issue with the lua script, I never would have caught that.

     

    The compiler I wrote doesn't support the DCO command yet, I am working on being able to write the 4 letters you want to use in a string literal in the assembly. But all other commands should be functional. As for using them it is formatted like:

     

    [CMD] [ARGA], [ARGB]

     

    So writing 10 to RAM1 would be:

     

    DB 0x1, 0xA

     

    Numbers in the assembly are in hex to shorten it up. For commands without an ARGB you type NUL:

     

    DIR 0x1, NUL

     

    You can also use EAX and EBX to specify registers 1 and 2:

     

    ADD EAX, EBX

     

    It also supports code commenting with the semicolon:

     

    IIP EAX, NUL ;Get number from user input to register 1

     

    Thats pretty much it. As I said I am working on using string literals for the DCO command, when I get that done it would be used like this:

     

    DCO "DR", "RS" ;Write my forum name to the screen

     

    Here is the working code for the adder you have been helping me write in assembly:

     

    DB 0x1, 0xA
    LD 0x1, EAX
    IIP EAX, NUL
    DB 0x1, 0xB
    LD 0x1, EAX
    IIP EAX, NUL
    LD 0xA, EAX
    LD 0xB, EBX
    ADD EAX, EBX
    DIR EAX, NUL

     

    I also made a plugin for Notepad++ that will add syntax highlighting to the assembly code, here is the download if you want it: https://drive.google.com/file/d/0B9aPKDgFnabZSW1FT0I0eTlHQVU/view?usp=sharing

    It detects the *.smc file extension and my compiler will take that in and spit out a *.sc

    Edited 3 times by drrs. Last: 5th Apr 2015
  • Synergy
    5th Apr 2015 Member 0 Permalink

    Damn looks epic. 

     

    One other thing. The JUMP instructions jump to an address in ROM that is specified with two different numbers. Have you implemented this one? so for argb: 00 111 0000001 would jump to row 1, column 7. There are 127 rows and 7 columns.