flat assembler
Message board for the users of flat assembler.

Index > Projects and Ideas > AttoWPU - experimental "avant-garde" processor and

Author
Thread Post new topic Reply to topic
Frooxius



Joined: 02 May 2011
Posts: 4
Frooxius 02 May 2011, 23:26
Hello, I would like to show a project I'm working on for some time already, hopefully get some people interested and get some feedback. It's basically interesting (hopefully ^_^' ) "toy" for programmers, maybe something similar to the esoteric programming languages, like the brain*coughcough*youknowwhat.

Image

Official website

Download whole package
Includes:
- Documentation in PDF
- Assembler ("compiler") for the AttoASM programming language, Windows, Linux, CLI
- Simulator (or emulator) of the AttoWPU processor, Windows, Linux, GUI (Qt)
- Logical scheme of the processor, PDF
- Example sourcecodes in the AttoASM
- Game Pong written in the AttoASM

Changelog:
0.8.01
-Moved emulation to its own thread, better timing code. This makes the emulation frequency more precise and it should run faster, especially on multicore processors, because one core can emulate the AttoWPU, while the other one handles the GUI drawing
-Maximum/unlimited emulation speed now works: simply drag the slider all the way to the right or just click the Max button and it will emulate the AttoWPU at the fastest speed your computer can handle
-LED diodes and switches are now graphical, instead of using radios and checkboxes (but they work the same), so they should look better
-Keyboard capture is now global for the whole application, no matter what element has keyboard focus
-Fixed crashing when "Cancel" was clicked on the Load AttoASM source dialog
-Small update to the specification, about how is the speaker controlled
-Czech version of the specification is available now

0.8.02
-Linux binaries are available
-Updated attoassembler code in the emulator to prevent crashes during assembling sources

It's an experimental processor from the WPU (Weird Processing Unit) series, which is an attempt of untraditional and interesting approach to machine code processing and programming: it includes programming language AttoASM (attoassembler) and CustASM (custom assembler) and associated assemblers ("compilers") and simulator, which allows you to try created programs, I also plan providing VHDL description in the future.

Image
(yeah I know, GUI isn't polished at all now)

What is WPU?

You probably know at least what CPU and GPU are: processing units with specific purpose and philosophy: CPU (central processing unit) is universal processor, that is capable of executing any type of a program (well, maybe not literaly), but unlike specialized units, he can't do many of them fast enough, so in case of graphic operations, GPU comes in: it's specifically designed to perform graphical operations quickly, but can't do much else (although that's somewhat changing with unified shaders and such, but that's besides the point). Point is, each of these has its philosophy and purpose, something that makes them typical, so what makes WPU typical?

WPU stands for Weird Processing Unit and such weird and crazy fun name already implies what WPU is: it's basically a processing unit, that's somehow weird - different from usual conventions. WPU can be any processor, that has at least part of it designed in a weird, unusual way, that makes programming for it and the way the machine code is executed challenging and/or interesting. It doesn't have to be practical in any way and often, it's not. It's more of a "hey, let's try this and see what happens" philosophy - purely experimental, whacky and weird for the sake of fun and curiosity.

This means, that WPU is basically any processing unit, that somehow tries to go beyond boundaries of conventions of normal processors. WPUs try to be more or less original, new and interesting concepts, that stimulate programmer's minds with untraditional design and usually untraditional programming. They can be even considered to be form of an art to some extent, something like "avant-garde processors".

What is the AttoWPU?

While WPU is common name for any processing unit, attoWPU is a specific WPU and not just that: it's the first WPU created as the start of the series of WPUs, so it's sort of the gateway into the world of the weird processing units. It's certainly not the best of them, or most original of WPUs, but it's a start.

AttoWPU is inspired by the microcode of normal processors and basically builds on the idea, that we can divide processors into two logical parts: execution unit (everything that does various calculations and operations) and control unit (part, that decodes instruction opcodes and tells execution unit what to do). AttoWPU has the control unit reduced to absurd minimum, requiring programmer to basically create a code, that will control the processor's function using three elementary instructions (attoinstructions), each one changing always only one bit. Regarding the exeuction units, AttoWPU has many of them and they do a lot of job by themselves, to make the programming simpler (if you want it even more hardcode, just wait for the zeptoWPU Razz ).

This basically allows you to either create conventional (or not) software using the attoasembly language used to control the parts of the processor, making it a form of extreme/hardcore programming, or to use the attoassembly to define a processor's function and let it process higher level instructions of your design. There's also another peculiar perk: because the attocode memory is read/write, it's theoretically possible to create self modifying processor.

There's also another task, related to AttoWPU programming: code optimization and compression. AttoWPU machine code provides a lot of space for program optimization (both making it smaller and run faster, these two are actually equal to some point) and compression (A LOT of redudancy), so you can test how good programmer you are in various challenges and forthcoming competitions.

In short, AttoWPU has the AttoCore, which is capable of processing only elementary instructions, called attoinstructions. AttoWPU has one 64 bit bus, which is divided into four logical buses: address, control, data and Quick aJump bus, each attoinstruction changes always one bit of this bus. There are various units (execution units) connected in parallel to these buses, so programmer must use the buses to instruct them what to do and allow them to exchange data using the data bus. The attoCore is only capable of changing one bit on one of the logical buses at each cycle, everything else must be handled by controlling the units. For better understanding, please look at the logical scheme, which can be found at the downloads section.

What is the AttoASM?

AttoASM is a programming language used to create an attocode - machine code that's processed by the attocore of the AttoWPU. It allows you create the attocode by writing individual attoinstructions, but it also provides ways of simplifying the programming and reducing repeating source code. The same thing can't be however said about produced machine code, so if you want to optimize the resulting code, source code will probably be more complex and harder to manage or even create, but it's extreme/hardcore programing, isn't it? Smile You'll need AttoASM "compiler" - attoassembler to convert the sourcecode to attocode (machine code).

What is the CustASM?

Because you can create attocode, which will basically define a processor - it will handle decoding instructions and executing appropriate actions, you can also create any instruction set you want (higher level instructions than the attoinstructions), but if you want to write your own programs, using your own instructions, you'll need an assembly tool, which will produce correct machine code from the sourcecode, which will use your own mnemonics.

For the sake of convenience, so you don't have to write your own tools or go and search for some, CustASM language and custassembler tool is provided. This assembly language basically allows you to easily define your own mnemonics, including the argument arrangement and corresponding machine code. Custassembler tool will then use these definitions when assembling your source code.

Currently, custassembler tool is not available yet.

How can I try it?

To give anyone possibility to try the AttoWPU and programming for it, simulator is provided, together with attoassembler tool (simulator has however built-in attoassembler, so you can load the source directly into it and it will convert it to machine code automatically). Of course, you need to read the documentation first and look at the included example source codes (more will appear with time and properly commented ones), tutorials explaining how to do various tasks more clearly will be also available soon.

Anyway, if you're interested in this project, keep watching this thread and optimally also the developer blog on the official website, as I'll inform you about any updates, including new versions of the tools and specification with new features and bugfixes and thus, I'll hopefully reach beta status soon. However, I'm now also focusing on another WPU, which is even more interesting (in my opinion) than this one, but I'm not ready to make it public yet, but when I will, you will know Smile

For now, I made only Windows versions of the tools available, but Linux binaries are coming soon too, as well as more tools, like the custassembler, attodisassembler, CLI simulator and package maker. The simulator is also quite slow for now, but it will get more optimized simulation core later, which will be able to simulate the AttoWPU at much higher speeds than now Smile

There are some few AttoASM source code examples in the file, but mostly they are just files I used to test the simulator. Most notable is the AttoPong, which is basically old classic game Pong written fully in AttoASM and it's fairly commented, so perhaps it will be a nice source of information, or at least proof, that it all works together nicely Wink

Well I guess that's enough for now, so don't forget to comment, experiment and hopefully subscribe to the RSS on the official website, or at least peek again sometime in the future, to look what's new Smile

Game Pong written in the AttoASM (by me obviously)
You can test it by downloading the package with the simulator. Also, this is an unoptimized version, it's basically first serious (relatively speaking Very Happy ) code ever created for the AttoWPU.
Code:
// Register Memory Allocation
PADDLE0_Y { 0 }
PADDLE1_Y { 1 }
BALL_X { 2 }
BALL_Y { 3 }
SCORE0 { 4 }
SCORE1 { 5 }
BALL_XSPD { 6 }
BALL_YSPD { 7 }
TEMP { 8 }

// For passing an argument to a symbol
ARG0 { 0 }
ARG1 { 0 }
ARG2 { 0 }
ARG3 { 0 }

// Auxiliary

EXE { CTRL+7(2) ! }
WriteTEMP
{
    ADDR [02, 8]
        CTRL [03, 7]
        EXE
}

// Output value from the Register memory at address given by ARG
OutputRegister
{
   ADDR [03, 8]
        DATA [ARG0]
 CTRL [01, 7]    // write address
    EXE
 CTRL [0DH, 7]   // output data
      EXE
 DATA 1(32)
}

// stop register output
StopRegister
{
  ADDR [03, 8]
  CTRL [0, 7]
  EXE
}

OUT2TEMP
{
   DATA 1(32)
   ADDR [05, 8] CTRL [01, 7] EXE // output OUT
   WriteTEMP
   ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
}

// signed add two values together and store the result back
// ARG1 - first value
// ARG2 - second value
// ARG3 - result (where to write)
SADDStoreBack
{
  
    ARG0 {! ARG1 }
    OutputRegister
      WriteTemp
   ADDR [03, 8] CTRL [0, 7] EXE // stop the register output
    ARG0 {! ARG2 }
    OutputRegister
      
    // add them together
        ADDR [04, 8]
        CTRL [09, 7]
        EXE
 
    // store the result back
    ADDR [03, 8] CTRL [0, 7] EXE // stop the register output
    ADDR [03, 8] DATA [ARG3] CTRL [01, 7] EXE // address the proper location in the register memory
     DATA 1(32)
  ADDR [05, 8] CTRL [1, 7] EXE // output the out
      ADDR [03, 8] CTRL [0EH, 7] EXE // write the value
   ADDR [05, 8] CTRL [0, 7] EXE // stop the out output     
}

// **** KEYBOARD READ ****

ReadKey
{
       DATA 1(32)      // prepare for data exchange
        ADDR [0DH, 8]   // address the input controller
     CTRL [08, 7]    // read the key
     EXE
}

StopKey
{
      ADDR [0DH, 8]   // address the input controller
     CTRL [0, 7]     // read the key
     EXE
}

ProcessAllKeys
{
       ARG0 {! PADDLE0_Y }
       ARG1 {! 22 }  // the W key
        ARG2 {! 02 }  // subtraction
      ProcessKey
  ARG0 {! PADDLE0_Y }
       ARG1 {! 18 }  // the S key
        ARG2 {! 01 }  // addition
 ProcessKey      
    
    // second paddle
    ARG0 {! PADDLE1_Y }
       ARG1 {! 4 }   // the E key
        ARG2 {! 02 }  // subtraction
      ProcessKey
  ARG0 {! PADDLE1_Y }
       ARG1 {! 3 }   // the D key
        ARG2 {! 01 }  // addition
 ProcessKey
}

/*
              ARGUMENTS:
              ARG0 = address at the register memory to process
            ARG1 = code of the key
              ARG2 = command code for the ALU to calculate new value
*/

ProcessKey
{
    // Read the W key
   ReadKey
     WriteTEMP
   StopKey
     
    DATA [ARG1] // code of the W key
    // compare them using the ALU
       ADDR [04, 8]
        CTRL [28H, 7] // test for equality
  EXE
 
    // output result from the OUT
       ADDR [05, 8]
        CTRL [01, 7]
        EXE
 DATA 1(32)
  WriteTEMP       // and store it in the temp register
        // multiply by two, so it moves by two pixels
       ADDR [04, 8]
        CTRL [01, 7]
        EXE EXE
     WriteTEMP
   
    ADDR [05, 8]
        CTRL [0, 7]
 EXE // stop OUT output
      
    
    // load the value from the Register memory
  
    // address is prepared in the ARG0
  OutputRegister
      
    // calculate new value
      ADDR [04, 8]
        CTRL [ARG2, 7]
      EXE
 
    ADDR [03, 8]
        CTRL [0, 7]
 EXE // stop register memory outputting
      
    // ---- limit value to min 0, max 127 ----
  // copy it from the OUT to the TEMP
 DATA 1(32)
  ADDR [05, 8]    
    CTRL [1, 7]
 EXE
 WriteTemp
   ADDR [05, 8]
        CTRL [0, 7]
 EXE
 
    // maximum
  DATA [128-18]
       ADDR [04, 8]
        CTRL [26H, 7]
       EXE
 
    // copy it from the OUT to the TEMP
 DATA 1(32)
  ADDR [05, 8]    
    CTRL [1, 7]
 EXE
 WriteTemp
   ADDR [05, 8]
        CTRL [0, 7]
 EXE     
    
    // minimum
  DATA [0]
    ADDR [04, 8]
        CTRL [24H, 7]
       EXE
 
    // new position is calculated, now store the value back
     DATA 1(32)
  ADDR [05, 8]
        CTRL [1, 7]
 EXE // output calculated value
      ADDR [03, 8] // register memory
     CTRL [0EH, 7]
       EXE // modified value is now written back
   
    // cleanup
  ADDR [05, 8]
        CTRL [0, 7]
 EXE // stop OUT output
}

// DRAWING

// draws the ball at current position - it's calculated automatically
DrawBall
{
      // ball is 6x6 px
   
    // get the Y position first and calculate proper address for the LCD
        ARG0 {! BALL_Y }
  OutputRegister
      // write it to the temp
     ADDR [02, 8]
        CTRL [03, 7]
        EXE

     // stop register output
     ADDR [03, 8]
        CTRL [0, 7]
 EXE

     // multiply by 128
  DATA [128]
  ADDR [04, 8]
        CTRL [03, 7]
        EXE

     // output the OUT
   ADDR [05, 8]
        CTRL [01, 7]
        EXE
 DATA 1(32)
  
    // write it to the temp
     WriteTEMP
   
    // stop the OUT output
      ADDR [05, 8]
        CTRL [0, 7]
 EXE
 
    // add the paddle X position to the address
 ARG0 {! BALL_X }
  OutputRegister
      
    ADDR [04, 8]
        CTRL [01, 7]
        EXE     // add the BALL_X to the address
    // OUT now contains the address, where drawing of the ball should start
     
    // stop register output
     ADDR [03, 8]
        CTRL [0, 7]
 EXE
 
    // output the OUT
   ADDR [05, 8]
        CTRL [01, 7]
        EXE
 
    // write the address to the LCD
     ADDR [0CH, 8]
       CTRL [01, 7]
        EXE             // write the new address
    
    // write it to the temp too (DrawRowNext requires it)
       WriteTEMP
   
    // stop the out output
      ADDR [05, 8]
        CTRL [0, 7]
 EXE
 
    ARG0 {! 00FF0000H }
       
    // draw 6 rows
      DrawRowNext DrawRowNext DrawRowNext
 DrawRowNext DrawRowNext DrawRowNext
}

// draws paddle at the current position - it needs to be set before this symbol is used
DrawPaddle
{
        // paddle is 6x18 px
        DATA 1(32)
  // store the starting value in the TEMP first
       ADDR [0CH, 8]
       CTRL [06, 7]
        EXE
 WriteTemp
   
    // start writing pixels
     ADDR [0CH, 8]
       CTRL [0, 7]
 EXE             // stop the data output first
       
    ARG0 {! 00FFFF00H }
       
        // hahaha I know
        DrawRowNext DrawRowNext DrawRowNext DrawRowNext
     DrawRowNext DrawRowNext DrawRowNext DrawRowNext
     DrawRowNext DrawRowNext DrawRowNext DrawRowNext
     DrawRowNext DrawRowNext DrawRowNext DrawRowNext
     DrawRowNext DrawRowNext 
}

// draw a row of pixels and move to the next one
// color is stored in ARG0
DrawRowNext
{
   DATA+8 [ARG0, 24]
   // write 6 pixels
   ADDR [0CH, 8]
       CTRL [03, 7]
        CTRL+7(12) !
        
    // move to the next row
     DATA [128]      
    ADDR [04, 8]
        CTRL [01, 7]
        EXE             // add 128 to the value
     
    DATA 1(32)
  ADDR [05, 8]
        EXE             // output it
        WriteTemp
   ADDR [0CH, 8]
       CTRL [01, 7]
        EXE             // write the new address
    ADDR [05, 8]
        CTRL [0, 7]
 EXE             // stop the output from the OUT
}

// write LCD paddle start position
// ARG0 - register address containing the position
// ARG1 - number to add to the start address (used to determine side)
LCDPaddleStart
{
      // output the start position from the register memory
       OutputRegister

  // write it to the temp
     ADDR [02, 8]
        CTRL [03, 7]
        EXE

     // stop register output
     ADDR [03, 8]
        CTRL [0, 7]
 EXE

     // multiply by 128
  DATA [128]
  ADDR [04, 8]
        CTRL [03, 7]
        EXE

     // output the OUT
   ADDR [05, 8]
        CTRL [01, 7]
        EXE
 DATA 1(32)
  
    // write it to the temp
     WriteTEMP
   
    // stop the OUT output
      ADDR [05, 8]
        CTRL [0, 7]
 EXE
 
    // now add the value in ARG1 (horizontal shift)
     DATA [ARG1]
 ADDR [04, 8]
        CTRL [01, 7]
        EXE
 
    // output the OUT
   ADDR [05, 8]
        CTRL [01, 7]
        EXE
 DATA 1(32)      

        // write the address to the LCD
     ADDR [0CH, 8]
       CTRL [01, 7]
        EXE

}

UpdateBall
{
       // increment/decrement
      // add BALL_XSPD to the BALL_X
      ARG1 {! BALL_X }
  ARG2 {! BALL_XSPD }
       ARG3 {! ARG1 }
    SADDStoreBack
       
    // add BALL_YSPD to the BALL_Y
      ARG1 {! BALL_Y }
  ARG2 {! BALL_YSPD }
       ARG3 {! ARG1 }
    SADDStoreBack
       
    /* **********************
                   VERTICAL COLLISION
     ********************** */
           
 DATA [0]
    WriteTEMP       // temp contains minimal value
      ARG0 {! BALL_Y }
  OutputRegister
      // now compare them 
        ADDR [04, 8]  
      CTRL [25H, 7]
       EXE             // if value in TEMP is larger than BALL_Y, then one will be outputed to the OUT
     
    ADDR [03, 8] CTRL [0, 7] EXE // stop register output
        CTRL [01, 7] DATA [TEMP] EXE    // address the cell for temporary data
      DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output the out
  ADDR [03, 8] CTRL [0EH, 7] EXE // write the value
   ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
 

        DATA [128-6]
        WriteTEMP
   ARG0 {! BALL_Y }
  OutputRegister
      // now compare them 
        ADDR [04, 8]
        CTRL [27H, 7]
       EXE             // if value in TEMP is smaller than BALL_X, then one will be outputed to the OUT
    
    ADDR [03, 8] CTRL [0, 7] EXE // stop register output
        
    // copy OUT to the TEMP
     DATA 1(32)
  ADDR [05, 8] CTRL [1, 7] EXE // output the OUT
      WriteTEMP
   ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
 
    
    // output the first value on the bus
        ARG0 {! TEMP }
    OutputRegister
      // now OR them, so 1 is outputted if at one of them is 1, otherwise zero
    ADDR [04, 8] CTRL [18H, 7] EXE
      ADDR [03, 8] CTRL [0, 7] EXE // stop the register output
    
    // now multiply by -1, so -1 is outputted, when position overflows, zero otherwise
  DATA [-1]
   WriteTEMP
   DATA 1(32)
  ADDR [05, 8] CTRL [01, 7] EXE // output the OUT
     ADDR [04, 8] CTRL [0BH, 7] EXE // signed multiply
   
    WriteTEMP
   ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
 
    DATA [1]
    ADDR [04, 8] CTRL [29H, 7] EXE // copy 1 to the OUT only if TEMP is zero (so OUT now contains either -1 or 1)
       
    // write back to the TEMP
   DATA 1(32)
  ADDR [05, 8] CTRL [1, 7] EXE // output the OUT
      WriteTEMP
   ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
 
    // multiply it with the BALL_YSPD
   ARG0 {! BALL_YSPD }
       OutputRegister
      ADDR [04, 8] CTRL [0BH, 7] EXE // multiply them

 // store the result back
    ADDR [03, 8] CTRL [0, 7] EXE // stop the register output
    CTRL [01, 7] DATA [BALL_YSPD] EXE // address the cell with BALL_YSPD, because the new value will be written there
   DATA 1(32)
  ADDR [05, 8] CTRL [1, 7] EXE // output the OUT, contaning the new value
     ADDR [03, 8] CTRL [0EH, 7] EXE // write the value
   ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output
     
            // left paddle detection
             
            ARG1 {! PADDLE0_Y }
               ARG2 {! 
                              DATA [6]
                            ADDR [04, 8]
                                CTRL [27H, 7]
                               EXE
                         }
              ARG3 {! 1 }
               PaddleBounce
                
            // right paddle detection
           
             ARG1 {! PADDLE1_Y }
               ARG2 {! 
                              DATA [128-6-6]
                              ADDR [04, 8]
                                CTRL [25H, 7]
                               EXE
                         }
              ARG3 {! -1 }
              PaddleBounce
                
            DetectOutside
}

// detect if the ball left the area
DetectOutside
{
       // detect left outside
      ARG0 {! BALL_X }
  OutputRegister
      WriteTEMP
   StopRegister
        DATA [0]
    ADDR [04, 8] CTRL [27H, 7] EXE  // if ball left on the left, then OUT is 1
  OUT2TEMP
    
    // conditional jump
 DATA [LEFTLOSE%]
    ADDR [04, 8] CTRL [2AH, 7] EXE // if OUT is 1 then OUT will contain address of the LEFTLOSE
 DATA [LEFTNORMAL%]
  ADDR [04, 8] CTRL [29H, 7] EXE // if OUT is 0 then OUT will contain address of the LEFTNORMAL
       
    // output out
       DATA 1(32)
  ADDR [05, 8] CTRL [01, 7] EXE // output OUT
 ADDR [00, 8] CTRL [01, 7] EXE // write the new address
              
    LEFTLOSE%:
      CTRL+7 0 // to be safe
      ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output
     ResetBall
   LeftLoseCode
        AJMP [END%, 15]
     AJMP+15(2) !
        
    LEFTNORMAL%:
    CTRL+7 0 // to be safe
      ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output
     
    // detect right outside
     ARG0 {! BALL_X }
  OutputRegister
      WriteTEMP
   StopRegister
        DATA [128-6]
        ADDR [04, 8] CTRL [25H, 7] EXE  // if ball left on the right, then OUT is 1
 OUT2TEMP
            
    // conditional jump
 DATA [RIGHTLOSE%]
   ADDR [04, 8] CTRL [2AH, 7] EXE // if OUT is 1 then OUT will contain address of the RIGHTLOSE
        DATA [END%]
 ADDR [04, 8] CTRL [29H, 7] EXE // if OUT is 0 then OUT will contain address of the END
      
    // output out
       DATA 1(32)
  ADDR [05, 8] CTRL [01, 7] EXE // output OUT
 ADDR [00, 8] CTRL [01, 7] EXE // write the new address
      
    RIGHTLOSE%:
     CTRL+7 0 // to be safe
      ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output
     ResetBall
   RightLoseCode
       
    END%:       
    CTRL+7 0 // to be safe
      ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output
}

LeftLoseCode
{
     // increment right score
    ARG0 {! SCORE1 }
  OutputRegister
      WriteTEMP
   StopRegister
        DATA [1] ADDR [04, 8] CTRL [01, 7] EXE // add one
   DATA [SCORE1] ADDR [03, 8] CTRL [01, 7] EXE // write the address
    ADDR [05, 8] DATA 1(32) CTRL [01, 7] EXE // output OUT
      ADDR [03, 8] CTRL [0EH, 7] EXE // write data
        ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output
     UpdateText
}

RightLoseCode
{
 // increment right score
    ARG0 {! SCORE0 }
  OutputRegister
      WriteTEMP
   StopRegister
        DATA [1] ADDR [04, 8] CTRL [01, 7] EXE // add one
   DATA [SCORE0] ADDR [03, 8] CTRL [01, 7] EXE // write the address
    ADDR [05, 8] DATA 1(32) CTRL [01, 7] EXE // output OUT
      ADDR [03, 8] CTRL [0EH, 7] EXE // write data
        ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output
     UpdateText
} 

UpdateText
{
   ADDR [0BH, 8] CTRL [09, 7] EXE // address the text display and reset it first
       ARG0 {! strInfo}
  CopyStr
     ARG0 {! strScore0 }
       CopyStr 
    ARG0 {! SCORE0 }
  TwoDigitsFromReg
    ARG0 {! endLine }
 CopyStr 
    ARG0 {! strScore1 }
       CopyStr 
    ARG0 {! SCORE1 }
  TwoDigitsFromReg
    ARG0 {! endLine }
 CopyStr
     ARG0 {! strInfo2 }
        CopyStr
}

// write two digits to the text display from the register memory at address in ARG0
TwoDigitsFromReg
{
  // first digit
      DATA [10]
   WriteTEMP
   OutputRegister
      ADDR [04, 8] CTRL [05, 7] EXE // divide it by 10
    StopRegister
        OUT2TEMP
    ADDR [04, 8] DATA [30H] CTRL [01, 7] EXE // add the value of '0' to it to produce a digit character
       ADDR [05, 8] DATA 1(32) CTRL [01, 7] EXE // output out
      ADDR [0BH, 8] CTRL [03, 7] EXE // write the character
       ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
 
    // second digit
     DATA [10]
   WriteTEMP
   OutputRegister
      ADDR [04, 8] CTRL [06, 7] EXE // module it by 10
    StopRegister
        OUT2TEMP
    ADDR [04, 8] DATA [30H] CTRL [01, 7] EXE // add the value of '0' to it to produce a digit character
       ADDR [05, 8] DATA 1(32) CTRL [01, 7] EXE // output out
      ADDR [0BH, 8] CTRL [03, 7] EXE // write the character
       ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
}

// copy zero terminated string to the display
// ARG0 - start address in the attocode memory
CopyStr
{
   ADDR [01, 8] DATA [ARG0] CTRL [01, 7] EXE // address start of the string
            
    LOOP%:
  DATA 0(24)1(8)
      ADDR [01, 8] CTRL [03, 7] EXE // output character
   // determine if it's a zero - then end the loop
    WriteTEMP
   ADDR [01, 8] CTRL [0, 7] EXE // stop output
 DATA 1(24)
  ADDR [04, 8]
        DATA [END%] CTRL [29H, 7] EXE // copy the END address if TEMP is zero (zero terminated string)
      DATA [CONTINUE%] CTRL [2AH, 7] EXE // copy when TEMP is non-zero (contains character)
       
    // write the address
        DATA 1(32)
  ADDR [05, 8] CTRL [01, 7] EXE // output the OUT
     ADDR [0, 8] CTRL [01, 7] EXE // write new address
   
    CONTINUE%:
      CTRL+7 0
    ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
 
    // copy the character to the text memory
    ADDR [02, 8] CTRL [04, 7] EXE   // output value from the TEMP (the character)
       ADDR [0BH, 8] CTRL [03, 7] EXE // write the character and move to the next one
      ADDR [02, 8] CTRL [0, 7] EXE // stop the TEMP output
        
    ADDR [01, 8] CTRL [07, 7] EXE // move to the next character
 
    AJMP [LOOP%, 15] AJMP+15(2) !   // maintain the cycle
               
    END%:       
    CTRL+7 0
    ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
}

ResetBall
{
    ADDR [03, 8]
        CTRL [01, 7] DATA [BALL_X] EXE DATA [64] CTRL [0EH, 7] EXE
  
    ARG0 {! BALL_Y }
  OutputRegister
      WriteTEMP
   StopRegister
        
    ADDR [03, 8] CTRL [01, 7] DATA [BALL_XSPD] EXE // address BALL_XSPD
 ADDR [02, 8] CTRL [04, 7] EXE // output TEMP
        ADDR [03, 8] DATA 0(31)1 CTRL [0EH, 7] EXE      // write the value
  ADDR [02, 8] CTRL [0, 7] EXE // stop TEMP output
    
    ADDR [03, 8] CTRL [01, 7] DATA [BALL_YSPD] EXE // address BALL_YSPD
 ADDR [02, 8] CTRL [04, 7] EXE // output TEMP
        ADDR [03, 8] DATA 0(30)10 CTRL [0EH, 7] EXE     // write data
       ADDR [02, 8] CTRL [0, 7] EXE // stop TEMP output
    
    ADDR [03, 8] CTRL [01, 7] DATA [BALL_Y] EXE  // address BALL_Y
      ADDR [02, 8] CTRL [04, 7] EXE // output TEMP
        ADDR [03, 8] DATA 1(32) CTRL [0EH, 7] EXE
   ADDR [02, 8] CTRL [0, 7] EXE // stop TEMP output        
    
    // now alter the BALL_XSPD and BALL_YSPD
    ARG0 {! BALL_XSPD }
       OutputRegister
      WriteTEMP
   StopRegister
        // copy either 1 or -1
      ADDR [04, 8] DATA [1] CTRL [29H, 7] EXE
     ADDR [04, 8] DATA [-1] CTRL [2AH, 7] EXE
    DATA [BALL_XSPD] ADDR [03, 8] CTRL [01, 7] EXE // address register
  ADDR [05, 8] DATA 1(32) CTRL [1, 7] EXE // output out
       ADDR [03, 8] CTRL [0EH, 7] EXE // write the new value
       ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
 
    ARG0 {! BALL_YSPD }
       OutputRegister
      WriteTEMP
   StopRegister
        // copy either 1 or -1
      ADDR [04, 8] DATA [1] CTRL [29H, 7] EXE
     ADDR [04, 8] DATA [-1] CTRL [2AH, 7] EXE
    DATA [BALL_YSPD] ADDR [03, 8] CTRL [01, 7] EXE // address register
  ADDR [05, 8] DATA 1(32) CTRL [1, 7] EXE // output out
       ADDR [03, 8] CTRL [0EH, 7] EXE // write the new value
       ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
}

// handle boucing from either paddle
// ARG1 - which paddle
// ARG2 - X axis detect code (only set DATA and do ALU stuff, TEMP contains ball X)
// ARG3 - new direction
PaddleBounce
{
     // first, calculate if it's in the range of the paddle (below and above paddle's size)
    ARG0 {! ARG1 }
    OutputRegister
      WriteTEMP
   StopRegister
        DATA [-5]
   ADDR [04, 8] CTRL [09H, 7] EXE // subtract 5 from the paddle Y (so it can bounce from the edge)
     OUT2TEMP
    // TEMP now contains the upper position, now check if it's above ball position
     ARG0 {! BALL_Y }                              
    OutputRegister
      ADDR [04, 8] CTRL [27H, 7] EXE // check if the BALL_Y is below PADDLE_Y
     StopRegister
        
    // store it in TEMP location in the register memory
 ADDR [03, 8] DATA [TEMP] CTRL [01, 7] EXE // write the address
      DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output OUT
      ADDR [03, 8] CTRL [0EH, 7] EXE  // the result is now stored
 ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output
     
    // BOTTOM OF THE PADDLE
     ARG0 {! ARG1 }
    OutputRegister
      WriteTEMP
   StopRegister
        DATA [18]
   ADDR [04, 8] CTRL [09H, 7] EXE // add 18 to the value (paddle is 18 pixels tall)
    OUT2TEMP
    // TEMP now contains the bottrom possition, now check if it's below ball position
  ARG0 {! BALL_Y }
  OutputRegister
      ADDR [04, 8] CTRL [25H, 7] EXE
      StopRegister
        OUT2TEMP
    
    // now AND both these together - they both must be true
     ARG0 {! TEMP }
    OutputRegister
      ADDR [04, 8] CTRL [17H, 7] EXE // Logical AND
       StopRegister
        
    // store the result in TEMP location once again, because it will be needed soon
     ADDR [03, 8] DATA [TEMP] CTRL [01, 7] EXE // write the address
      ADDR [05, 8] CTRL [1, 7] EXE // output out
  DATA 1(32)
  ADDR [03, 8] CTRL [0EH, 7] EXE // write the value
   ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output
 
    // now detect, if the ball is touching the paddle on the X axis
     ARG0 {! BALL_X }
  OutputRegister
      WriteTemp
   StopRegister
        ARG2 // detection is handled by an external code
    OUT2TEMP
    
    // now AND it with the value in the TEMP, to produce final value, determining whether or not to bounce
      ARG0 {! TEMP }
    OutputRegister
      ADDR [04, 8] CTRL [17H, 7] EXE  // AND
      StopRegister
        OUT2TEMP
    
    // now calculate new BALL_XSPD based on the calculated conditional value
    DATA [ARG3]
 ADDR [04, 8] CTRL [2AH, 7] EXE // if TEMP is nonzero, copy value from DATA to the OUT
       ARG0 {! BALL_XSPD }
       OutputRegister
      ADDR [04, 8] CTRL [29H, 7] EXE // copy current speed if TEMP is zero (no collision - maintain regular speed)
        StopRegister
        
    // write the calculated speed to the BALL_XSPD
      ADDR [03, 8] CTRL [1, 7] DATA [BALL_XSPD] EXE // address the propel cell
    DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE // output the OUT
   ADDR [03, 8] CTRL [0EH, 7] EXE // write the value
   ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output     
}

/*    ************************************
                                PROGRAM START
       ************************************ */

// INITIALIZE EVERYTHING

0 0(64)
      
// enable double buffering
ADDR [0CH, 8]
CTRL [0BH, 7]
EXE

ADDR [03, 8] CTRL [01, 7] DATA [PADDLE0_Y] EXE DATA [64-9] CTRL [0EH, 7] EXE
ADDR [03, 8] CTRL [01, 7] DATA [PADDLE1_Y] EXE DATA [64-9] CTRL [0EH, 7] EXE
ADDR [03, 8] CTRL [01, 7] DATA [SCORE0] EXE DATA [0] CTRL [0EH, 7] EXE
ADDR [03, 8] CTRL [01, 7] DATA [SCORE1] EXE DATA [0] CTRL [0EH, 7] EXE

ResetBall
UpdateText

LOOP:
// cleanup after jump
CTRL+7 0
ADDR [0, 8] CTRL [0, 7] EXE

// game logic
UpdateBall
ProcessAllKeys
ARG0 {! PADDLE0_Y }
ARG1 {! 0 }
LCDPaddleStart
DrawPaddle
ARG0 {! PADDLE1_Y }
ARG1 {! 128-6 }
LCDPaddleStart
DrawPaddle
DrawBall

// switch buffer
ADDR [0CH, 8]
CTRL [0CH, 7]
EXE
CTRL [09, 7]
EXE

// long jump
DATA [LOOP]
ADDR [0, 8] CTRL [01, 7] EXE

strInfo:
"              attoPong 1.0              " $00
strInfo2:
"Programmed by Tomas \"Frooxius\" Mariancik" $00
strScore0:
"           Player 0 score: " $00
strScore1:
"           Player 1 score: " $00
endLine:
"           " $00
    


Last edited by Frooxius on 11 May 2011, 15:02; edited 3 times in total
Post 02 May 2011, 23:26
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 03 May 2011, 08:01
Great effort! It may become popular in schools where they teach CPU-s through experimenting. It seems to be quite complete already and its not only CPU, but I can see interfacing with input/output too.

10 points Very Happy
Post 03 May 2011, 08:01
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
Dex4u



Joined: 08 Feb 2005
Posts: 1601
Location: web
Dex4u 03 May 2011, 19:24
Great work, i will read more about it.
Post 03 May 2011, 19:24
View user's profile Send private message Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 03 May 2011, 19:28
That's a huge and perfectly documented project, I'm impressed. Smile What programming language did you use to code this application?
Post 03 May 2011, 19:28
View user's profile Send private message Visit poster's website Reply with quote
neville



Joined: 13 Jul 2008
Posts: 507
Location: New Zealand
neville 04 May 2011, 02:44
Yes, this is truly excellent Frooxius. Very well done!

_________________
FAMOS - the first memory operating system
Post 04 May 2011, 02:44
View user's profile Send private message Visit poster's website Reply with quote
Frooxius



Joined: 02 May 2011
Posts: 4
Frooxius 04 May 2011, 21:14
Wow, thanks Smile So far, I used C++ (+ Qt SDK for GUI, but the emulation code is modular, it's not dependent anyhow on the GUI and I can include it to any other code, even console app), but I'll probably rewrite the emulation core into assembly, so it's faster (well, there will be more optimizations, than just rewriting it), but only after I'm sure that the full version works correctly, so if something won't work right when optimizing, I'll know it's because of the optimizing, instead of not being sure whether it's some flaw in the design, or incorrect optimization.

Madis731: yeah, it has integrated some controllers for interfacing with some devices for input and output, these controllers are part of the CPU (well WPU Very Happy ), but of course, the devices themselves are not (like the LCD display for example).

Anyway, I updated to new version 0.8.01, what's new? Smile (download in original post)

Changelog:
0.8.01
-Moved emulation to its own thread, better timing code. This makes the emulation frequency more precise and it should run faster, especially on multicore processors, because one core can emulate the AttoWPU, while the other one handles the GUI drawing
-Maximum/unlimited emulation speed now works: simply drag the slider all the way to the right or just click the Max button and it will emulate the AttoWPU at the fastest speed your computer can handle
-LED diodes and switches are now graphical, instead of using radios and checkboxes (but they work the same), so they should look better
-Keyboard capture is now global for the whole application, no matter what element has keyboard focus
-Fixed crashing when "Cancel" was clicked on the Load AttoASM source dialog
-Small update to the specification, about how is the speaker controlled
-Czech version of the specification is available now
Post 04 May 2011, 21:14
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
Frooxius



Joined: 02 May 2011
Posts: 4
Frooxius 11 May 2011, 14:59
Oh, wow, it got sticky Shocked Thanks
Anyway, update!
Linux binaries are here Very Happy , also minor update, which should remove some bugs. You can download them in the original link, you need Qt4 libraries in order to run the emulator under the Linux.

Also, I made general WPU website available at wpu.solirax.org, it's going to be a gateway to specific WPU's. So far there's only AttoWPU, but you can already see hints about the forthcoming WPU's, if you look closely, there's even part of source code in the language for one of the forthcoming ones. Smile

Developer blog wrote:
I finally made available also the Linux version of the attoassembler tool (the "compiler" for AttoASM) and AttoWPU emulator. They're simply tar.gzipped binary executables and similarly to Windows ones, they're still in development. Also, because there's myriad of Linux distributions available, there are two bad things: I provide no packages or installers (but if you want to create them for any distribution you like, I'll be grateful), you either have to run them from command line or do whatever else you need to run them and also, the appearance is still far from perfect. I tried it on Ubuntu and OpenSUSE and it looks slightly different on both of them so expect, that it might look weird on whatever distribution you use. I'll try to polish the GUI more in the future, but it's not a priority.

Also, you need Qt4 libaries in order to run the emulator, search for libqt4 or something like that. If you have Qt development tools installed, it should work fine too.

Also, I made a minor update to the emulator. First, I changes some strings, so it says emulator everywhere now, instead of the "simulator", which was kind of stupid and I updated the attoassembler code in the emulator, so it shouldn't produce nasty crashes during assembling certain perfectly fine files, so even if you're using the Windows version, make sure to grab the latest one.

Image
Post 11 May 2011, 14:59
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
Frooxius



Joined: 02 May 2011
Posts: 4
Frooxius 20 May 2011, 19:54
Hi, somebody recently (a few dozen minutes ago) attempted to write Hello World code for my processor. In case anybody here tried to do same thing as the first app... well I don't recommend it, because it's a little bit more difficult for a first app, I recommend trying to light up a LED or something like that. For illustration, I wrote the Hello World in my language myself. It's quite funny for an Hello World app Very Happy

Hello World in AttoASM

Code:
/* Hello World in AttoASM by Frooxius, slightly optimized, 5/20/2011, www.attowpu.solirax.org */

EXE { CTRL+7(2) ! }          // execute command

ADDR+4 [01H, 4]               // attocode memory
CTRL+3 [01H, 4]           // write new address
DATA [TEXT]
EXE

DATA+24 1(8)  // prepare for data exchange

LOOP:

// cleanup after jump
CTRL+7 0
ADDR+4 [05H, 4]               // out register
CTRL+3 [00H, 4]              // stop the output
EXE

// Write the character
ADDR+4 [01H, 4]              // attocode memory
CTRL+3 [03H, 4]           // output addressed data
EXE

ADDR+4 [0BH, 4]          // address text display
CTRL+3 [03H, 4]              // write character and increment address
EXE

// Maintain the loop if end of string wasn't reached yet

ADDR+4 [01H, 4]         // address attocode memory
CTRL+3 [07H, 4]           // move to the next element
EXE

ADDR+4 [02H, 4]               // address TEMP register
CTRL+3 [03H, 4]             // write value without mask from the databus
EXE

ADDR+4 [01H, 4]              // attocode memory
CTRL+3 [00H, 4]           // stop data output
EXE

ADDR+4 [04H, 4]               // address ALU
CTRL [29H, 7]         // ZeroSet
DATA [ENDLOOP]
EXE
CTRL [2AH, 7]            // NotZeroSet
DATA [LOOP]
EXE

CTRL 000     // clear three MSB

DATA+24 1(8)  // prepare for data exchange

ADDR+4 [05H, 4]             // OUT register
CTRL+3 [01H, 4]              // output its contents
EXE

ADDR+4 [00H, 4]    // aPC
CTRL+3 [01H, 4]       // write new address from the databus
EXE

ENDLOOP:

// cleanup after jump
CTRL+7 0
ADDR+4 [05H, 4]            // out register
CTRL+3 [00H, 4]              // stop the output
EXE

// infinite loop to stop the program from executing following (nonexistent - gibberish) code
AJMP [INFLOOP, 15]
INFLOOP:
AJMP+15(2) !

text:
"Hello world" $00    
Post 20 May 2011, 19:54
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger Reply with quote
Enko



Joined: 03 Apr 2007
Posts: 676
Location: Mar del Plata
Enko 20 May 2011, 20:03
Congrats!!!

It´s a really big and very well documented project. Excelent work

When I get some free time, I'll try to write somthing, but it seems like a very tricky thing Rolling Eyes
Post 20 May 2011, 20:03
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 26 Sep 2013, 16:39
I didn't have a detailed look into the presented utility, but it seems quite similar to a single-address CPU simulator we used years ago in the first year of my university study. We could write assembly programs as well as define our own assembly instructions in microcode by specifying signal lines to be activated at every specific cycle of instruction execution. Just found it here.


Description:
Filesize: 320.74 KB
Viewed: 24708 Time(s)

capture.png



_________________
Faith is a superposition of knowledge and fallacy
Post 26 Sep 2013, 16:39
View user's profile Send private message Reply with quote
dstyl



Joined: 23 Jul 2015
Posts: 67
dstyl 06 Aug 2015, 10:20
Would like to try it but the page is down can someon please reup it
Post 06 Aug 2015, 10:20
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.