8 Replies - 1330 Views - Last Post: 28 April 2011 - 05:48 PM

#1 Frooxius   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 28-April 11

AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 11:37 AM

Posted Image

Official website

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

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.

Posted Image

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 :P ).

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? :-) 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 :-)

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 :-)

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 ;-)

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 :-)

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 :D ) code ever created for the AttoWPU.
// 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 }
	
	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



Is This A Good Question/Topic? 0
  • +

Replies To: AttoWPU - "avant-garde" processor and programming language

#2 Amrykid   User is offline

  • 4+1=Moo
  • member icon

Reputation: 150
  • View blog
  • Posts: 1,589
  • Joined: 16-December 08

Re: AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 03:33 PM

I think I missed it somewhere but is the WPU a real physical object or is it like a Virtual Machine...
Was This Post Helpful? 0
  • +
  • -

#3 Frooxius   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 28-April 11

Re: AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 03:48 PM

Amrykid: well WPU is common term for any specific processor with the philosophy described above, AttoWPU is specific processor (WPU), but the main point is the architecture: how it processes the machine code and how do you program it and that's independent on whether it's emulated or physical. However, for now, you can only simulate (emulate) using the tool I provided, but later (after I tune the design), I'll also make available VHDL description of the physical version, so if you have field programmable gate array chip, you can also have physical version of it. But WPU and AttoWPU are rather architectures (well WPU is term for all of them, like CPU and GPU are common terms for various processors and graphic cards) and sets of ideas and ways to program it, that are not much dependent on the actual realization of the device.
Was This Post Helpful? 0
  • +
  • -

#4 Amrykid   User is offline

  • 4+1=Moo
  • member icon

Reputation: 150
  • View blog
  • Posts: 1,589
  • Joined: 16-December 08

Re: AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 03:54 PM

Okay, so at the moment, it is like a virtual machine (or.. processor) with its own instruction set, etc. Gotcha.

What programming language was the emulator programmed in?
Was This Post Helpful? 0
  • +
  • -

#5 Frooxius   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 28-April 11

Re: AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 04:38 PM

Yeah, virtual processor plus some accessories (the LCD display isn't part of the processor itself for example, but rather something you'll connect to it, but the controller stays the same, so it's not dependent (the programming) on what LCD display (some actual device you might buy) you connect.

Also, it sort of differs from the convention, so it's not just instruction set (well it has three elementary instructions, nothing more, as it's described above and in the documentation).

