AttoWPU - experimentální procesor a programovací jazyk – Offtopic – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

AttoWPU - experimentální procesor a programovací jazyk – Offtopic – Fórum – Programujte.comAttoWPU - experimentální procesor a programovací jazyk – Offtopic – Fórum – Programujte.com

 

Frooxius0
Duch
27. 4. 2011   #1
-
0
-

Dobrý den,
chtěl bych vám představit jeden projekt, na kterém nějakou dobu pracuji, nevěděl jsem do které sekce to dát (ty o programování jsou spíše poradny), tak jsem to nacpal sem :-)


http://attowpu.solirax.org - Oficiální web

http://data.solirax.org/attowpu/attoWPUalpha0.8.zip - Stáhnout
Obsahuje:
- Anglickou dokumentaci v PDF
- Překladač ("kompilátor") pro jazyk AttoASM, Windows, Linux, konzolová aplikace
- Simulátor (či emulátor) pro procesor AttoWPU, Windows, Linux, GUI (Qt)
- Logické schéma procesoru v PDF
- Ukázkové zdrojové kódy v jazyce AttoASM
- Hru Pong napsanou v jazyce AttoASM

Changelog
0.8.01
-kód starající se o emulaci AttoWPU nyní běží v samostatném vlákně - o něco rychlejší (zvláště u multijádrových procesorů), přesnější časování.
-maximální/nelimitovaná rychlost emulace nyní funguje, stačí kliknout na Max, či přetáhnout posuvník úplně doprava
-LED diody a přepínače jsou nyní grafické, namísto radio a checkboxů, takže vypadají lépe
-zachytávání kláves je nyní zcela globální pro celou aplikaci, nezáleží který prvek má keyboard focus
-opraveno padání při zavření dialogu pro načtení zdrojového souboru
-malá aktualizace ve specifikaci ve způsobu ovládání speakeru
-dostupná je česká verze dokumentace, počítejte ale s tím, že nebude aktualizována tak často, jako anglická

0.8.02
-K dispozici binárky pro Linux
-Aktualizován attoassembler kód v emulátoru, což řeší některé pády při překladu zdrojových kódů

Jedná se o experimentální procesor attoWPU ze série WPU (Weird Processing Unit), který se snaží o netradiční a zajímavý přístup ke zpracování strojového kódu a samotnému programování: součástí je i programovací jazyk AttoASM (attoassembler) a CustASM (custom assembler) a s tím související kompilátory, plus simulátor, ve kterém si můžete vytvořené programy vyzkoušet, v plánu je i VHDLko.



Co je to WPU?
Určitě znáte alespoň pojmy CPU a GPU: procesorové jednotky s určitým účelem: CPU (central processing unit) je univerzální procesor schopný zpracovat jakýkoliv typ programu (nebrat doslova), avšak na rozdíl od specializovaných jednotek řadu operací nezvládá dostatečně rychle, takže kupříkladu u grafických operací přijde na řadu GPU: tento procesor je navržen speciálně pro rychlé zpracování grafických operací, ale moc jiného neumí (ačkoli s unified shadery je to už na pováženou, ale to je mimo pointu). Důležité je, že každý z těchto typů procesorových jednotek má svoji vlastní filozofii a účel, tedy něco, co je činí typickými. Čím jsou tedy typické WPU?

WPU znamená Weird Processing Unit (podivná procesorová jednotka) a takové podivné, praštěné a legrační jméno už implikuje, co WPU je: jedná se v podstatě o procesorovou jednotku, která je nějakým způsobem podivná - jiná od běžných konvencí. WPU může být jakýkoliv procesor, který je alespoň z části navržený podivným, nevídaným způsobem, což činí programování pro tento procesor a způsob zpracování strojového kódu vyzývajícím a/nebo zajímavým. Nemusí mít žádný čistě praktický účel a většinou ani mít nebude. Jedná se spíše o způsob "hej, zkusme tohle a uvidíme co to udělá" - čistě experimentální, praštěný a podivný pro zábavu a zvědavost.

