AttoASM
AttoASM is a language designed for the AttoWPU experimental processing unit, as part of the WPU (Weird Processing Unit) concept. AttoASM is the assembly language of the AttoWPU unit and thus corresponds to the basic operation of this architecture. Both AttoWPU and AttoASM use very minimalistic design and support only three elementary instructions that change individual bits on a bus. By a series of these elementary operations, various internal units can be controlled to perform various tasks.
WPU
AttoASM and AttoWPU are part of the WPU concept. WPU stands for Weird Processing Unit, which is basically series of various experimental processors (architectures) that try to be interesting, new, original, extraordinary, different or just plain weird. WPUs try to be original and playful and they usually go beyond the boundaries of convention - things we consider normal.
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, as some of the architectures are 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, however sometimes there springs something really useful from all this that can be actually used for some improvement.
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 execution units, AttoWPU has many of them and they do a lot of job by themselves, to make the programming simpler.
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 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 it's possible to test programming skills in various challenges and 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 the AttoWPU schematic is recommended.
Thanks the the bus design, the architecture is modular and can be easily modified - new units can be added and removed, while the AttoCore and base operation remains the same. The standard specification provides several units for integer and floating point arithmetic and input and output with easy interface, allowing to quickly get visual feedback in the simulator.
AttoASM
AttoASM is a programming language used to create an attocode - machine code that's processed by the attocore of the AttoWPU. It allows programmer 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, which can present a certain challenge to programmers.
Simplest Example
2 1 // sets third bit (address 2)
Hello World Example
Following code presents a Hello World application in AttoASM, that writes the "Hello World!" message on the 40x4 ASCII text display, that's part of the specification.
/* 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
MOV mem, mem Example
/* Implementation of MOV mem32, mem32 instruction in the AttoASM This code is not fully optimized for sake of readibility, it can be further optimized to execute faster and also be smaller Following code assumes, that programmer has already decoded addresses of both memory locations and stored them in the register memory unit on address 0x03 in registers he called TMP0 and TMP1 */ EXE { CTRL+7(2) ! } // execute the command - Symbol/Macro, equivalent to sequence of CTRL+7 1, CTRL+7 0 CTRL 0(8) // clear control bus from any previous codes codes ADDR 0(8) // clear the address as well DATA 0(32) // data as well ADDR+4 0011 // address register memory DATA+27 0001 // move address of the TMP1 register the register memory on the data bus CTRL+6 1 // prepare command code to control bus, which will tell currently addressed device - spec. data memory to read value on data bus and store it in its own addressation register CTRL+7 1 // by activating most significant bit on the control bus, tell addressed device to read the instruction code on the control bus and thus address TMP1 register CTRL+7 0 // don't forget to set it back to zero afterwards DATA 1(32) // set all wires of data bus to 1, so it won't interrupt data outputed by special memory CTRL+5 1 // (in combination with previous CTRL+6 1 forms code 11) prepare instruction code, which will tell special data memory to read value of addressed location and output it on the data bus CTRL+7 1 // activate control instruction (after this, value of TMP1 will be on the data bus) CTRL+7 0 // deactivate it again ADDR+4 0111 // address program/data memory CTRL+5 01 // prepare command code, which will tell program/data memory to read address from data bus and address appropriate cell (source location) EXE // macro for CTRL+7 1 CTRL+7 0, after this, source location is addressed in program/data memory CTRL+5 11 // prepare command code, which will tell program/data memory to ouput value at addressed cell to the data bus EXE // value of source address is now at data bus (however, still mixed with the address from TMP1) ADDR+4 0011 // address special data memory again CTRL+5 00 // erase previous control instruction, this forms zero instruction, which tells the special data memory to disconnect from data bus (high impedance mode) and thus stop disturbing the value on data bus from source location EXE ADDR+4 0010 // address standalone TEMP register CTRL+5 01 // prepare instruction code which will tell the TEMP register to store value on the data bus in itself EXE // TEMP now contains the source value ADDR+4 0011 // address register memory again DATA 0(30)10 // put address of TMP2 register in register memory on the data bus (TMP2 contains target location) CTRL+5 01 // prepare command code which will tell register memory to address location with address on the data bus EXE CTRL+5 1 // (in combination with previous command code 1 forms code 11) prepare command code, which will tell special data memory to read value of addressed location and output it on the data bus EXE ADDR 0111 // address program/data memory CTRL+5 0 // (clear this bit, changing 11 to 01) prepare instruction code, which will tell program/data memory to read address from data bus and address appropriate cell (target location) and by changing the instruction code, this will also stop it outputing value of source address on the data bus EXE // target location is now addressed ADDR 0010 // address standalone TEMP again CTRL+5 10 // prepare instructoin code, which will instruct standalone TEMP to output its value (which is source value) on the data bus EXE ADDR 0011 // address register memory CTRL+6 0 // erase control instruction, to stop special data memory from outputting value on the data bus EXE // data bus now contains only the source value from TEMP ADDR 0111 // address program/data memory again CTRL+4 100 // prepare instruction code, which will tell program/data memory to read value from data bus and store it at addressed location EXE // target location now contains value of source location, MOV operation is complete (some cleanup may follow as well as jump to start decoding another instruction from program/data memory)
Syntax Overview
AttoASM supports 4 elementary instructions, which can be written by following symbols:
0 fall 1 rise ! invert | halt (optional) - skip (pseudo instruction)
Each statement starts with a number from 0 to 63 which determines the address of the first bit, followed by at least one of the symbols representing the instructions. Each consecutive instruction applies to the following bit of the bus. It's also possible to convert an integer or single precision floating point number to a series of instructions using the square brackets statement.
For simplification, four symbols are predefined, each one holding starting bit of one of the four logical buses:
ADDR = 0 start of the address bus CTRL = 8 start of the control bus DATA = 16 start of the data bus AJMP = 48 start of the Quick aJump bus
Here are some examples of valid statements in AttoASM:
CTRL+2 0001 DATA 110-11001 // is same as: DATA 110 DATA+4 1101 ADDR+4 !01 DATA [15550] // write number 15550 to the data bus ADDR [0CH,8,0]
AttoASM also supports definition of symbols. Symbol basically contains any valid piece of AttoASM code, which is placed at every location, where the symbol is used, as is, with the exception of local symbols inside a symbol, which are made unique for every usage of the symbol by generating an unique name. Symbol can't be used prior its definition, with the exception of labels.
It's also possible to redefine symbol - new definition is valid from the point of redefinition. Redefined version is applied also to any subsequent usages of symbols, that contain usage of the redefined symbol and thus allow to pass arguments or whole pieces of code to the other symbols.
Labels are special form of symbols, when they're defined, they hold an integer number with the address of the instruction immediately following the symbol. They can be used like any other symbol.
Infinite loop example:
EXE { CTRL+7(2) ! } // symbol to execute the command ADDR 0(8) // address aPC CTRL 0(6)01 // prepare command code to write new address to the aPC DATA+11 [Somelabel, 20] //write the address of the label to the data bus Somelabel: EXE // execute the command and thus cause jump back to Somelabel
Trivia
The WPU concept was originally concieved by Frooxius, who is now most well known for Neos.
External resources
- Official AttoWPU documentation, examples, and binaries (from the Wayback Machine; retrieved on 15 August 2015)