I made the emulation core modular, so I can just include the source in any project and emulate the processor independently - whether it's console app, GUI or part of something larger. The current version is made in C++ and it's highly unoptimized (it's basically "full", so it always simulates everything, even when it's not needed). That's because the project is still in alpha state, so I'm still adding new stuff to it (but it should already be reliable and work properly with what's implemented). I'll make optimized simulation cores later, maybe rewrite some parts into assembly (although that makes it less multiplatform, but it shouldn't be such an issue) and do various other optimizations, that will make it run much faster, but before I start messing with how the emulation works, removing and rewriting some parts, I want to be sure that it emulates it properly, so when something starts malfunctioning, I'll know that it's because of some bad optimization and not flaw in the design of the simulator itself (and related parts).

Also, it will be possible to select from multiple emulator cores, because the optimized ones might process several instructions in a single step or recompile parts of the AttoWPU machine code into something better suited for emulation, but that will make debugging impossible (well mostly stepping), so if programmer will want to debug the code he wrote for the AttoWPU, he'll select the full emulation core.
Was This Post Helpful? 0
  • +
  • -

#6 Amrykid   User is offline

  • 4+1=Moo
  • member icon

Reputation: 150
  • View blog
  • Posts: 1,589
  • Joined: 16-December 08

Re: AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 04:44 PM

Does WPU use any JIT-compilation of the instructions or it just interprets whats already there.

Does WPU support any kind of threading?

Are there any open specifications for the instructions if someone were to implement their own "compatible" processor?

This post has been edited by Amrykid: 28 April 2011 - 04:44 PM

Was This Post Helpful? 0
  • +
  • -

#7 Frooxius   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 28-April 11

Re: AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 05:00 PM

Well it's AttoWPU we're talking about, WPU is term, like CPU (general term) , while AttoWPU is more like x86, but that's just detail now.

Do you mean if the AttoWPU emulator uses some JIT, to translate the instructions into something better suited for emulation? Like I explained in previous post, it doesn't for now, but later it will, to increase the emulation speed. As the architecture itself, it simply processes the machine code as it is, in the intended format, it doesn't modify it anyhow. Of course, it must be assembled (it won't process the source code, well it will, but it will be just gibberish). In case of the physical device, you must of course load the assembled machine code in the memory, the GUI emulator provided in the package you can download in the first post has integrated "compiler" (well it's not technically a compiler, since compilers are rather for high level languages), so if you load the source file, it will assembly it, but then it will emulate the machine code.

As for threading, that's very tricky question, because the answer is yes and no. The basic core (attocore), which processes the elementary instructions and basically controls whole processor, doesn't support any threading or anything else, it just changes bits on the bus. But you can write a code, that will basically control the inner parts of the processor in a way, where the actual program you write with your own instruction set (you design the attocode, so it decodes and processes your own instructions) and it's up to you, what you implement in the attocode - how will the AttoWPU process your machine code. Whether it will run two or more separate threads at once (well, technically it won't, it will just switch between them quickly in the attocode, but you can create it, so it's seamless for the regular program).

Or did you mean, whether the emulator/simulator uses threading while emulating? For now it doesn't, now it runs all in one thread, I will later separate the emulation to its own thread (I wanted to do it before, but I didn't have time, I'll be graduating secondary school soon, so I don't have much time now).

You can download specification in the first post, along with some examples and the simulator and assembler tool for the AttoASM language, the PDF file (about 40 pages) explains instruction format and basically everything else that's needed. You can implement own processor however you want as long as it behaves like it's described in the specification.
Was This Post Helpful? 0
  • +
  • -

#8 Amrykid   User is offline

  • 4+1=Moo
  • member icon

Reputation: 150
  • View blog
  • Posts: 1,589
  • Joined: 16-December 08

Re: AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 05:27 PM

Firstly, congrats on graduating. I have 2 more years myself.

I meant CPU threading but you answered my next question too.

What inspired you to write such a cool um.. invention? (I do not know if that is the word for something this amazing.)

Where do you see this future processor? Desktop computers? Mobile devices?
Was This Post Helpful? 0
  • +
  • -

#9 Frooxius   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 28-April 11

Re: AttoWPU - "avant-garde" processor and programming language

Posted 28 April 2011 - 05:48 PM

Sorry if I didn't express myself correctly (I'm not native speaker), I mean, that I still have the graduation exams before me, I didn't graduate yet.

Well, there were several inspirations. I like creating rather new and original things, that are somehow interesting. I like the game development the most, but I got ideas for some experimental processors, so why not do them? :-) Another part of inspiration is surprisingly music, specifically avant-garde metal bands. They basically experiment with the music and genres, go beyond conventions and try new things, even when it might be weird.

Well that's basically what I did, I tried to do some things in the design of the WPUs differently, in some interesting way, that doesn't have to end up being practical (it can even be the exact opposite), but it satisfies my and hopefully other people's curiosity and gives them something to experiment with and stimulate their programmer brains with things they don't normally do.

And that's basically what's the purpose of this. Desktops, mobiles? Nothing like that :D This is more of a toy for programmers to play with and test their skills and like I said: satisfy curiosity and stimulate brains with something new and nontraditional, something that they are not used to and that will hopefully make them think more about the concepts used in the programming. This architecture is not even that complex, like x86 or ARM are (for example). It can be compared to esoteric programming languages, for example like the brain*ahem*.

But I would like to see others playing with it, trying to write some programs for it for fun, education, experimentation and such. But what I would like want to do in the future, are some competitions. AttoWPU provides a lot of space for code optimization (squeezing every byte and cycle) and compression (a lot of redundancy), so I might give some task, to create a program with specified function and others will try to implement it as best as they could and the smallest and the fastest programs will win. You can look at that source code example of the Pong game I provided. It's made quite quickly and it wastes a lot of space and performance, I'll show optimized version later, that will be significantly smaller and faster, yet the function will be the same, but of course, it will take more time to program it optimized, rather than unoptimized.

Anyway, like I said in the first post, WPUs are series and AttoWPU is just the first one of them, basically a starting point. I myself don't consider it very much interesting and original, like some of the other concepts I have. Now I'm working on another one (while still working on this), that really fascinates me, because it introduces new kinds of instructions and basically requires you to structure the program and algorithms differently, than you normally do in assembly languages, but I won't tell much about it for now, to not spoil things.

Also I couldn't help myself: Lelouch vi Britannia! ^^
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1