To znamená, že WPU je v podstatě jakýkoliv procesor, který se snaží jít za hranice konvencí běžných procesorů. WPU se snaží být více či méně originální a přicházet s novými a zajímavými koncepty, které pomohou stimulovat mysl programátorů netradičním designem a obvykle i netradičním programováním. Mohou být dokonce do jisté míry považovány za druh umění, něco jako "avant-garde procesory".

Co je to AttoWPU?
Zatímco WPU je obecný termín pro jakoukoliv procesorovou jednotku (splňující filozofii WPU), attoWPU je specifický WPU a nejenom to: jedná se o první WPU, vytvořený jako začátek série těchto experimentálních procesorů. Rozhodně se nejedná o nejlepší z nich (už plánuji nějaké mnohem lepší :-) ), ale je to začátek.

AttoWPU je inspirován mikrokódem normálních procesorů a v podstatě staví na myšlence, že můžeme procesory rozdělit na dvě logické části: výpočetní část (provádí všechny výpočty a operace) a řídící část (dekóduje instrukce a říká výpočetním částím co mají dělat). AttoWPU má řídící část zredukovanou na absurdní minimum a vyžaduje od programátora, aby v podstatě vytvořil kód, který bude řídit funkci procesoru použitím tří elementárních instrukcí (attoinstrukcí), každá z nich mění vždy pouze jediný bit. Co se týče výpočetních jednotek, těch má AttoWPU hodně a odvádějí poměrně dost práce za programátora, čímž je programování jednodušší (jestli to chcete ještě více hardcore, počkejte na zeptoWPU :P ).

To vám v podstatě umožňuje vytvořit konvenční (nebo taky ne) software použitím attoassembleru (programovací jazyk na ještě nižší úrovni než assembler), což je v podstatě forma extrémního/hardcore programování, ale také vám umožňuje pomocí attoassembleru definovat funkci procesoru a nechat jej zpracovávat program na vyšší úrovni s vašimi vlastními instrukcemi, jednoduše řečeno, v podstatě se jedná o procesor, jehož funkci a instrukční sadu si musíte sami naprogramovat. S tím souvisí taky zajímavá vlastnost: neboť je paměť attokódu zapisovatelná, je teoreticky možné vytvořit sebemodifikující procesor. :twisted:

Další činností spojenou s programováním AttoWPU je optimalizace kódu a komprese (kódu). Strojový kód AttoWPU nabízí obrovský prostor pro optimalizaci (menší a rychlejší kód, což jsou do jisté míry v podstatě stejné parametry) a kompresi (HODNĚ redudance), takže si můžete otestovat, jak dobří programátoři jste v různých vyzývavých úkolech a budoucích soutěžích.

Ve zkratce: AttoWPU má AttoJádro, které je schopné zpracovávat pouze elementární instrukce, nazvané attoinstrukce. AttoWPU má jednu 64 bitovou sběrnici, která je rozdělena na čtyři logické sběrnice: adresní, řídící, datovou a Quick aJump sběrnici. Každá attoinstrukce mění vždy pouze jediný bit této sběrnice. K těmto sběrnicím jsou paralelně připojeny různé jednotky (výpočetní jednotky), takže programátor musí využít těchto sběrnic k ovládání těchto jednotek a výměně dat mezi jednotkami. AttoJádro je pouze schopno měnit jeden bit na jedné z logických sběrnic v každém cyklu, vše ostatní (i (ne)podmíněné skoky) musí být provedeny použitím jednotek. Pro lepší pochopení doporučuji soubor Schematics.pdf v archivu, který je ke stažení níže.

Co to je AttoASM?
AttoASM je programovací jazyk sloužící k vytvoření attokódu - strojového kódu, který je zpracován attojádrem AttoWPU. Umožňuje vytvořit attokód (strojový kód) zapsáním jednotlivých attoinstrukcí, ale nabízí i způsoby, jak programování zjednodušit a odstranit opakující se zdrojový kód. To samé ale nejde říct o strojovém kódu, takže pokud budete chtít optimalizovat výsledný strojový kód, zdrojový kód bude zřejmě složitější, stejně jako jeho tvorba, ale přece jenom se jedná o extrémní/hardcore programování, ne? :-) Budete potřebovat "kompilátor" (attoassembler - tak se správně nazývá překladač) k převedení zdrojového kódu na attokód (strojový kód).

