Jump to content

Recommended Posts

Posted (edited)

Hello, I recently found this forums, when I was looking for places with computer science enthusiasts, so I can show my project (basically hobby) and hopefully get some feedback and discussion (I asked administrator if I can post this).

 

Basically it's new kind (sort of) of processing unit called WPU, which tries new unusual, unconventional and creative approach to processor design and programming for several reasons: to give programmer's some "toy" and interesting thing to play with, to encourage thinking about standard and conventions (and this particular processor also encourages program optimization) and thus allow better understanding of them by introducing something, that doesn't strictly follow these conventions and tries to do things in unusual way, even when it might not be directly useful and basically try to more or less merge art with technology. I have planned several such unusual processors and programming languages and the first one called AttoWPU is already in state, when it's working (virtually for now, although it's not completely finished yet) and can be presented. It's not the best one of what I have planned, but it's a start ^_^

 

banner80.png

 

Official WPU website (includes some hints about forthcoming WPU's :) )

 

Official AttoWPU website

 

Download

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

-No longer call the emulator simulator, which was kind of dumb >.<

 

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.

 

simscreen.png

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

 

Linux version:

emullinux.png

 

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

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

Edited by Frooxius
Posted

Not for AttoWPU (but I don't mind if somebody tries to do that if he wants to), but for some others yes. Also for the second WPU unit (WPU is general term like CPU, while AttoWPU is specific architecture, like x86/ARM/PPC/etc) I'm planning, compiling a code is going to be very interesting, because it will have unusual way of organization of the instructions (and also different program flow). I mean... writing the compiler will be very interesting, especially if you want it to optimize the generated code too. I look forward to exploring that :)

Posted

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

 

Anyway, has anyone tried writing some code or playing with this? Don't hesitate to post your code and thoughts, I'm curious :)

 

Hello World in AttoASM

/* 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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.