Frooxius Posted May 14, 2011 Posted May 14, 2011 (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 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. (yeah I know, GUI isn't polished at all now) Linux version: 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 ). 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 ) 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 May 14, 2011 by Frooxius
Cap'n Refsmmat Posted May 14, 2011 Posted May 14, 2011 Do you have plans for building higher-level languages on top of your WPU system?
Frooxius Posted May 14, 2011 Author Posted May 14, 2011 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
Frooxius Posted May 20, 2011 Author Posted May 20, 2011 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 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
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now