Co je to CustASM?
Protože lze vytvořit attokód, který bude v podstatě definovat procesor - bude dekódovat instrukce a provádět příslušné akce, můžete vytvořit prakticky libovolnou instrukční sadu (na vyšší úrovni než jsou attoinstrukce, nebo taky ne, klidně si napište attokód, který bude zpracovávat attokód :lol: ), budete potřebovat nástroj, který vytvoří příslušný strojový kód ze zdrojového kódu s vašimi vlastními mnemotechnickými symboly.

Pro pohodlí, abyste nemuseli sami psát svůj překladač, nebo nějaký hledat, je k dispozici i programovací jazyk CustASM a příslušný překladač (custassembler). Tento jazyk symbolických adres vám v podstatě umožňuje jednoduše nadefinovat své vlastní mnemotechnické zkratky, včetně uspořádání a počtu argumentů a příslušný strojový kód. Custassembler poté použije tyto definice při překladu strojového kódu.

Custassembler prozatím není k dispozici ke stažení, ale bude brzy.

Jak si to můžu vyzkoušet?
Aby si mohl kdokoliv vyzkoušet AttoWPU a programování pro něj, je k dispozici i grafický simulátor, spolu s překladačem (simulátor má však vestavěný překladač, takže stačí načíst zdrojový kód a on se postará o překlad). Samozřejmě byste si měli přečíst dokumentaci (bohužel zatím jen v angličtině, bude ale trochu ořezaná česká verze) a podívat se na ukázkové zdrojové kódy (brzy jich bude více a lépe komentovaných).

Doporučuji zejména Pong.att, což je v podstatě hra Pong napsaná čistě v AttoAssemebleru (AttoASM) a poměrně hojně komentovaná (ono to ani jinak nejde).

Jaký je stav projektu?
Projekt je momentálně ve fázi alfa, takže stále podléhá značnému vývoji, takže očekávávejte bugy, problémy a nedodělané funkce. Naštěstí je procesor, překladač i simulátor funkční do té míry, že si jej lze rozumně vyzkoušet a prezentovat jej :-)

Momentálně věnuji čas i dalšímu WPU ze série, o kterém však zatím nic neřeknu no a samozřejmě mě čeká maturita, takže času tolik není, přesto bych byl rád za nějakou odezvu, tak neváhejte, zkoušejte, experimentujte, programujte a komentujte :-) Jakmile budou nějaké novinky, tak vás upozorním, ideálně sledujte oficiální web http://attowpu.solirax.org



Ukázka zdrojového kódu - hra Pong v jazyce AttoASM:
Psal jsem to samozřejmě já, už jste někdy zkoušeli psát něco ve vlastním programovacím jazyce pro vlastní procesor? Je to zvláštní :D


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

// funny, 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

Nahlásit jako SPAM
IP: 217.196.214.–
crAzY^
~ Moderátor
+10
Grafoman
27. 4. 2011   #2
-
+1
-
Zajímavé

vypadá to hodně zajímavě... je za tím asi dost práce, že? Každopádně klobouk dolu...

Nahlásit jako SPAM
IP: 89.190.90.–
All you need is vision and time.
Frooxius0
Duch
11. 5. 2011   #3
-
0
-

crAzY^: díky, jo dost času to zabralo, nejvíce asi tvorba a návrh samotné specifikace, když je (téměř) hotová dokumentace, pak je programování docela rychlé :-)

Jinak bych chtěl upozornit na aktualizaci, vyšly dvě minoritní verze (viz changelog) a jsou k dispozici binárky pro Linux a dokumentace v češtině :-) Stahovat lze z originálního odkazu.

