flat assembler
Message board for the users of flat assembler.
Index
> Projects and Ideas > AttoWPU - experimental "avant-garde" processor and |
Author |
|
Frooxius 02 May 2011, 23:26
Hello, I would like to show a project I'm working on for some time already, hopefully get some people interested and get some feedback. It's basically interesting (hopefully ^_^' ) "toy" for programmers, maybe something similar to the esoteric programming languages, like the brain*coughcough*youknowwhat.
Official website Download whole package Includes: - Documentation in PDF - Assembler ("compiler") for the AttoASM programming language, Windows, Linux, CLI - Simulator (or emulator) of the AttoWPU processor, Windows, Linux, GUI (Qt) - Logical scheme of the processor, PDF - Example sourcecodes in the AttoASM - Game Pong written in the AttoASM Changelog: 0.8.01 -Moved emulation to its own thread, better timing code. This makes the emulation frequency more precise and it should run faster, especially on multicore processors, because one core can emulate the AttoWPU, while the other one handles the GUI drawing -Maximum/unlimited emulation speed now works: simply drag the slider all the way to the right or just click the Max button and it will emulate the AttoWPU at the fastest speed your computer can handle -LED diodes and switches are now graphical, instead of using radios and checkboxes (but they work the same), so they should look better -Keyboard capture is now global for the whole application, no matter what element has keyboard focus -Fixed crashing when "Cancel" was clicked on the Load AttoASM source dialog -Small update to the specification, about how is the speaker controlled -Czech version of the specification is available now 0.8.02 -Linux binaries are available -Updated attoassembler code in the emulator to prevent crashes during assembling sources It's an experimental processor from the WPU (Weird Processing Unit) series, which is an attempt of untraditional and interesting approach to machine code processing and programming: it includes programming language AttoASM (attoassembler) and CustASM (custom assembler) and associated assemblers ("compilers") and simulator, which allows you to try created programs, I also plan providing VHDL description in the future. (yeah I know, GUI isn't polished at all now) What is WPU? You probably know at least what CPU and GPU are: processing units with specific purpose and philosophy: CPU (central processing unit) is universal processor, that is capable of executing any type of a program (well, maybe not literaly), but unlike specialized units, he can't do many of them fast enough, so in case of graphic operations, GPU comes in: it's specifically designed to perform graphical operations quickly, but can't do much else (although that's somewhat changing with unified shaders and such, but that's besides the point). Point is, each of these has its philosophy and purpose, something that makes them typical, so what makes WPU typical? WPU stands for Weird Processing Unit and such weird and crazy fun name already implies what WPU is: it's basically a processing unit, that's somehow weird - different from usual conventions. WPU can be any processor, that has at least part of it designed in a weird, unusual way, that makes programming for it and the way the machine code is executed challenging and/or interesting. It doesn't have to be practical in any way and often, it's not. It's more of a "hey, let's try this and see what happens" philosophy - purely experimental, whacky and weird for the sake of fun and curiosity. This means, that WPU is basically any processing unit, that somehow tries to go beyond boundaries of conventions of normal processors. WPUs try to be more or less original, new and interesting concepts, that stimulate programmer's minds with untraditional design and usually untraditional programming. They can be even considered to be form of an art to some extent, something like "avant-garde processors". What is the AttoWPU? While WPU is common name for any processing unit, attoWPU is a specific WPU and not just that: it's the first WPU created as the start of the series of WPUs, so it's sort of the gateway into the world of the weird processing units. It's certainly not the best of them, or most original of WPUs, but it's a start. AttoWPU is inspired by the microcode of normal processors and basically builds on the idea, that we can divide processors into two logical parts: execution unit (everything that does various calculations and operations) and control unit (part, that decodes instruction opcodes and tells execution unit what to do). AttoWPU has the control unit reduced to absurd minimum, requiring programmer to basically create a code, that will control the processor's function using three elementary instructions (attoinstructions), each one changing always only one bit. Regarding the exeuction units, AttoWPU has many of them and they do a lot of job by themselves, to make the programming simpler (if you want it even more hardcode, just wait for the zeptoWPU ). 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. Code: // Register Memory Allocation PADDLE0_Y { 0 } PADDLE1_Y { 1 } BALL_X { 2 } BALL_Y { 3 } SCORE0 { 4 } SCORE1 { 5 } BALL_XSPD { 6 } BALL_YSPD { 7 } TEMP { 8 } // For passing an argument to a symbol ARG0 { 0 } ARG1 { 0 } ARG2 { 0 } ARG3 { 0 } // Auxiliary EXE { CTRL+7(2) ! } WriteTEMP { ADDR [02, 8] CTRL [03, 7] EXE } // Output value from the Register memory at address given by ARG OutputRegister { ADDR [03, 8] DATA [ARG0] CTRL [01, 7] // write address EXE CTRL [0DH, 7] // output data EXE DATA 1(32) } // stop register output StopRegister { ADDR [03, 8] CTRL [0, 7] EXE } OUT2TEMP { DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output OUT WriteTEMP ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output } // signed add two values together and store the result back // ARG1 - first value // ARG2 - second value // ARG3 - result (where to write) SADDStoreBack { ARG0 {! ARG1 } OutputRegister WriteTemp ADDR [03, 8] CTRL [0, 7] EXE // stop the register output ARG0 {! ARG2 } OutputRegister // add them together ADDR [04, 8] CTRL [09, 7] EXE // store the result back ADDR [03, 8] CTRL [0, 7] EXE // stop the register output ADDR [03, 8] DATA [ARG3] CTRL [01, 7] EXE // address the proper location in the register memory DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE // output the out ADDR [03, 8] CTRL [0EH, 7] EXE // write the value ADDR [05, 8] CTRL [0, 7] EXE // stop the out output } // **** KEYBOARD READ **** ReadKey { DATA 1(32) // prepare for data exchange ADDR [0DH, 8] // address the input controller CTRL [08, 7] // read the key EXE } StopKey { ADDR [0DH, 8] // address the input controller CTRL [0, 7] // read the key EXE } ProcessAllKeys { ARG0 {! PADDLE0_Y } ARG1 {! 22 } // the W key ARG2 {! 02 } // subtraction ProcessKey ARG0 {! PADDLE0_Y } ARG1 {! 18 } // the S key ARG2 {! 01 } // addition ProcessKey // second paddle ARG0 {! PADDLE1_Y } ARG1 {! 4 } // the E key ARG2 {! 02 } // subtraction ProcessKey ARG0 {! PADDLE1_Y } ARG1 {! 3 } // the D key ARG2 {! 01 } // addition ProcessKey } /* ARGUMENTS: ARG0 = address at the register memory to process ARG1 = code of the key ARG2 = command code for the ALU to calculate new value */ ProcessKey { // Read the W key ReadKey WriteTEMP StopKey DATA [ARG1] // code of the W key // compare them using the ALU ADDR [04, 8] CTRL [28H, 7] // test for equality EXE // output result from the OUT ADDR [05, 8] CTRL [01, 7] EXE DATA 1(32) WriteTEMP // and store it in the temp register // multiply by two, so it moves by two pixels ADDR [04, 8] CTRL [01, 7] EXE EXE WriteTEMP ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output // load the value from the Register memory // address is prepared in the ARG0 OutputRegister // calculate new value ADDR [04, 8] CTRL [ARG2, 7] EXE ADDR [03, 8] CTRL [0, 7] EXE // stop register memory outputting // ---- limit value to min 0, max 127 ---- // copy it from the OUT to the TEMP DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE WriteTemp ADDR [05, 8] CTRL [0, 7] EXE // maximum DATA [128-18] ADDR [04, 8] CTRL [26H, 7] EXE // copy it from the OUT to the TEMP DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE WriteTemp ADDR [05, 8] CTRL [0, 7] EXE // minimum DATA [0] ADDR [04, 8] CTRL [24H, 7] EXE // new position is calculated, now store the value back DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE // output calculated value ADDR [03, 8] // register memory CTRL [0EH, 7] EXE // modified value is now written back // cleanup ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output } // DRAWING // draws the ball at current position - it's calculated automatically DrawBall { // ball is 6x6 px // get the Y position first and calculate proper address for the LCD ARG0 {! BALL_Y } OutputRegister // write it to the temp ADDR [02, 8] CTRL [03, 7] EXE // stop register output ADDR [03, 8] CTRL [0, 7] EXE // multiply by 128 DATA [128] ADDR [04, 8] CTRL [03, 7] EXE // output the OUT ADDR [05, 8] CTRL [01, 7] EXE DATA 1(32) // write it to the temp WriteTEMP // stop the OUT output ADDR [05, 8] CTRL [0, 7] EXE // add the paddle X position to the address ARG0 {! BALL_X } OutputRegister ADDR [04, 8] CTRL [01, 7] EXE // add the BALL_X to the address // OUT now contains the address, where drawing of the ball should start // stop register output ADDR [03, 8] CTRL [0, 7] EXE // output the OUT ADDR [05, 8] CTRL [01, 7] EXE // write the address to the LCD ADDR [0CH, 8] CTRL [01, 7] EXE // write the new address // write it to the temp too (DrawRowNext requires it) WriteTEMP // stop the out output ADDR [05, 8] CTRL [0, 7] EXE ARG0 {! 00FF0000H } // draw 6 rows DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext } // draws paddle at the current position - it needs to be set before this symbol is used DrawPaddle { // paddle is 6x18 px DATA 1(32) // store the starting value in the TEMP first ADDR [0CH, 8] CTRL [06, 7] EXE WriteTemp // start writing pixels ADDR [0CH, 8] CTRL [0, 7] EXE // stop the data output first ARG0 {! 00FFFF00H } // hahaha I know DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext DrawRowNext } // draw a row of pixels and move to the next one // color is stored in ARG0 DrawRowNext { DATA+8 [ARG0, 24] // write 6 pixels ADDR [0CH, 8] CTRL [03, 7] CTRL+7(12) ! // move to the next row DATA [128] ADDR [04, 8] CTRL [01, 7] EXE // add 128 to the value DATA 1(32) ADDR [05, 8] EXE // output it WriteTemp ADDR [0CH, 8] CTRL [01, 7] EXE // write the new address ADDR [05, 8] CTRL [0, 7] EXE // stop the output from the OUT } // write LCD paddle start position // ARG0 - register address containing the position // ARG1 - number to add to the start address (used to determine side) LCDPaddleStart { // output the start position from the register memory OutputRegister // write it to the temp ADDR [02, 8] CTRL [03, 7] EXE // stop register output ADDR [03, 8] CTRL [0, 7] EXE // multiply by 128 DATA [128] ADDR [04, 8] CTRL [03, 7] EXE // output the OUT ADDR [05, 8] CTRL [01, 7] EXE DATA 1(32) // write it to the temp WriteTEMP // stop the OUT output ADDR [05, 8] CTRL [0, 7] EXE // now add the value in ARG1 (horizontal shift) DATA [ARG1] ADDR [04, 8] CTRL [01, 7] EXE // output the OUT ADDR [05, 8] CTRL [01, 7] EXE DATA 1(32) // write the address to the LCD ADDR [0CH, 8] CTRL [01, 7] EXE } UpdateBall { // increment/decrement // add BALL_XSPD to the BALL_X ARG1 {! BALL_X } ARG2 {! BALL_XSPD } ARG3 {! ARG1 } SADDStoreBack // add BALL_YSPD to the BALL_Y ARG1 {! BALL_Y } ARG2 {! BALL_YSPD } ARG3 {! ARG1 } SADDStoreBack /* ********************** VERTICAL COLLISION ********************** */ DATA [0] WriteTEMP // temp contains minimal value ARG0 {! BALL_Y } OutputRegister // now compare them ADDR [04, 8] CTRL [25H, 7] EXE // if value in TEMP is larger than BALL_Y, then one will be outputed to the OUT ADDR [03, 8] CTRL [0, 7] EXE // stop register output CTRL [01, 7] DATA [TEMP] EXE // address the cell for temporary data DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output the out ADDR [03, 8] CTRL [0EH, 7] EXE // write the value ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output DATA [128-6] WriteTEMP ARG0 {! BALL_Y } OutputRegister // now compare them ADDR [04, 8] CTRL [27H, 7] EXE // if value in TEMP is smaller than BALL_X, then one will be outputed to the OUT ADDR [03, 8] CTRL [0, 7] EXE // stop register output // copy OUT to the TEMP DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE // output the OUT WriteTEMP ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output // output the first value on the bus ARG0 {! TEMP } OutputRegister // now OR them, so 1 is outputted if at one of them is 1, otherwise zero ADDR [04, 8] CTRL [18H, 7] EXE ADDR [03, 8] CTRL [0, 7] EXE // stop the register output // now multiply by -1, so -1 is outputted, when position overflows, zero otherwise DATA [-1] WriteTEMP DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output the OUT ADDR [04, 8] CTRL [0BH, 7] EXE // signed multiply WriteTEMP ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output DATA [1] ADDR [04, 8] CTRL [29H, 7] EXE // copy 1 to the OUT only if TEMP is zero (so OUT now contains either -1 or 1) // write back to the TEMP DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE // output the OUT WriteTEMP ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output // multiply it with the BALL_YSPD ARG0 {! BALL_YSPD } OutputRegister ADDR [04, 8] CTRL [0BH, 7] EXE // multiply them // store the result back ADDR [03, 8] CTRL [0, 7] EXE // stop the register output CTRL [01, 7] DATA [BALL_YSPD] EXE // address the cell with BALL_YSPD, because the new value will be written there DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE // output the OUT, contaning the new value ADDR [03, 8] CTRL [0EH, 7] EXE // write the value ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output // left paddle detection ARG1 {! PADDLE0_Y } ARG2 {! DATA [6] ADDR [04, 8] CTRL [27H, 7] EXE } ARG3 {! 1 } PaddleBounce // right paddle detection ARG1 {! PADDLE1_Y } ARG2 {! DATA [128-6-6] ADDR [04, 8] CTRL [25H, 7] EXE } ARG3 {! -1 } PaddleBounce DetectOutside } // detect if the ball left the area DetectOutside { // detect left outside ARG0 {! BALL_X } OutputRegister WriteTEMP StopRegister DATA [0] ADDR [04, 8] CTRL [27H, 7] EXE // if ball left on the left, then OUT is 1 OUT2TEMP // conditional jump DATA [LEFTLOSE%] ADDR [04, 8] CTRL [2AH, 7] EXE // if OUT is 1 then OUT will contain address of the LEFTLOSE DATA [LEFTNORMAL%] ADDR [04, 8] CTRL [29H, 7] EXE // if OUT is 0 then OUT will contain address of the LEFTNORMAL // output out DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output OUT ADDR [00, 8] CTRL [01, 7] EXE // write the new address LEFTLOSE%: CTRL+7 0 // to be safe ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output ResetBall LeftLoseCode AJMP [END%, 15] AJMP+15(2) ! LEFTNORMAL%: CTRL+7 0 // to be safe ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output // detect right outside ARG0 {! BALL_X } OutputRegister WriteTEMP StopRegister DATA [128-6] ADDR [04, 8] CTRL [25H, 7] EXE // if ball left on the right, then OUT is 1 OUT2TEMP // conditional jump DATA [RIGHTLOSE%] ADDR [04, 8] CTRL [2AH, 7] EXE // if OUT is 1 then OUT will contain address of the RIGHTLOSE DATA [END%] ADDR [04, 8] CTRL [29H, 7] EXE // if OUT is 0 then OUT will contain address of the END // output out DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output OUT ADDR [00, 8] CTRL [01, 7] EXE // write the new address RIGHTLOSE%: CTRL+7 0 // to be safe ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output ResetBall RightLoseCode END%: CTRL+7 0 // to be safe ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output } LeftLoseCode { // increment right score ARG0 {! SCORE1 } OutputRegister WriteTEMP StopRegister DATA [1] ADDR [04, 8] CTRL [01, 7] EXE // add one DATA [SCORE1] ADDR [03, 8] CTRL [01, 7] EXE // write the address ADDR [05, 8] DATA 1(32) CTRL [01, 7] EXE // output OUT ADDR [03, 8] CTRL [0EH, 7] EXE // write data ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output UpdateText } RightLoseCode { // increment right score ARG0 {! SCORE0 } OutputRegister WriteTEMP StopRegister DATA [1] ADDR [04, 8] CTRL [01, 7] EXE // add one DATA [SCORE0] ADDR [03, 8] CTRL [01, 7] EXE // write the address ADDR [05, 8] DATA 1(32) CTRL [01, 7] EXE // output OUT ADDR [03, 8] CTRL [0EH, 7] EXE // write data ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output UpdateText } UpdateText { ADDR [0BH, 8] CTRL [09, 7] EXE // address the text display and reset it first ARG0 {! strInfo} CopyStr ARG0 {! strScore0 } CopyStr ARG0 {! SCORE0 } TwoDigitsFromReg ARG0 {! endLine } CopyStr ARG0 {! strScore1 } CopyStr ARG0 {! SCORE1 } TwoDigitsFromReg ARG0 {! endLine } CopyStr ARG0 {! strInfo2 } CopyStr } // write two digits to the text display from the register memory at address in ARG0 TwoDigitsFromReg { // first digit DATA [10] WriteTEMP OutputRegister ADDR [04, 8] CTRL [05, 7] EXE // divide it by 10 StopRegister OUT2TEMP ADDR [04, 8] DATA [30H] CTRL [01, 7] EXE // add the value of '0' to it to produce a digit character ADDR [05, 8] DATA 1(32) CTRL [01, 7] EXE // output out ADDR [0BH, 8] CTRL [03, 7] EXE // write the character ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output // second digit DATA [10] WriteTEMP OutputRegister ADDR [04, 8] CTRL [06, 7] EXE // module it by 10 StopRegister OUT2TEMP ADDR [04, 8] DATA [30H] CTRL [01, 7] EXE // add the value of '0' to it to produce a digit character ADDR [05, 8] DATA 1(32) CTRL [01, 7] EXE // output out ADDR [0BH, 8] CTRL [03, 7] EXE // write the character ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output } // copy zero terminated string to the display // ARG0 - start address in the attocode memory CopyStr { ADDR [01, 8] DATA [ARG0] CTRL [01, 7] EXE // address start of the string LOOP%: DATA 0(24)1(8) ADDR [01, 8] CTRL [03, 7] EXE // output character // determine if it's a zero - then end the loop WriteTEMP ADDR [01, 8] CTRL [0, 7] EXE // stop output DATA 1(24) ADDR [04, 8] DATA [END%] CTRL [29H, 7] EXE // copy the END address if TEMP is zero (zero terminated string) DATA [CONTINUE%] CTRL [2AH, 7] EXE // copy when TEMP is non-zero (contains character) // write the address DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output the OUT ADDR [0, 8] CTRL [01, 7] EXE // write new address CONTINUE%: CTRL+7 0 ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output // copy the character to the text memory ADDR [02, 8] CTRL [04, 7] EXE // output value from the TEMP (the character) ADDR [0BH, 8] CTRL [03, 7] EXE // write the character and move to the next one ADDR [02, 8] CTRL [0, 7] EXE // stop the TEMP output ADDR [01, 8] CTRL [07, 7] EXE // move to the next character AJMP [LOOP%, 15] AJMP+15(2) ! // maintain the cycle END%: CTRL+7 0 ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output } ResetBall { ADDR [03, 8] CTRL [01, 7] DATA [BALL_X] EXE DATA [64] CTRL [0EH, 7] EXE ARG0 {! BALL_Y } OutputRegister WriteTEMP StopRegister ADDR [03, 8] CTRL [01, 7] DATA [BALL_XSPD] EXE // address BALL_XSPD ADDR [02, 8] CTRL [04, 7] EXE // output TEMP ADDR [03, 8] DATA 0(31)1 CTRL [0EH, 7] EXE // write the value ADDR [02, 8] CTRL [0, 7] EXE // stop TEMP output ADDR [03, 8] CTRL [01, 7] DATA [BALL_YSPD] EXE // address BALL_YSPD ADDR [02, 8] CTRL [04, 7] EXE // output TEMP ADDR [03, 8] DATA 0(30)10 CTRL [0EH, 7] EXE // write data ADDR [02, 8] CTRL [0, 7] EXE // stop TEMP output ADDR [03, 8] CTRL [01, 7] DATA [BALL_Y] EXE // address BALL_Y ADDR [02, 8] CTRL [04, 7] EXE // output TEMP ADDR [03, 8] DATA 1(32) CTRL [0EH, 7] EXE ADDR [02, 8] CTRL [0, 7] EXE // stop TEMP output // now alter the BALL_XSPD and BALL_YSPD ARG0 {! BALL_XSPD } OutputRegister WriteTEMP StopRegister // copy either 1 or -1 ADDR [04, 8] DATA [1] CTRL [29H, 7] EXE ADDR [04, 8] DATA [-1] CTRL [2AH, 7] EXE DATA [BALL_XSPD] ADDR [03, 8] CTRL [01, 7] EXE // address register ADDR [05, 8] DATA 1(32) CTRL [1, 7] EXE // output out ADDR [03, 8] CTRL [0EH, 7] EXE // write the new value ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output ARG0 {! BALL_YSPD } OutputRegister WriteTEMP StopRegister // copy either 1 or -1 ADDR [04, 8] DATA [1] CTRL [29H, 7] EXE ADDR [04, 8] DATA [-1] CTRL [2AH, 7] EXE DATA [BALL_YSPD] ADDR [03, 8] CTRL [01, 7] EXE // address register ADDR [05, 8] DATA 1(32) CTRL [1, 7] EXE // output out ADDR [03, 8] CTRL [0EH, 7] EXE // write the new value ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output } // handle boucing from either paddle // ARG1 - which paddle // ARG2 - X axis detect code (only set DATA and do ALU stuff, TEMP contains ball X) // ARG3 - new direction PaddleBounce { // first, calculate if it's in the range of the paddle (below and above paddle's size) ARG0 {! ARG1 } OutputRegister WriteTEMP StopRegister DATA [-5] ADDR [04, 8] CTRL [09H, 7] EXE // subtract 5 from the paddle Y (so it can bounce from the edge) OUT2TEMP // TEMP now contains the upper position, now check if it's above ball position ARG0 {! BALL_Y } OutputRegister ADDR [04, 8] CTRL [27H, 7] EXE // check if the BALL_Y is below PADDLE_Y StopRegister // store it in TEMP location in the register memory ADDR [03, 8] DATA [TEMP] CTRL [01, 7] EXE // write the address DATA 1(32) ADDR [05, 8] CTRL [01, 7] EXE // output OUT ADDR [03, 8] CTRL [0EH, 7] EXE // the result is now stored ADDR [05, 8] CTRL [0, 7] EXE // stop OUT output // BOTTOM OF THE PADDLE ARG0 {! ARG1 } OutputRegister WriteTEMP StopRegister DATA [18] ADDR [04, 8] CTRL [09H, 7] EXE // add 18 to the value (paddle is 18 pixels tall) OUT2TEMP // TEMP now contains the bottrom possition, now check if it's below ball position ARG0 {! BALL_Y } OutputRegister ADDR [04, 8] CTRL [25H, 7] EXE StopRegister OUT2TEMP // now AND both these together - they both must be true ARG0 {! TEMP } OutputRegister ADDR [04, 8] CTRL [17H, 7] EXE // Logical AND StopRegister // store the result in TEMP location once again, because it will be needed soon ADDR [03, 8] DATA [TEMP] CTRL [01, 7] EXE // write the address ADDR [05, 8] CTRL [1, 7] EXE // output out DATA 1(32) ADDR [03, 8] CTRL [0EH, 7] EXE // write the value ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output // now detect, if the ball is touching the paddle on the X axis ARG0 {! BALL_X } OutputRegister WriteTemp StopRegister ARG2 // detection is handled by an external code OUT2TEMP // now AND it with the value in the TEMP, to produce final value, determining whether or not to bounce ARG0 {! TEMP } OutputRegister ADDR [04, 8] CTRL [17H, 7] EXE // AND StopRegister OUT2TEMP // now calculate new BALL_XSPD based on the calculated conditional value DATA [ARG3] ADDR [04, 8] CTRL [2AH, 7] EXE // if TEMP is nonzero, copy value from DATA to the OUT ARG0 {! BALL_XSPD } OutputRegister ADDR [04, 8] CTRL [29H, 7] EXE // copy current speed if TEMP is zero (no collision - maintain regular speed) StopRegister // write the calculated speed to the BALL_XSPD ADDR [03, 8] CTRL [1, 7] DATA [BALL_XSPD] EXE // address the propel cell DATA 1(32) ADDR [05, 8] CTRL [1, 7] EXE // output the OUT ADDR [03, 8] CTRL [0EH, 7] EXE // write the value ADDR [05, 8] CTRL [0, 7] EXE // stop the OUT output } /* ************************************ PROGRAM START ************************************ */ // INITIALIZE EVERYTHING 0 0(64) // enable double buffering ADDR [0CH, 8] CTRL [0BH, 7] EXE ADDR [03, 8] CTRL [01, 7] DATA [PADDLE0_Y] EXE DATA [64-9] CTRL [0EH, 7] EXE ADDR [03, 8] CTRL [01, 7] DATA [PADDLE1_Y] EXE DATA [64-9] CTRL [0EH, 7] EXE ADDR [03, 8] CTRL [01, 7] DATA [SCORE0] EXE DATA [0] CTRL [0EH, 7] EXE ADDR [03, 8] CTRL [01, 7] DATA [SCORE1] EXE DATA [0] CTRL [0EH, 7] EXE ResetBall UpdateText LOOP: // cleanup after jump CTRL+7 0 ADDR [0, 8] CTRL [0, 7] EXE // game logic UpdateBall ProcessAllKeys ARG0 {! PADDLE0_Y } ARG1 {! 0 } LCDPaddleStart DrawPaddle ARG0 {! PADDLE1_Y } ARG1 {! 128-6 } LCDPaddleStart DrawPaddle DrawBall // switch buffer ADDR [0CH, 8] CTRL [0CH, 7] EXE CTRL [09, 7] EXE // long jump DATA [LOOP] ADDR [0, 8] CTRL [01, 7] EXE strInfo: " attoPong 1.0 " $00 strInfo2: "Programmed by Tomas \"Frooxius\" Mariancik" $00 strScore0: " Player 0 score: " $00 strScore1: " Player 1 score: " $00 endLine: " " $00 Last edited by Frooxius on 11 May 2011, 15:02; edited 3 times in total |
|||
02 May 2011, 23:26 |
|
Dex4u 03 May 2011, 19:24
Great work, i will read more about it.
|
|||
03 May 2011, 19:24 |
|
MHajduk 03 May 2011, 19:28
That's a huge and perfectly documented project, I'm impressed. What programming language did you use to code this application?
|
|||
03 May 2011, 19:28 |
|
neville 04 May 2011, 02:44
Yes, this is truly excellent Frooxius. Very well done!
_________________ FAMOS - the first memory operating system |
|||
04 May 2011, 02:44 |
|
Frooxius 04 May 2011, 21:14
Wow, thanks So far, I used C++ (+ Qt SDK for GUI, but the emulation code is modular, it's not dependent anyhow on the GUI and I can include it to any other code, even console app), but I'll probably rewrite the emulation core into assembly, so it's faster (well, there will be more optimizations, than just rewriting it), but only after I'm sure that the full version works correctly, so if something won't work right when optimizing, I'll know it's because of the optimizing, instead of not being sure whether it's some flaw in the design, or incorrect optimization.
Madis731: yeah, it has integrated some controllers for interfacing with some devices for input and output, these controllers are part of the CPU (well WPU ), but of course, the devices themselves are not (like the LCD display for example). Anyway, I updated to new version 0.8.01, what's new? (download in original post) Changelog: 0.8.01 -Moved emulation to its own thread, better timing code. This makes the emulation frequency more precise and it should run faster, especially on multicore processors, because one core can emulate the AttoWPU, while the other one handles the GUI drawing -Maximum/unlimited emulation speed now works: simply drag the slider all the way to the right or just click the Max button and it will emulate the AttoWPU at the fastest speed your computer can handle -LED diodes and switches are now graphical, instead of using radios and checkboxes (but they work the same), so they should look better -Keyboard capture is now global for the whole application, no matter what element has keyboard focus -Fixed crashing when "Cancel" was clicked on the Load AttoASM source dialog -Small update to the specification, about how is the speaker controlled -Czech version of the specification is available now |
|||
04 May 2011, 21:14 |
|
Frooxius 11 May 2011, 14:59
Oh, wow, it got sticky Thanks
Anyway, update! Linux binaries are here , also minor update, which should remove some bugs. You can download them in the original link, you need Qt4 libraries in order to run the emulator under the Linux. Also, I made general WPU website available at wpu.solirax.org, it's going to be a gateway to specific WPU's. So far there's only AttoWPU, but you can already see hints about the forthcoming WPU's, if you look closely, there's even part of source code in the language for one of the forthcoming ones. Developer blog wrote: I finally made available also the Linux version of the attoassembler tool (the "compiler" for AttoASM) and AttoWPU emulator. They're simply tar.gzipped binary executables and similarly to Windows ones, they're still in development. Also, because there's myriad of Linux distributions available, there are two bad things: I provide no packages or installers (but if you want to create them for any distribution you like, I'll be grateful), you either have to run them from command line or do whatever else you need to run them and also, the appearance is still far from perfect. I tried it on Ubuntu and OpenSUSE and it looks slightly different on both of them so expect, that it might look weird on whatever distribution you use. I'll try to polish the GUI more in the future, but it's not a priority. |
|||
11 May 2011, 14:59 |
|
Frooxius 20 May 2011, 19:54
Hi, somebody recently (a few dozen minutes ago) attempted to write Hello World code for my processor. In case anybody here tried to do same thing as the first app... well I don't recommend it, because it's a little bit more difficult for a first app, I recommend trying to light up a LED or something like that. For illustration, I wrote the Hello World in my language myself. It's quite funny for an Hello World app
Hello World in AttoASM Code: /* Hello World in AttoASM by Frooxius, slightly optimized, 5/20/2011, www.attowpu.solirax.org */ EXE { CTRL+7(2) ! } // execute command ADDR+4 [01H, 4] // attocode memory CTRL+3 [01H, 4] // write new address DATA [TEXT] EXE DATA+24 1(8) // prepare for data exchange LOOP: // cleanup after jump CTRL+7 0 ADDR+4 [05H, 4] // out register CTRL+3 [00H, 4] // stop the output EXE // Write the character ADDR+4 [01H, 4] // attocode memory CTRL+3 [03H, 4] // output addressed data EXE ADDR+4 [0BH, 4] // address text display CTRL+3 [03H, 4] // write character and increment address EXE // Maintain the loop if end of string wasn't reached yet ADDR+4 [01H, 4] // address attocode memory CTRL+3 [07H, 4] // move to the next element EXE ADDR+4 [02H, 4] // address TEMP register CTRL+3 [03H, 4] // write value without mask from the databus EXE ADDR+4 [01H, 4] // attocode memory CTRL+3 [00H, 4] // stop data output EXE ADDR+4 [04H, 4] // address ALU CTRL [29H, 7] // ZeroSet DATA [ENDLOOP] EXE CTRL [2AH, 7] // NotZeroSet DATA [LOOP] EXE CTRL 000 // clear three MSB DATA+24 1(8) // prepare for data exchange ADDR+4 [05H, 4] // OUT register CTRL+3 [01H, 4] // output its contents EXE ADDR+4 [00H, 4] // aPC CTRL+3 [01H, 4] // write new address from the databus EXE ENDLOOP: // cleanup after jump CTRL+7 0 ADDR+4 [05H, 4] // out register CTRL+3 [00H, 4] // stop the output EXE // infinite loop to stop the program from executing following (nonexistent - gibberish) code AJMP [INFLOOP, 15] INFLOOP: AJMP+15(2) ! text: "Hello world" $00 |
|||
20 May 2011, 19:54 |
|
Enko 20 May 2011, 20:03
Congrats!!!
It´s a really big and very well documented project. Excelent work When I get some free time, I'll try to write somthing, but it seems like a very tricky thing |
|||
20 May 2011, 20:03 |
|
l_inc 26 Sep 2013, 16:39
I didn't have a detailed look into the presented utility, but it seems quite similar to a single-address CPU simulator we used years ago in the first year of my university study. We could write assembly programs as well as define our own assembly instructions in microcode by specifying signal lines to be activated at every specific cycle of instruction execution. Just found it here.
_________________ Faith is a superposition of knowledge and fallacy |
||||||||||
26 Sep 2013, 16:39 |
|
dstyl 06 Aug 2015, 10:20
Would like to try it but the page is down can someon please reup it
|
|||
06 Aug 2015, 10:20 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.