Také jsem spustil web věnovaný obecně WPU [url=http://wpu.solirax.org]wpu.solirax.org[/url], v podstatě je to rozcestník ke specifickým WPU. Zatím je tam pouze AttoWPU, ale už jsou tam náznaky k plánovaným WPUčkům a pokud se podíváte pozorně, uvidíte i malou část zdrojového kódu v jazyce pro jeden z připravovaných WPU. :)

Z vývojářského blogu:

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.

Also, you need Qt4 libaries in order to run the emulator, search for libqt4 or something like that. If you have Qt development tools installed, it should work fine too.

Also, I made a minor update to the emulator. First, I changes some strings, so it says emulator everywhere now, instead of the "simulator", which was kind of stupid and I updated the attoassembler code in the emulator, so it shouldn't produce nasty crashes during assembling certain perfectly fine files, so even if you're using the Windows version, make sure to grab the latest one.




Changelog
0.8.01
-kód starající se o emulaci AttoWPU nyní běží v samostatném vlákně - o něco rychlejší (zvláště u multijádrových procesorů), přesnější časování.
-maximální/nelimitovaná rychlost emulace nyní funguje, stačí kliknout na Max, či přetáhnout posuvník úplně doprava
-LED diody a přepínače jsou nyní grafické, namísto radio a checkboxů, takže vypadají lépe
-zachytávání kláves je nyní zcela globální pro celou aplikaci, nezáleží který prvek má keyboard focus
-opraveno padání při zavření dialogu pro načtení zdrojového souboru
-malá aktualizace ve specifikaci ve způsobu ovládání speakeru
-dostupná je česká verze dokumentace, počítejte ale s tím, že nebude aktualizována tak často, jako anglická

0.8.02
-K dispozici binárky pro Linux
-Aktualizován attoassembler kód v emulátoru, což řeší některé pády při překladu zdrojových kódů

Nahlásit jako SPAM
IP: 217.196.214.–
Frooxius0
Duch
21. 5. 2012   #4
-
+2
-
Zajímavé

Kdyby to někoho zajímalo, vyhrál jsem s tímto projektem národní SOČ v oboru Informatika i v zahraničí to mělo docela úspěch, respektive zejména architektura 2DWPU, jejíž výsledky jsem na Intel ISEFu prezentoval, neboť jsou mnohem zajímavější :3

http://www.lidovky.cz/…/ln_veda.asp?…

Nahlásit jako SPAM
IP: 217.196.214.–
crazy
~ Moderátor
+10
Grafoman
21. 5. 2012   #5
-
0
-

#4 Frooxius
wow, velká gratulace...

Nahlásit jako SPAM
IP: 89.190.90.–
All you need is vision and time.
JoDiK
~ Anonymní uživatel
987 příspěvků
21. 5. 2012   #6
-
0
-

#4 Frooxius
Můžu dotaz?

Nepochopil jsem jednu zásadní věc - procesor z rodiny WPU - je už nějaký vyrobený? Tím myslím že fyzicky existuje, tzn že ho nějaká firma vyrábí a prodává? Nebo je to zatím jen teoretická záležitost řešená přes simulátor/emulátor na klasickém procesoru?

Možná se to někde na tom anglickém webu píše, ale nemám teď čas se tím prolouskávat...

Nahlásit jako SPAM
IP: 88.103.236.–
Frooxius0
Duch
22. 5. 2012   #7
-
0
-

#6 JoDiK
Ano, existuje, ale nevyrábí se a neprodává se (zatím). Teoretická záležitost by to byla akorát, kdyby byla jen specifikace, už ten simulátor je v podstatě jistá praktická (funkční) forma implementace, ovšem mám i hardwarovou verzi, syntetizovanou pro hradlové pole (FPGA čip), takže jsem na Intel ISEFu předváděl i fyzický obvod běžící v reálném čase na vývojové desce.

Nahlásit jako SPAM
IP: 217.196.214.–
JoDiK
~ Anonymní uživatel
987 příspěvků
22. 5. 2012   #8
-
0
-

#7 Frooxius
Díky za info, mně se hned nezdálo, žeby někdo investoval do vývoje procesoru, který by "žaby zatím?" neměl masové použití...

Nahlásit jako SPAM
IP: 88.103.233.–
Frooxius0
Duch
22. 5. 2012   #9
-
0
-

#8 JoDiK
Mno tak že se to teď nevyrábí, neznamená, že ty architektury, které jsem vyvinul, nemají masové použití. Jen je to zatím ve fázi prototypu a vývoje.

Nahlásit jako SPAM
IP: 217.196.214.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 12 hostů

Podobná vlákna

Programovací jazyk R — založil Martin

Programovací jazyk — založil Itej

Programovací jazyk E — založil Nikol

Programovaci jazyk — založil marfik

Programovací jazyk — založil Dalibor

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý