[ mserifov @ 19.07.2008. 12:04 ] @
ja nesto ko biva znam o elektronici teoretski o mikrokontrolerima i tako. Ali u uopšte programiranje u ovom slučaju programiranje mikrokontrolera. To je potpuno druga nauka. Iako u svijetu mikrokontrolera elektronika kao hardware i program kao software cine jednu cijelinu.
Moje pitanje je kojim programskim jezikom znači c++ ili nesto drugo. Započeti rad ili učenje programiranj.
Zasto su nizi programski jezici po mom iskustvu tezi za programirat. Odnosno programi su veći postupak pisanja programa je duži.
Ali ti programi su bolji manje bugova.

A naprimjer kada se program piše u novim jezicima višim. Programiranje je jednostavnije ali nije to to.

Znači ako može da se u ovoj temi piše samo o umjetnosti programiranja. Za početak oni početnički odgovori kako gdje izašto.

Ipak programje taj koji daje život jednom mikrokontroleru.


[ korak @ 19.07.2008. 13:51 ] @
mserifov, potpuno si u pravu sa svojim razmisljanjem o programskim jezicima za mikrokontrolere. Jos vise si u pravu kada su u pitanju 8-o bitni mikrokontroleri. Ja sam pravio neke testove sa netrivijalnim programima, radi se o MAC sumi preko TDES algoritma. Koristio sam profesionalne C kompajlere (zaista vrlo dobre) i rezultat je sledeci: generisani kod C kompajlerom je najmanje 20% duzi, a izvrsava se do 50% sporije. Osim toga C je jezik srednjeg nivoa i moze da tokom prevodjenja prijavi greske koje se vrlo tesko otkrivaju, narocito ako su to greske koje prijavljuje linker. Jos je gore ako ne prijavi gresku, a vama program ne radi dobro, sto je moguce zbog same definicije C-a koja nema jaku tipizaciju.

Asembler ce uvek biti najbolji jezik za programiranje mikrokontrolera. Medjutim, on ima mana. Najveca mu je ta sto je efikasnost pisanja softvera niska, a svi zele sto pre da izbace proizvod na trziste. Zatim, odsustvi svake struktuiranosti, kako podataka tako i programskih sekvenci cini programiranje na asembleru napornim. Meni narociti tesko pada izmisljanje imena raznim labelama, to me izludjuje.

Ali asembler se moze napraviti tako da mu se poveca efikasnost i olaksa programiranje. Kako se dugo bavim mikrokontrolerima, sam sam definisao jedan asemblerski kompajler i realizovao sa njim razvojni sistem sa loadovanjem programa, simulacijom i dibagiranjem. Da ne bih opisivao kakav je to asembler dovoljno je reci da je u svemu isti sa PASCAL-om, samo sto su PASCAL iskazi zamenjeni asemblerskim iskazima. Poseduje module (kao turboPASCAL) i makroe kao svaki dobar asembler.

Problem sa asemblerom je sto je neprenosiv. Mozete ga koristiti samo za jednu familiju mikrokontrolera, a ako zelite isti program da primenite na drugu familiju mikrokontrolera, aonda morate ponovo pisati asemblerski program u asembleru za taj drugi mikrokontroler. Ovaj problem ne se ne javlja u tom obliku kada koristite C, potreban vam je samo drugi C kompajler i isti program uz manje ili vece izmene mozete primeniti na programiranje tog drugog mikrokontrolera. Medjutim, izmene izvornog teksta programa nisu ni malo naivne, narocito ako vam se program mnogo oslanja, i to ditektno, na hardver mikrokontrolera. Srecom, koliko vidim na forumu, uglavnom svi rade samo sa jednom familijom mikrokontrolera pa ih potpuno moze zadovoljiti programiranje na asembleru.

Pozdrav.
[ mserifov @ 19.07.2008. 14:03 ] @
korak sa tim problemima se susreću i veterani i početnici
onma koji se bave hobijem kao mikrokontolerima osim ako neće više da znaju obično ona najednostavnija i naj brža programska rješenja odgovaraju.
Medutim kaze vidi pitanja dali se moze mikrokontoler iprogramirati u fortranu.
To ja hocu da u ovoj temi objasnimo početnicima i onim totalnim i onima koji imaju teoretsko znanje i ali ne i praksu kako početi kako naučiti osnove koje su razlike š ta želite da radite.
Normalno i onima veteranima po gotovo koji su programiranje naučili sa pogrešne strane kako i šta uraditi.
mada se programirati ili zna ili nezna

molim za uključenje u diskusiju neka ko hoce da svoj doprinos i koju rijec o
nazovimo je umjetnosti programiranja mikrokontrolera od amih početak i upustava onih osnovnih pa do kompleksnih problema.

Hval unaprijed.
[ korak @ 19.07.2008. 15:09 ] @
U FORTRAN-u?

Pa da vidimo.

Tipovi u FORTRAN-u su implicitno odrdjeni pocetnim slovom imena varijable. Ako se dobro secam, kada ime pocinje sa I,J,K,L,M ili N to su celobrojne varijable, inace su real varijable (u pokretnom zarezu). Kako definisati byte (u C-u char) word, longword i naspram ovih neoznacenih i oznacene varijable. To je nepremostiv problem. Nedostatak ostalih tipova, i gradjenje slozenijih od manje slozenih (do preddefinisanih u samom jeziku) je takodje diskvalifikujuci nedostatak.

Izostanak svake struktuiranosti jezika je nesto sto je danas neprihvatljivo.

Dakle, ne isplati se pisati se pisati FORTRAN kompajler za programiranje mikrokontrolera.

Pozdrav.
[ vladabajic @ 21.07.2008. 13:29 ] @
ovo ce biti zanimljivo....

Citat:
korak
Ali asembler se moze napraviti tako da mu se poveca efikasnost i olaksa programiranje. Kako se dugo bavim mikrokontrolerima, sam sam definisao jedan asemblerski kompajler i realizovao sa njim razvojni sistem sa loadovanjem programa, simulacijom i dibagiranjem. Da ne bih opisivao kakav je to asembler dovoljno je reci da je u svemu isti sa PASCAL-om, samo sto su PASCAL iskazi zamenjeni asemblerskim iskazima. Poseduje module (kao turboPASCAL) i makroe kao svaki dobar asembler.
Pozdrav.


svaka cast korak...
a da li je kod napisan u ovom "pascal-asembleru" da ga tako nazovem, jednake duzine i brzine izvrsavanja, kao i kod pisan u asembleru klasicno? mikroelektronika ima svoj pascal. ima li neke slicnosti ili razlike sa tvojim?

ja sam razmisljao da sebi olaksam posao tako sto cu napisati gooomilu makroa koje mogu da koristim kada mi zatrebaju. da li mi onda kod bio duzi?

[ korak @ 21.07.2008. 15:36 ] @
Ovo je pravo pitanje od vladabajic-a,

U deklaracionom bloku, gde se definicu konstante, varijable, tipovi i t. d. nista se ne gubi u odnosu na klasican asembler. Tablice se definicu kao tipizirane konstante, i vrednost ovih konstanti se smesta u flash. Prednost je to sto ovakva tablica moze imati slozenu strukturu (array, record), a uz podrsku asemblera ima se lak pristup bilo kom podatku u tablici. Tipiziranim konstantama se pristupa kao varijablama. Na primer:

tTab = array[0..3] of record
a : byte;
b : word;
end;

const
Tab : tTab = ((a:1;b:1001),(a:2;b:2002),(a:4;b:4004),(a:8;b:8008));

Adresni deo kojim se pristupa, na primer, trecem elementu polja b je [Tab[2].b]; Ako nije moguc 16-to bitni pristup, vec samo bajt po bajt, onda bi se pristupilo visem pa nizem sa: [Tab[2].b.0] i [Tab[2].b.1];. Kompajler prijavljuje gresku ako: [Tab[2].b.2] jer polje b ima samo 2 bajta. Svaka string konstanta se automatski definise kao tipizirana konstanta. Tako na primer:

const
ss = 'Aca i Maca';

pa se sa [ss[0]] pristupa bajtu duzine stringa, a sa [ss[7]] karakteru 'M'. Dakle nema nikakvih ogranicenja ili dodatnog koda u odnosu na klasican asembler.

Sto se tice iskaznog dela programa, tu ima neznatnih odstupanja. Kod repeat..until petlje nema dodatnog koda jer na primer:

repeat
-
-
until =0;

se prevodi tako sto kompajler zapamti adresu na mestu repeat, a kod until =0 pravi relativni skok na tu adresu ako nije setovan fleg Z. Ili ako se inkrementira dvobajtna varijabla za 1:

var
n : word;
-
-
inc [n.1];
if =0 then inc [n.0];

Prvo se inkrementira nizi bajt za 1, pa se testira fleg Z, i ako je on setovan inkrementira se i visi bajt. Ako Z nije setovano skace se na prvu naredbu iza if. Moze se javiti, nekada, par dodatnih bajtova koda kod koriscenja case..of strukture. Tada se javlja nepotreban skok na prvu naredbu iza tog skoka. Ovo nije zbog lose definicije jezika, vec zbog lose implementacije. Ovo nisam ispravljao, mrzelo me je, a ova struktura je vrlo korisna i mnogo pomaze kod struktura sa visestrukim uslovima. Na primer kada testirate koji je taster pritisnut, i zavisno od toga pozivate odredjenu proceduru. Sigurno se pitas koja varijabla ide iza case. Nijedna, vec samo registar sa kojim se moze vrsiti naredba komparacije. Dakle, pre toga vrednost varijable treba smestiti u takav registar.

Postoji i while..do petlja ali u obliku:

repeat by
-
-
prior
-
until >=0;

Kompajler generise kod kojim se posle repeat by skace na prior gde je asemblerski kod za generisanje uslova za izlazak iz petlje, i ako je on ispunjen odmah se napusta petlja i ne izvrsava kod u telu petlje izmedju repeat by i prior. U suprotnom sve se odigrava kao u obicnor repeat..until petlji.

Procedura se poziva samo navodjenjem imena procedure, a kompajler generise dugacak ili kratak poziv, zavisno od toga koliko je udaljena procedura koja se poziva. Parametri proceduri se mogu proslediti preko registara MCU-a, i tada se procedura deklarise bez formalnih parametara. U okviru procedure mogu da se definisu konstante, tipovi i varijable, i one su lokalne za proceduru. Zavisno od implementacije (a moja je takva) varijable definisane u proceduri su dinamicke i nalaze se na steku. Ovo je je moguce i u klasicnom asembleru, ali je tesko za programera i podlozno greskama, dok je sve to mnogo jednostavnije ako se prepusti kompajleru. Moguce je defklarisati i procedure sa formalnim parametrima kojima se strarni parametri prosledjuju preko steka. Isto je i za funkcije. Tako na primer ako imate funkciju koja mnozi word i word i daje rezultat word, onda mnozenje 3 word varijable i smestanje rezultata u cetvrtu bi bilo:

var
a,b,c,r : word;
-
-
r := MulWord(MulWord(a,b).c);

Postoje i moduli, ali nije dozvoljeno da jedan modul ukljucuje drugi. To nije ni potrebno jer kompajler radi malo drukcije od DELPHI ili TurboPASCAL kompajlera. Naime, kada naidje na listu modula:

uses
ModulA,ModulB,ModulC;

kompajler po redosledu prvo prevede sve module od njihovog pocetka (zaglavlja) pa do simbola (sluzbene reci) implementation. Sve sto je prevedeno je globalno i moze se koristiti kako u glavnom tako i u svim ostalim modulima. Posle toga, po istom redosledu, prevede ostali deo izvornog teksta modula. Ovo nije moguce ni u jednom klasicnom asembleru.

Varijable se automatski rasporedjuju u memoriji. Iza simbola var moze stajati var zeropage sto definise da su varijable, tu definisane, na nultoj strani. Ako je varijabla definisana kao:

var
Port1 : byte absolute 1;

znaci da je Port1 varijabla tipa bajt i da se nalazi na adreso 0x0001.

Makroi su posebna prica, za ciji opis ovde nema mnogo prostora. Oni imaju svoje formalne parametre koji nisu tipizirani. U samom makrou se moze ispitivati tip prosledjenog parametra i zavisno od toga se mogu pozivati razlicite procedure, funkcije ili razlicito generisati kod. Makro moze i vratiti vrednost kroz preddefinisani formalni parametar result (koristi se i u funkcijama). Jedan makro moze da ukljuci drugi makro. U makrou mogu da postoje i labele (oni koji rade u C-u znaju kakvi problemi postoje sa makroima koji imaju labele). Takodje posoji i preddefinisana procedura koja prijavljuje gresku, onako kako to programer definise. Samo jedan mali primer:

macro Pomnozi(a,b);
begin
_if (TypeOf(a) = TypeOf(byte)) and (TypeOf(b) = TypeOf(byte)) then result := MulByte(a,b);

_if (TypeOf(a) = TypeOf(word)) and (TypeOf(b) = TypeOf(word)) then result := MulWord(a,b);
end;

i ukljucivanje makroa:

VarWord := Pomnozi(Var1Word,Var2Word);

Ovde se _if razlikuje od if. Prvo je kompajlerski if, koji odredjuje koji deo koda ce se prevoditi, a drugi je deo programa.

Ceo razvojni sistem je napravljen modularno, tako da je sintaksna analiza odvojena od generisanja koda, pa tako moze relativno lako da se napravi za bilo koji mikrokontroler.

Ako ima nekih posebnih pitanja koji zadiru u detalje, mozemo i o toma prodiskutovati.

Pozdrav.

[ vladabajic @ 21.07.2008. 18:35 ] @
hvala na ovako opsirnom odgovoru. nisam bas uspeo sve potpuno da svarim, a evo i zbog cega:
jos sam (relativno) pocetnik i radio sam neke stvari u pic basicu. medjutim kad sam uvideo da sa njim bas ne moze sve tako bajno da se uradi, digao sam ruke od njega i odlucio da sednem i posvetim se asembleru. e sad tek vidim koliko je to sve kompleksno (da ne kazem tesko), pa hocu to nekako da pojednostavim, ali da to ne bude pravljenje rutina koje cu cuvati i koristiti kada mi trebaju (uz gomilu modifikacija)...
e sad samo treba sesti i uciti :-)
[ tasa5 @ 23.07.2008. 10:36 ] @
Ja se jos nisam sretao sa objeknim jezikom za MC tipa c++, jeli je neko?
[ vladabajic @ 23.07.2008. 11:17 ] @
koliko je meni poznato (tako kazu neki programeri), u visual studio-u postoji deo koji je namenjen oop MCU-a.
takodje jedan poznanik mi je skoro rekao da pise program za PIC bash u c++
zanemario sam njegovu konstataciju da je kod manji i da se brze izvrsava nego asm kod!!! :-)
[ korak @ 23.07.2008. 12:05 ] @
Metrowerks-ov CodeWarrior kompajler za C je C++.

Ni teoretski ni prakticno ne moze program generisan sa C ili C++ da bude kraci i brzi od onog napisanog asemblerom. Takav zakljucak mogu da daju samo oni bez iskustva u asemblerskom programiranju.

Inace, ako se koriste osobenosti C++, program mora biti nesto duzi i sporiji nego kada se ne koriste osobine objektnog programiranja. Proucite malo objektno programiranje pa ce te shvatiti zasto.

Pozdrav.
[ vladabajic @ 23.07.2008. 15:32 ] @
pokusao sam da ga ubedim u isto, ali nije vredelo...
ne treba biti preveliki strucnjak da bi se doslo do tog zakljucka, ali on ne zna ni a od asemblera pa sam video da je uzalud trud...
meni licno se asembler svidja sto ti moras da savladas mcu hardverski i da znas kako sta unutra radi da bi mogao da ga programiras... dok sam radio u pic-basicu nisam morao skoro nista da znam o njegovim registrima, steku, brojacima... e sad kada sam poceo sa asemblerom... to je vec prica za sebe.

nego korak, da li si komercializovao tvoj 'paskal-asemblerski kompajler', i koliko bi bilo potrebno modifikacija da bi bio primenjiv na pic. ne mislim da je pic najbolji niti da zalazim u takve diskusije (ti naprimer preferiras motorolu), nego sam do sada jedino njega koristio i hardverski ga sazvakao.
[ korak @ 23.07.2008. 17:14 ] @
Voleo bih da modifikujem svoj kompajler za PIC. Nisu vazne njegove karakteristike, ali vrlo je raspostranjen kod hobista, koji kada nadju posao, normalno da ce raditi sa PIC-om. Ali, PIC ima vise familija koje se razlikuju, a tesko mi je da obuhvatim sve, pre svega jer bi morao sve njih da proucim. Dobro bi bilo da se opredelim za jednu ili dve (najvise) familije - vazno je da imaju isti skup naredbi, ili da se neznatno razlikuju. Nisam dobro upoznat sa raznovrsnoscu PIC-ovih familija. Dobro bi bilo da mi neko pomogne sa sugestijama, koju familiju da uzmem u rad. Drugo sto mi je problem to je loadovanje programa. Da li je dovoljno generisati binarni fajl sa prevedenim kodom, a onda da se nekim programatorom programira PIC. Ovo zato sto vidim da ima dosta razlicitih programatora, pa bi mi mnogo vremena oduzelo da sve to proucim.

Vase dobre sugestije i pomoc u tom smislu bi mogli da dovedu do nekog rezultata.

Pozdrav.
[ rsinisa @ 23.07.2008. 19:53 ] @
Mislim da ti je nabolje da krenes sa 16F, prilicno se koristi bash kod hobista, ali su sasvim dovoljno mocni i za srednje slozene aplikacije. Sto se tice programiranja, svi kompajleri (koji su meni poznati) generisu hex fajl kojim se posle programira PIC, da ne ulazim u detalje kojih sve softvera i hardvera ima.

Pozdrav.
Sinisha

P.S. Korak, imas PP.
[ Stojan Trifunovic @ 24.07.2008. 06:28 ] @
Slazem se sa Sinisom. 16F i eventualno 18F (teza) familija.

16F ima samo 35 instrukcija, medjutim zbog razlicitih adresnih modova (instrukcije kojima odrediste rezultata moze biti memorijski ili radni registar - F ili W) dobija se cifra od 49 unikatnih instrukcija. U citavoj 16F seriji koriste se samo te instrukcije (ne racunam one koje Microchip ne preporucuje).

Mikrokontroleri se jedan od drugog razlikuju po integrisanim hardverskim modulima (PWM, ADC, TIMER1...) i po rasporedu registara specijalne namene u pocetku RAM memorije. Taj raspored je na srecu standardizovan na oko 3 (ako se ne varam) standardne postavke za celu 16F familiju, naravno uz izuzetak odredjenih registara (ili bitova) ukoliko nemaju pripadajuci hardverski modul.

Najvece probleme pri prilagodjavanju kompajlera verovatno bi imali pri prelazu na razne strane RAM memorije, koja je eto kod 16F serije podeljena po bankama (bank). Registri specijalne namene se nalaze na pocetcima banaka. Microchip je predvideo nesto malo registara kojima se moze pristupati iz svih banaka, i koji su tako najpogodniji za ceste operacije (npr. cuvanje sadrzaja registara pri interaptima).

Drugi problem moze biti ogranicenje programske memorije (flash) oko prelaza strana (page). Kako je programski brojac kod PIC16 serije trinaestobitni, on moze adresirati maksimalno 2Kb programske memorije. Kompajler bi morao voditi racuna o skokovima preko takvih strana.

Treci problem moze biti koriscenje tabela, koje se u PIC16 seriji najlakse implementiraju preko niza retlw k instrukcija, gde je k osmobitni broj. Da bi se skocilo na pojedini clan u nizu, indeks se direktno sabira sa donjim (osmobitnim) bajtom (PCL) programskog brojaca (PC). To ogranicava polozaj tabele na blokove od 256 bajta. Svakako da se i ovo moze resiti, ali treba i na to obratiti paznju, pogotovu ako se definisu tabele sa podacima duzim od jednog bajta (npr. word). Oni bi se u 16F seriji mogli nalaziti unutar cetiri tabele, jedna iza druge, ili pak unutar razlicitih banaka (ako su vece).

Buduci da PIC16 serija nema mocnije hardverske matematicke instrukcije (mnozenje, deljenje...) koje paskal sigurno podrzava, one bi se mogle samo kopirati iz Microchipovih tehnickih uputstava (Aplication Note) i pozivati kao gotovi moduli. To bi ubrzalo razvoj kompajlera.

Cisto binarni kod ne bi bio mnogo upotrebljiv. Teska bi bila kasnija konverzija. Microchip koristi INHX8M .hex format, koji je kao takav spreman sa snimanje. Njega koriste "skoro" svi programatori (bar sam ja video samo jedan koji ga ne koristi). Umesto njega, mozda bi bilo lakse samo prebaciti Pascal kod u asemblerske instrukcije i snimiti asemblerski kod unutar .asm fajla (dodajuci pri tome na odgovarajucim mestima i komentare iz paskala) i onda prepustiti konverziju iz .asm u .hex kod standardnim (i besplatnim) Microchipovim alatima. Tako konvertovane programe iz C jezika vidjao sam vec po Microchipovim tehnickim uputstvima.
[ sander @ 24.07.2008. 08:50 ] @
Citat:
korak: Voleo bih da modifikujem svoj kompajler za PIC. Nisu vazne njegove karakteristike, ali vrlo je raspostranjen kod hobista, koji kada nadju posao, normalno da ce raditi sa PIC-om. Ali, PIC ima vise familija koje se razlikuju, a tesko mi je da obuhvatim sve, pre svega jer bi morao sve njih da proucim. Dobro bi bilo da se opredelim za jednu ili dve (najvise) familije - vazno je da imaju isti skup naredbi, ili da se neznatno razlikuju. Nisam dobro upoznat sa raznovrsnoscu PIC-ovih familija. Dobro bi bilo da mi neko pomogne sa sugestijama, koju familiju da uzmem u rad. Drugo sto mi je problem to je loadovanje programa. Da li je dovoljno generisati binarni fajl sa prevedenim kodom, a onda da se nekim programatorom programira PIC. Ovo zato sto vidim da ima dosta razlicitih programatora, pa bi mi mnogo vremena oduzelo da sve to proucim.

Vase dobre sugestije i pomoc u tom smislu bi mogli da dovedu do nekog rezultata.

Pozdrav.


Bilo bi lepo videti tvoj kompajler za PIC familiju mikrokontrolera ali iskreno ne vidim da bi nesto zaziveo medju korisnicima istih, oni koji nemaju nameru da se previse bakcu i dalje ce koristiti PIC Basic, dok oni koji misle da rade nesto ozbiljno su i onako presli na neke od dobrih C kompajlera. Takodje, da li bi ti se ulozeni trud isplatio jer vec postoje Paskal kompajleri za PIC-eve sa vec velikom podrskom u gotovim bibliotekama za raznorazne periferije (pogledati Mikroelektronikin)? Ono sto bi ti ja predlozio je da kompajler (za motorolu) koji vec imas uradjen i koji koristis ponudis recimo Mikroelektronici koja ima u najavi razvojnu plocu za tu familiji kontrolera i kojima bi bas leglo da imaju podrsku u vidu kompajlera. Onii vec imaju razradjen posao i ako napravite neki dogovor tek onda bih ja razmisljao o nekim drugim platformama ali pitanje da li bi medju njima bilo PIC mikrokontrolera. Ovo ti najiskrenije govorim iz najbolje namere, jer raditi kompajler i potrositi silno vreme a na kraju nemati nikakvu materijalnu satisfakciju po meni nije pametno. Ukoliko imas viska vremena i ipak se odlucis da radis kompajler za PIC mikrokontrolere stojim ti na raspolaganjiu za eventualne sugestije.

Pozdrav.
[ vladabajic @ 24.07.2008. 09:14 ] @
Ali ako bi kompajler bio dobro uradjen i trosio manje resursa kontrolera i sam rad bio brzi, zasto bi to bio uzaludan posao. Pa svi bi ga koristili, ako se zna da je programiranje olaksano i primenljivo bez vecih prepravki na celu familiju! a pritom je rezultat isti ili skoro isti kao da se radi u asembleru. ne moze se to porediti sa mikroc kompajlerom.
[ sander @ 24.07.2008. 11:23 ] @
Citat:
vladabajic: Ali ako bi kompajler bio dobro uradjen i trosio manje resursa kontrolera i sam rad bio brzi, zasto bi to bio uzaludan posao. Pa svi bi ga koristili, ako se zna da je programiranje olaksano i primenljivo bez vecih prepravki na celu familiju! a pritom je rezultat isti ili skoro isti kao da se radi u asembleru. ne moze se to porediti sa mikroc kompajlerom.


Vidi to sto ti kazes je OK ali (opet ali) korak, uz svo duzno postovanje prema njemu i njegovom radu, nije radio sa PIC mikrokontrolerima i samim ti je uskracen za neka saznanja koje su ljudi godinama sticali i to pretocili u svoje kompajlere. Sam proces razvijanja kompajlera je prilicno mukotrpan, pomno sam pratio razvoj mikroC kompajlera sto zbog licnog interesovanja sto zbog nekih prijatelja koji su radili na razvoju nekih biblioteka. Ponavljam, za sam razvoj kompajlera mislim da bi bilo bolje izbaciti kompajler koji se pokazao pouzdan za taj ti mikrokontrolera (motorola) pa ako se prihvati od sirokih narodnih masa onda razmisljati o prebacivanju istog na druge platforme.
[ vladabajic @ 24.07.2008. 12:23 ] @
Citat:
sander: Vidi to sto ti kazes je OK ali (opet ali) korak, uz svo duzno postovanje prema njemu i njegovom radu, nije radio sa PIC mikrokontrolerima i samim ti je uskracen za neka saznanja koje su ljudi godinama sticali i to pretocili u svoje kompajlere.

da, ovo bi moglo predstavljati problem...
ali sa druge strane, posto je mnogo vise korisnika pica, bilo bi mozda i neke koristi, ako se valjano uradi :-)
naravno, nije uvek korist pokretac...
[ korak @ 24.07.2008. 13:11 ] @
Vrlo korisne informacije.

Treba znati gde se kod 16F, i 18F cuvaju bitovi za selektovanje stranica. Svaka je, zar ne, duzine 256 bajta. To migu videti u dokumentaciji. PIC ima neki mehanizam za indirektno adresiranje, zar on ne moze da se koristi za citanje tablica, jer ono sto sam sretao kao primere citanja tablica prilicno je ogranicavajuce.

Narocito me onteresuju registri kojima se pristupa bez obzira na stranicu i koji mogu da se sacuvaju prilikom aktiviranjem interrupt-a. Mozda mogu da se iskoriste za prenos parametara procedurama? To moram prouciti, i zamolio bin za pomoc u tome.

Imace moj pristup je drukciji od Mikroelektronike. U dva navrata sam posetio tu firmu i shvatio princip na kome oni rade. Ja ne mogu tako da radim. Posetio sam njihov forum i video koliko ima primedbi na njihov mikro PASCAL, a i sam sam ga testirao. Ja tako nesto ne bih komerciajlizovao. Ja proizvodim 4-o slojne plocice dimenzija 5 x 4 cm na kojoj se nalazi mikrokontroler raznih tipova familije MC9S08 sa serijskim EEPROM-om od 16K ili vise, satom realnog vremena i RS232 drajverom. Plocica ima dva 40-to pinska (2 x 20) muska konekrora (pin letve) koje se ubadaju u ista dva zenska konektora. Preko ovih konektora su izvedeni svi signali sa mikrokontrolera i RS232 RxD i TxD posle drajvera. Takva plocica je imuna na smetnje i moze posluziti kako za neku plocu za ucenje, tako i za finalni uredjaj. Maticna ploca na koju se postavlja ova plocica moze biti i jednoslojna, ali nece biti ugrozen kvalitet vaseg uredjaja. Ako uzmete u obzir cenu od mog dobavljaca u Nisu za MC9S08JM60 od 3.88 EUR, ovaj mikrokontroler ima 60KB flash-a, 4KB RAM-a, dve RS232 komunikacije i dve SPI komunikacije I2C, 12-to kanalni ADC (10 bita) )dva nezavisne tajmerske jedinice sa po 6 i 2 tajmerska kanala (a znate da Motorola ima najbolje tajmerske jedinice) USB 2.0 (12MBps), klok na bus-s od 24 MHz (perioda ciklisa 41.7ns), 8 KBI pina i 51 IO pin, napajanje od 2.7V do 5.5V, onda se stvarno radi o vrlo povoljnom odnosu performanse/cena. Za sada imam uredjene plocice za ovak MCU, za MC9S08GB60 koji je slican predhodnom, ali nema USB i ima 56 IO pina a napaja se od 1.8V do 3.6V i MC9S08AW60 slican sa MC9S08GB, ali je za napon od 2.7V do 5.5V.

Dakle, posto sam ja i proizvodjac profesionalnih uredjaja, odlucio sam se za ovu varijantu, koja medjutim, ne iskljucuje i hobiste. Kada bi radio i za PIC, primeno bih isti pristup.

Pozdrav, ocekujem pomoc za PIC.

Uputite me na format hex fajla koji poriste PIC programeri. Hvala
[ sander @ 24.07.2008. 13:48 ] @
Ako si vec odlucan da se upustas u to onda za pocetak nesto sto bi moglo pomoci.
To je Techbrief TB071a "Converting from Motorola® HC08 to Microchip Assembler:
A Quick Reference".
Ako ne budes mogao da ga nadjes, ili mi posalji mail na koji da ti posaljem ili adresu
da ti posaljem Microchip Technical Library CD doduse iz 2006 ali i onako su tu svi fajlovi
za ono sto ti je potrebno.
[ Stojan Trifunovic @ 24.07.2008. 16:22 ] @
Ogranicicu se pri odgovoru samo na 16F seriju.
Bitovi za selektovanje stranica RAM memorije nalaze se u STATUS registru. Bitovi imaju oznake RP0 i RP1, a njihova binarna kombinacija direktno odredjuje banku RAM memorije po sledecem:

00 - Bank 0
01 - Bank 1
10 - Bank 2
11 - Bank 3

U jednoj banci ne moze biti 256 bajtova, vec maksimalno 128 (0x7F). Ovo ogranicenje proistice od samo 7 bita za adresiranje RAM memorije, a ono je verovatno uvedeno zbog Hardvarske arhitekture instrukcija.

Indirektno adresiranje RAM memorije postoji, ali i za njega je potrebno selektovati odgovarajucu stranu (IRP bitom STATUS registra) po sledecem:

0 - Bank 0 i Bank 1
1 - Bank 2 i Bank 3

Kada sam u proslom postu pominjao tabele mislio sam na tabele sa fiksnim vrednostima koje se cuvaju u flash memoriji. Flash, nazalost nema mogucnost indirektnog adresiranja, vec joj se moze pristupiti jedino preko trinaestobitnog PC (Program Counter) registra, odnosno PCL (bajt manje tezine) i PCH (bajt vece tezine) registara. Pri tome se PCH bajt (jer nije dostupan direktno) updatuje prilikom bilo kakve softverske izmene vrednosti PCL preko PCLATH registra. Naravno, za svako prekoracenje PCL pri koriscenju tabele ili proracunatog skoka (on W goto), mora se updatovati i PCLATH. Otuda toliko muka oko tabela.
Asemblerske instrukcije skoka na cudan nacin koriste PCH. Na primer GOTO k i CALL k koriste k kao adresu skoka, ali je k (opet zbog Harvardske arhitekture) samo desetobitni (a ne trinaestobitni) pa ce sadrzaj PCLATH biti delimicno promenjen (samo donja dva bita) i zato se njima ne moze skociti preko bloka (page) od 2Kb.

U PIC16 seriji se registri ne mogu sacuvati automatski aktiviranjem interapta, vec se sadrzaj (obicno W, STATUS i eventualno PCLATH) registara mora rucno sacuvati pri ulasku i rucno vratiti pre povratka iz interapta. Jos gore, PIC16 serija nema instrukcije citanja i upisa u stek, tako da je za njihovo cuvanje najprakticnije koristiti adrese 0x70 do 0x7F kojima se moze pristupati iz bilo koje banke.
Svakako da su ovi registri (pored interapta) idealni za prenos parametara procedurama, jedini je problem njihov mali broj.


Za INHX8M format pronasao sam sledece sa help-a MPLAB paketa:

Intel Hex Format
This format produces one 8-bit hex file with a low byte, high byte combination. Since each address can only contain 8 bits in this format, all addresses are doubled.

Each data record begins with a 9-character prefix and ends with a 2-character checksum. Each record has the following format:

:BBAAAATTHHHH....HHHCC

where:

BB A two digit hexadecimal byte count representing the number of data bytes that will appear on the line.

AAAA A four digit hexadecimal address representing the starting address of the data record.

TT A two digit record type that will always be '00' except for the end-of-file record, which will be '01'.

HH A two digit hexadecimal data byte, presented in low byte/high byte combinations.

CC A two digit hexadecimal checksum that is the two's complement of the sum of all preceding bytes in the record.


Example: INHX8M
file_name.hex
:1000000000000000000000000000000000000000F0
:0400100000000000EC
:100032000000280040006800A800E800C80028016D
:100042006801A9018901EA01280208026A02BF02C5
:10005200E002E80228036803BF03E803C8030804B8
:1000620008040804030443050306E807E807FF0839
:06007200FF08FF08190A57
:00000001FF
[ korak @ 24.07.2008. 18:21 ] @
Super,
u nazivu nisam prepoznao intelov format. Nekada sam radio sa njim i poznat mi je. Dobro je sto si me podsetio.
Interrupt automatski stavlja status registar na stek, pa time i bitove za stranicenje. To je OK. Sta je sa PIC-ovima koji imaju veci RAM i vise stranica. Cini mi se da oni imaju poseban registar za stranicenje. Da li se i ovaj registar stavlja automatski na stek ili se to mora softverski uraditi. Nisam razumeo pravi razlog zasto je stranica ogranicena na 128 bajta.

0x70 do 0x7F je moze da bude dovoljno za prenos parametara, jer bi se duzi podaci prenosili preko pointera koji ukazuje na njih. Ali, moram da vidim koliko je komplikovano PIC-u da radi sa pointerima.

Nezgodno je sto GoTo i CALL nisu relativni skokovi (-1K, +1K) vec apsolutni u okviru istog bloka od 2KB.

No, sada imam malo vremena pa cu pogledati sve ovo detaljnije i prezentiracu neke predloge tebi i drugima na ocenu izvodljivosti.

Veliko hvala.
[ Stojan Trifunovic @ 24.07.2008. 21:39 ] @
Ne, interapt ne cuva STATUS (ni ostale registre) automatski niti (bar u 16F seriji) ih moze sacuvati na steku, vec se za njihovo cuvanje i povracaj uglavnom primenjuje sledeci kod:

Code:

      cblock    0x70        ; definisanje pocetka registara - registri zajednicki za sve banke
      W_TEMP                ; W_TEMP sa ovakvim algoritmom mora biti deljiv izmedju svih banki
      STATUS_TEMP           ; STATUS_TEMP moze se nalaziti bilo gde u Bank 0.
      PCLATH_TEMP           ; PCLATH_TEMP se takodje moze nalaziti bilo gde u Bank 0
      endc                  ; kraj imenovanja registara
      
_interrupt
        MOVWF W_TEMP        ;Copy W to W_TEMP register
        SWAPF STATUS,W      ;Swap status to be saved into W
        CLRF  STATUS        ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
        MOVWF STATUS_TEMP   ;Save status to bank zero STATUS_TEMP register
        MOVF  PCLATH, W     ;Only required if using pages 1, 2 and/or 3
        MOVWF PCLATH_TEMP   ;Save PCLATH into PCLATH_TEMP register
        CLRF  PCLATH        ;Page zero, regardless of current page

;
;(ISR) ;(Insert user code here)
;

        MOVF  PCLATH_TEMP, W ;Restore PCLATH
        MOVWF PCLATH         ;Move W into PCLATH
        SWAPF STATUS_TEMP,W  ;Swap STATUS_TEMP register into W
        ;(sets bank to original state)
        MOVWF STATUS         ;Move W into STATUS register
        SWAPF W_TEMP,F       ;Swap W_TEMP
        SWAPF W_TEMP,W       ;Swap W_TEMP into W
        retfie               ; return from interrupt


On se samo iskopira, i to je to. Cela filozofija. Interapti ni ne mogu predstavljati problem (osim ako njihov kod nije duzi od 2Kb) jer se uglavnom stavljaju na pocetku memorije, a pocetak glavnog programa pocinje nakon njihovog kraja.
16F serija ima samo dve specijalne flash adrese, a to su reset vektor (adresa 0x00) i interapt vektor (0x04). Uglavnom se odmah od pocetka interapt vektora postavlja interapt rutina, a na njenom kraju nadovezuje se glavni program. To izgleda otprilike ovako:

Code:

        ORG     0x000    ; processor reset vector
        goto    _main    ; go to beginning of program

        ORG     0x004    ; interrupt vector location
                         ; Ovde odmah pocinje interapt rutina
_interrupt               ; sa gornjim snimanjem i povracajem registara
        MOVF  PCLATH_TEMP, W ;Restore PCLATH
        
        ...

        retfie           ; povratak iz interapta

_main                    ; pocetak glavnog programa
        ...



Cela 16F serija uopste nema instrukcija za pristup steku. On se spolja ne moze videti, a koriste ga jedino interapt i CALL instrukcija (i naravno, odgovarajuce instrukcije povratka) za cuvanje adrese povratka. 16F serija ima samo 8 nivoa steka.

Harvardski set instrukcija podrazumeva da se unutar instrukcije nalazi kod instrukcije (po kome se CALL instrukcija razlikuje od GOTO), i operand sa kojim se radi (adresa, registar, bajt, bit, odrediste rezultata). Postoje i instrukcije sa vise operanda.

CALL instrukcija izgledala bi ovako:
kod . . operand - apsolutna adresa skoka
100 . kkkkkkkkkkk

Od GOTO instrukcije ona se razlikuje jedino po kodu instrukcije koji je za GOTO 101

Instrukcija povratka iz potprograma RETURN koja nema ikakav operand izgleda ovako:
. . . . kod
00000000001000

Instrukcija za brisanje registra CLRF (upis vrednosti 0x00) izgleda ovako:
. kod . . . operand - RAM adresa
000001 . . fffffff

Ono sto je svim instrukcijama zajednicko je fiksna duzina instrukcija (14 bitova). Kako su za kod CALL i GOTO instrukcija utrosena 3 bita, ostaje ih samo 11 za adresiranje apsolutne adrese. 11 bitova = 2Kb. Sve sto prelazi ovakvu stranicu (Program Counter je trinaestobitni, pa moze adresirati do 8Kb flasha sto je maksimum za 16F seriju) mora updatovati PCH preko PCLATH registra.

Ukoliko se pogleda CLRF instrukcija, primecuje se da je kod instrukcije zauzeo 7 bitova, tako da ih je ostalo samo 7 za adresiranje RAM memorije. 7 bitova = 128 bajtova. Sve preko toga resava se preko banaka (4 banaka * 128 bajtova je maksimalna RAM memorija za 16F seriju).


Za pointere unutar RAM memorije najprakticnije je koristiti njeno indirektno adresiranje. Medjutim, tu veliko ogranicenje predatavljaju banke, jer se RAM ne moze samo tako nadovezati iz jedne u drugu banku. Ovo ogranicenje postoji jer je unutar svake banke pocetni deo (0x00 - 0x1F ili 0x00 - 0x0B u zavisnosti od tipa mikrokontrolera) svake banke rezervisan za registre specijalne namene. Kako se njima direktno upravlja integrisanim hardverskim modulima, kompajler bi za pointere morao ili koristiti neprekidan RAM unutar jedne banke (najbrzi i najoptimizovaniji metod), ili koristiti komplikovanije procedure za virtuelno spajanje ovako izdeljene RAM memorije.

Jos jedna stvar koja je nezgodna kod PIC16 serije je upotreba instrukcija grananja. Naime, one preskacu narednu instrukciju (samo narednu instrukciju, nema relativnog +- skoka) u slucaju da je odgovarajuci uslov ispunjen. To se pak moze resiti upotrebom dve GOTO instrukcije odmah nakon instrukcija grananja, a jos bolje bi bilo da kompajler prepozna ovu situaciju i da u cilju bolje optimizacije koda stavi samo jednu GOTO instrukciju (neposredno nakon instrukcije grananja - onu koja ce biti preskocena ako je uslov ispunjen) i da odmah nakon nje nastavi sa drugim delom (koji se izvrsava ukoliko je uslov ispunjen).

[Ovu poruku je menjao Stojan Trifunovic dana 24.07.2008. u 23:06 GMT+1]

[Ovu poruku je menjao Stojan Trifunovic dana 24.07.2008. u 23:13 GMT+1]
[ sander @ 24.07.2008. 23:40 ] @
U principu 16F serija ima prilicna ogranicenja u poredjenju sa trenutno aktuelnim kontrolerima sto je razumljivo jer tada kada se pojavila potrebe su bile manje tako da ogranicenja nisu smetala. Mnoge stvari su ispravljene 18F serijom ali verovatno zbog kompatibilnosti su ponesto i ostavili za kasnije serije 24F i 32bit serije. Elem, posto je bilo prica o 16F seriji rekoh da malo nesto kazemo i o 18F seriji. Dakle, kod 18F serije takodje RAM memorija je podeljena u banke i to u 16 (0-15) banaka po 256b ali su sve SFR registre postavili u gornjih 128b u poslednjoj 15 banci i kojima se moze pristupati direktno bez potrebe da se dira registar za selekciju banaka BSR. Kako? Ram memoriji se moze pristupati ili preko vec pomenutog BSR registra (selekcija banke) ili koriscenjem Access bank-e tako sto se u instrukciji za pristup naznaci nacin pristupa. Access ram omogucava da se pristupi prvoj polovini banke 0 i drugoj polovini banke 15 bez obzira na stanje BSR registra. Recimo:

movwf f,a - sadrzaj W registra ce se upisati u registar f uz selekciju banke preko BSR registra ako je a=1 odnosno preko access ram-a ako je a=0

Ovim je postignuto da je pristup SFR registrima omoguceno bez dodatnih instrukcija za selekciju banke. Recimo za poredjenje, kod 18F serije se bez preklapanja banaka moze pristupati prvoj polovini banke 0, celoj jednoj banci (1-14) i SFR registrima odnosno nesto vise od cele ram memorije kod 16F serije (384b naspram 368b). Sama selekcija banke je takodje dozivela izmene i sada postoji posebna instrukcija za to:

movlb k - postavlja sadrzaj BSR registra

Dodata je i instrukcija

movff fs,fd - sadrzaj fs registra (12-bitn adresa) kopira u registar fd (12-bit adresa)

Takodje unapredjeno je indirektno adresiranje tako sto FSR registri sadrze 12-bit adresu sto znaci da preko indirektnog adresiranja pristupamo celokupnom memoriskom prostoru bez selekcije banaka. Da stvar bude jos bolja postoje 3 FSR registra: FSR0, FSR1 i FSR2 sa pripadajucim INDF registrma: INDF0, INDF1 i INDF2. To nije i poslednja inovacija kod indirektnog adresiranja, koriscenjem registra POSTINC0, POSTDEC0, PREINC0 i PLUSW0 moguce je pristupiti adresi u FSR-u i po pristupu uvecati/umanjiti adresu ili pre pristupa adresi, adresu uvecati ili joj dodati vrednost u W registru. Dodata je i dodatna instrukcija za upis u FSR registre:

lfsr f,k- u FSR registar f upisuje 12-bit adresu

Stek je takodje doziveo izmene i sada 32 byte veliki sa mogucnoscu da automatski snimi sadrzaj bitnih registara kod interapta (fast stack).

Kao sto vidimo 18F serija je dozivela prilicna poboljsanja u radu sa ram (data) memorijom i nije ni cudo sto je microchip tvrdi da je arhitektura/instrukcije prilagodjene C jeziku.
[ korak @ 25.07.2008. 12:31 ] @
Cini se da je bolje praviti odmah kompajler za 18F, sa tim sto bi na neki nacin u izvornom tekstu bilo oznaceno da li se koristi 16F ili 18F. Ako se koristi 16F, a pisu se neke naredbe koje ima samo 18F, kompajler ce prijaviti gresku.

Takodje je moguce da kada se napise GoTo ili Call da kompajler vidi koliko je udaljen skok, i ako je on u okviru dozvolenog bloka generise samo naredbu skoka ili poziv procedure. Ako to nije slucaj, on ce dodati i azuriranje registra PCLATH pra skoka.

Ali sta sa uslovnom naredbon skip, koliko, i kako je to definisano, naredbi ona preskace. Predpostavljam da uvek preskace samo jedni. Da li je do tako?

Deklaracija varijabli bi moglabiti ovakva:

var bank 0
lista varijabli

var bank 1
lista varijabli

i tako redom koliko ima varijabli i raspolozivih banaka. Imenu varijable bi bili pridruzeni adresa u banci i broj banke. Ovo bi omogucilo programeru da varijable koje ucestvuju medjusobno u nekim operacijama budu u istim bankama kako bi bilo sto manje preklaoanja banaka.

Ako bi deklaracija bila

var
lista varijabli

onda bi one bile kontinualno rasporedjene i prelazile bi iz banke u banki, sto nije prakticno.

Sinoc sam pogledao seriju 16F, i modul za generisanje koda bi bio dosta jednostavniji u odnosu na MC908 koji ima vose naredbi i 13 adresnih modova.

Cini se da bi izmena bila relativno jadnostavna, ali za to ce mi trebati nesto slobodnog vremena od oko mesec dana zajedno sa testiranjem.

Ovde sam postavio neka pitanja, pa molim da mi odgovorite na njih. Ja cu veceras da pogledam i seriju 18F pa cu izvuci ono sto je razlicito od 16F.

Pozdrav.
[ Stojan Trifunovic @ 25.07.2008. 15:45 ] @
Jeste, 18F serija je svakako mocnija, ali bi zahtevala dosta vise rada na kompajleru zbog vise instrukcija i vise adresnih modova.

To za CALL i GOTO je odlicno resenje. Tako programer uopste ne bi brinuo o navedenom problemu. Isto bi se moglo uraditi i za ON W GOTO i za tabele iz flasha (oba nacina koriste skok direktnom izmenom PCL).

Da, uslovna naredba skip (na primer btfss STATUS,Z) preskace samo jednu naredbu (sledecu) ukoliko je uslov ispunjen. U ovom slucaju preskocice sledecu instrukciju ukoliko je Zero flag setovan. Bitno je napomenuti da BTFSS instrukcija ne testira samo Zero flag, vec bilo koji bit unutar bilo kog registra. Slobodno se moze pisati btfss MOJ_REGISTAR,BIT_UNUTAR_REGISTRA.

Oblik ove instrukcije u programu je sledeci:

Code:

      btfss REGISTAR, BIT_UNUTAR REGISTRA
      goto  BIT_RESETOVAN
      goto  BIT_SETOVAN

BIT_RESETOVAN

      ...

BIT_SETOVAN

      ...

ili kraci (i optimizovaniji) oblik:
Code:

      btfss REGISTAR, BIT_UNUTAR REGISTRA
      goto  BIT_RESETOVAN
BIT_SETOVAN

      ...

BIT_RESETOVAN

      ...


Predlog za deklaraciju varijabli je dobar, sa tim sto bi kompajler morao unapred znati adresu pocetka varijabli (0x0C ili 0x20 u zavisnosti od tipa PIC-a) kako ne bi presao preko registara specijalne namene.

Mislim da bi najprakticnije bilo na pocetku odredjenom direktivom staviti oznaku mikrokontrolera (MPASM asembler za ovo koristi "list pF84" direktivu), a da onda kompajler na osnovu tipa mikrokontrolera (16F ili 18F) odabere set instrukcija, a na osnovu njegove dodatne oznake (84, 872, 877...) odabere podrzane hardverske module i raspored adresa za njihovo upravljanje.
[ korak @ 25.07.2008. 18:07 ] @
Da, sto se tice razlikovanja 16F i 18F to se mora uraditi zbog prosirenog seta naredbi kod 18F. Bitno je da svi 16F i 18F imaju u okviru svoje podfamilije iste instrukcije. Da li je tako?

Sto se tice ostalog, volim da je sve eksplicitno u izvornom tekstu programa. Sta ako izadje neki novi tip, onda treba apdejt.

Zato bi moglo:

var [0x20..0x7F]
lista varijabli

var [0xA0..0xEF]
lista varijabli

i t. d.

i programer bi, znajuci kakve banke ima mogao za svaki tip PIC- da pravi korektnu deklaraciju

Slicno bi bilo i za kod programa. Kod mene sada postoji:

code[pocetak..kraj]; gde ja upisujem prema tipu MCU-a ove dve vrednosti. Generisanje koda pocinje od 'pocetak'.

Sta mislite o ovome?

Pozdrav.
[ sander @ 25.07.2008. 23:48 ] @
Asembleski program sa 16F serije se bez dorade moze izvrsavati na 18F seriji s tim da se u programu izbace delovi za selekciju banaka (16F877 i 18F452). Licno sam prisustvovao demonstraciji od strane predavaca na Microchip-ovom seminaru u Beogradu. Prosireni set instrukcija mu dodje samo kao optimizacija odnosno poboljsanje perfomansi/brzine. Recimo, 18F serija ima dodatne instrukcije za grananje:

bc n
bn n
bnc n
bnn n
bnov n
bnz n
bov n
bra n
bz n

koje se mogu postici i preko:

btfsc STATUS,b

ili

btfss STATUS,b

ali im je vreme izvrsavanja krace. Isto tako snimanje sadrzaja vaznih registara priliom opsluzivanja interapt rutine se moze izvesti
kao i kod 16F serije, istim instrukcijama, ili automatski koriscenjem fast registar stack-a.
Znaci da kompajler moze proizvoditi kod i za 18F seriju isto kao i za 16F bez optimizacije ili uz naznaku o tipu mikrokontrolera da radi optimizaciju.
Sto se tice instrukciskog seta on je isti za celu seriju mikrokontrolera, razlika je jedino u periferijama.
C kompajler koji koristim sam dodeljuje memoriske lokacije varijablama ali je takodje moguce varijabli dodeliti fiksnu adresu, mozda bi i o tome trebalo razmisliti.
[ Stojan Trifunovic @ 26.07.2008. 07:37 ] @
Jeste. Cela 16F i 18F familija ima u okviru svoje podfamilije potpuno iste instrukcije.

Deklaracija varijabli moze biti takva (iako zahteva da programer bar pri prvom programu za taj tip PIC-a pogleda u datasheetu konkretne podatke), ali ukoliko vec ne zelite (zbog novih podfamilija PIC) da im definisete parametre unutar kompajlera, morali bi u kompajleru predvideti mogucnost definisanja perifernih modula i konfiguracionih bitova koji se koriste bas za taj tip PIC-a. To je pak, malo veci posao. Evo sta se sve treba definisati pre pocetka programa:

Pre svega periferni moduli. Pic16 serija ima sledece:

1. General purpose I/O Revision �DS31009A�
2. Timer0 Revision �DS31011A�
3. Timer1 Revision �DS31012A�
4. Timer2 Revision �DS31013A�
5. Capture, Compare, and PWM (CCP) Revision �DS31014A�
6. Synchronous Serial Port (SSP) Revision �DS31015A�
7. Basic Synchronous Serial Port (SSP) Revision �DS31016A�
8. Master Synchronous Serial Port (MSSP) Revision �DS31017A�
9. USART (SCI) Revision �DS31018A�
10. Voltage References Revision �DS31019A�
11. Comparators Revision �DS31020A�
12. 8-bit Analog to Digital (A/D) Revision �DS31021A�
13. Basic 8-bit Analog to Digital (A/D) Revision �DS31022A�
14. 10-bit Analog to Digital (A/D) Revision �DS31023A�
15. Slope Analog to Digital (A/D) w/ Thermister Revision �DS31024A�
16. Liquid Crystal Display (LCD) Drivers Revision �DS31025A�
17. Parallel Slave Port (PSP) Revision �DS31010A�

sa tim sto i unutar njih ima izmena, izazvanih verovatno nedovoljnim brojem pinova. Na primer ima PIC-eva koji podrzavaju jedino PORTA i PORTB, a ima i onih koji podrzavaju i ostale.

Onda konfiguracioni bitovi:

CP1:CP0: Code Protection bits
11 = Code protection off
10 = See device data sheet
01 = See device data sheet
00 = All memory is code protected
Note: Some devices may use more or less bits to determine the code protect. Presently
there are also some devices that use only one bit (CP0). For these devices the bit
description is:
1 = Code protection off
0 = Code protection on

DP: Data EEPROM Memory Code Protection bit
1 = Code protection off
0 = Data EEPROM Memory is code protected
Note: This bit is used when a device with ROM program memory also has Data EEPROM
memory.

BODEN: Brown-out Reset Enable bit
1 = BOR enabled
0 = BOR disabled
Note: Enabling Brown-out Reset automatically enables the Power-up Timer (PWRT)
regardless of the value of bit PWRTE. Ensure the Power-up Timer is enabled anytime
Brown-out Reset is enabled.

PWRTE: Power-up Timer Enable bit
1 = PWRT disabled
0 = PWRT enabled
Note 1: Enabling Brown-out Reset automatically enables Power-up Timer (PWRT) regardless
of the value of bit PWRTE. Ensure the Power-up Timer is enabled anytime
Brown-out Reset is enabled.
Note 2: Some original PICmicros have the polarity of this bit reversed.

MCLRE: MCLR Pin Function Select bit
1 = Pin�s function is MCLR
0 = Pin�s function is as a digital I/O. MCLR is internally tied to VDD.

WDTE: Watchdog Timer Enable bit
1 = WDT enabled
0 = WDT disabled

FOSC1:FOSC0: Oscillator Selection bits
11 = RC oscillator
10 = HS oscillator
01 = XT oscillator
00 = LP oscillator

FOSC2:FOSC0: Oscillator Selection bits
111 = EXTRC oscillator, with CLKOUT
110 = EXTRC oscillator
101 = INTRC oscillator, with CLKOUT
100 = INTRC oscillator
011 = Reserved
010 = HS oscillator
001 = XT oscillator
000 = LP oscillator

Mislim da bi bilo previse zahtevati od programera da definise svaki od ovih podataka za svaki novi program. Morala bi se predvideti mogucnost standardnog zaglavlja sa svim potrebnim definicijama, pa makar se one prenosile u nove programe copy/paste metodom.

MPLAB asembler sve potrebne definicije cuva unutar standardnog eksternog fajla, koji se u program ubacuje posebnom direktivom (#include <p16F84.inc>). Licno, ne smatram ovakav pristup dobrim, jer otezava programeru razvoj svog stila programiranja (zbog cega PORTA ne bi mogao biti PortA ili A). Vidjao sam npr. zamenu "STATUS,Z" sa "_Z" sto sigurno ubrzava razvoj programa. Ukoliko bi sve potrebne definicije zajedno sa programom bile unutar jednog fajla, kompajler ne bi trazio njegovu definiciju na dva mesta (u p16f84.inc i u program.asm fajlu), vec jedino unutar jednog jedinog .asm fajla. Osim toga, od programera ne bi bilo ista "skriveno".

Kako dobar deo programera (po inerciji i zbog lose snabdevenosti nasih dobavljaca) koristi samo par tipova PIC-a iz cele familije, ne verujem da bi copy/paste metod bio previse komplikovan. Ukoliko vec krenu sa nekim "egzoticnim" (nepoznatim) tipom PIC-a, mogli bi mu sami prilagoditi definicije.
[ korak @ 26.07.2008. 13:19 ] @
Hvala, na trudu da me sto vise uvedete u materiju.

Sve je OK, ali ja ne volim mnogo 'pametne' programe sa mostvom prozora u kojima svasta podesavam da bi onda komapajler to uzimao u obzir. Kada odstampam izvorni kod ta setovanja se ne vide, pa cak i kada ga citam sa monitora, moram da otvaram prozore da vidim sta je kako definisano. Osim toga, sve takve definicije treba snimiti i vezati za odradjeni projekat. Ja sam pristalica da se sve definicije vide u izvornom tekstu programa i da su na dohvat ruke programera. Moze se stvar olaksati, da se sve to ne pise uvek kada se radi sa istim tipom PIC-a, ako se one smeste u modulu (ne include) gde mogu biti definisane po zelji programera. Taj modul bi bio uklucen na pocetku (pre svih modula) glavnog modula. To ne smatram velikim problemom, narocito zato sto onaj koji se opredelio za asembler, taj sigurno zna anatomiju PIC-a koji koristi. Znam da C kompajleri imaju pristup takav de se sve setuje samim izborom tipa MCU-a. Ako imate legalnu verziju softvera, uvek mozete da apdejtujete svoj kompajler za novi MCU. Ja ne zelim da programer stalno zavisi od proizvodjaca kompajlera. Kada ga jednom nabavi on treba da mu je koristan i za novu tipove MCU-a.

Juce sam razmisljao o jednoj stvari koja mi se cini vaznom. Mislim da su ceste greske kada u asenbleru nehotice upotrebite neku varijablu a pri tome niste prekopcali banku za nju. Da li se varam? Pokusavao sam da nadjem resenje da se to ne dogadja i da obezbedim mehanizam da tu kontrolu drzi kompajler. Evo sta mi je palo napamet:

Napraviti strukturu:

SetBank n do <naradna>;

ili

SetBank n do
begin
lista naredbi;
end;

Lista naredbi bi koristila varijable samo iz banke n. Kompajler bi vodio racuna da se u ovoj strukturi koriste samo takve naredbe, a za one iz druge banke bi prijavio gresku. Ako se koriste vise banaka, na primer dve onda bi bilo:

SetBank n do
begin
lista naredbi; //varijable iz banke n

SetBank m do
begin
lista neredbi; //varijable iz banke m
end;

lista naredbi; //varijable iz banke n
end;

Umesto n i m moze se koristiti preddefinisana funkcija BankOf(imeVar) cime ne morate da pamtite u kojoj je banci koja varijabla. Na ovaj nacin kompajler sa SetBank ukljucuje novu banku, a pamti predhodno setovanu banku. Kada naidje na end svoje strukture, on ukljucuje ponovo predhodno setovanu banku. Mali problem se javlja kada se iz SetBank..do strukture skoci negde, onda kompajler gubi evidenciju o aktuelnoj banci. Zato treba asembler da ima sve strukture (if..then..else, repeat..until, whilr..do, case..of i t. d.) kako bi postala nepotrebna naredba skoka.

Interesuje me sta se desava sa bank registrom (pa cak kada je on i u STATUS registru) kada se pozivaju procedure. Mislim da je ovo sa bankama najvaznije pitanje za pouzdano pisanje softvera jer PIC nema kontinualan memorijski prostor.

Sta mislite o ovome.

Pozdrav.

[ sander @ 26.07.2008. 14:15 ] @
Vezano za varijable koje su definisane u ram-u. Ako kod definicije upotrebimo 10-bitnu adresu (16F) koja se sastoji iz 2bit za selekciju banke i 8 bitne adrese registra kompajler bi uvek znao da kada pristupa toj varijabli u kojoj se banci nalazi. Ovim bi se omogucilo i da se urade i "include" moduli sa definicijama specificnim za pojedine kontrolere. Recimo nesto kao:

var Port_A: byte @0x005 sto bi znacilo da smo definisali varijablu Port_A na lokaciji 0x05 u banci 0 koja bi ustvari bila na istoj lokaciji registra PORTA

ili

var Tris_A: byte @0x105 sto bi znacilo da smo definisali varijablu Tris_A na lokaciji 0x05 ali u banci 1 koja je na istoj lokaciji TRISA registra.

ili mozda za bit promenljive:

var RA0: boolen @ 0x005,0

da bi kasnije u programu mogli da napisemo:

Port_A:=0;
Tris_A:=0b11111111;

a kompajler bi automatski postavi0 kod za selekciju banke i pristupio varijabli:

bcf STATUS,RP0
bcf STATUS,RP1
movlw 0
movwf 5
[ korak @ 26.07.2008. 18:02 ] @
Da, ali kompajler nezna koja je stranica trenutno ukljucena i da li treba da je promeni. To je razlog mog predloga.

Za postavljanje varijabli na apsolutnim adresama je obicno:

var
Port_A: byte absolute 0x005
Tris_A: byte absolute 0x105

ovo drugo ne treba tako. Tris_A treba da ima apsolutnu adresa, a kompajler zavisno od tipa PIC-a (velicine stranice) odradjuje broj stranice. Dakle ako je stranica po 128 bajta, treba:

Tris_A: byte absolute 0x85

a kompajler ce da izracuna od 0x85 = 133 sledece 133 div 128 = 1 prva banka, i 133 mod 128 = 5 adresa u banci. Mislim da je ovo konciznije sa aspekta buducih komplikacija.

Pozdrav.

Pauza do ponedeljka.
[ sander @ 26.07.2008. 18:27 ] @
Da upravu si, zanemario sam da banka nema 256 nago 128 b kod 16F serije.
A sto se tice banke mislim da ce morati uvek selekcija banke sem kod nekih racunskih operacija kad kompajler rezervise deo memorije za to i ne izlazi iz odredjene banke, svako testiranje koja je banka aktivna bi samo usporavala rad.
Ako se secate polemike oko snage pojedinih tipova kontrolera zato sam i insistirao da se pod PIC-em ne podrazumeva 16F, tek kada se otkriju unapredjenja koja 18F serija donosi vidljivo je da je razlika izmedju ove dve serije sto se brzine tice prilicna a kamoli poredjenje sa novijim serijama.
[ korak @ 28.07.2008. 13:03 ] @
Da potpuni se slazem, treba ici na 18F kao osnovni, a da usput podrzava i 16F.

Pogledaj moj predlog za rad sa bankama, sta mislis o tome?

Pozdrav.
[ Stojan Trifunovic @ 28.07.2008. 21:52 ] @
Korak, dobar Vam je pristup. I mene nervira podesavanje po vise fajlova i navigacija po prozorima. Nisam najbolje shvatio sta podrazumevate pod modulima, ali pretpostavljam da ce za nov projekat sa istim PIC i podesavanjima biti dovoljno samo iskopirati modul unutar .asm fajla. Sasvim dovoljno i potpuno pregledno.

MPLAB asembler vec ima "banksel" direktivu koja ce postaviti odgovarajucu banku kada joj se doda ime registra (npr. "banksel TRISA").
Ipak, priznajem da bi bilo zgodnije kada bi kompajler brinuo o ovome. Realno, programer ni ne treba znati gde mu se nalazi koja varijabla, pa samim tim ni u kojoj je banci. Pretpostavljam da bi kompajler mogao da na osnovu liste naredbi unutar:
Code:

begin
  lista naredbi;
end;

odredi koji se sve registri tu koriste (opste namene za koje je svejedno, specijalne namene koji su mapirani u svim bankama za koje je takodje svejedno ili pak specijalne namene mapirane samo u odredjenim bankama) i da na osnovu rezultata odredi u koju bi banku bilo najprakticnije staviti koje varijable, kako bi bile optimalno grupisane.

Skok bi sigurno predstavljao problem, ali za sada ne vidim nacina kako bi se mogao resiti, osim kao sto je korak naponenuo strukturom programa koja bi skokove (GOTO) ucinila suvisnim.

U principu raspored registara specijalne namene je takav da se najveci broj uobicajenih operacija moze izvesti unutar banke 0, dok se registri u ostalim bankama dosta redje koriste (uglavnom prilikom pocetne inicijalizacije mikrokontrolera). Tako je moguce koristiti ostale banke jedino u slucajevima kada je to (zbog malo RAM-a u banci 0) neophodno, odnosno ukoliko kompajler proceni da je to neophodno. Svakako bi gore navedeno grupisanje varijabli unutar procedura dodatno olaksalo procenu kompajleru.

Bitovi za odredjivanje banke unutar STATUS registra ostaju onakvi kakvi su bili pre skoka. Znaci, program ce ostati u istoj banci u kojoj je i bio. Skokom se menja jedino Program Counter, a on ne utice na RAM niti na flagove STATUS registra, pa samim tim ni na promenu trenutne banke.
[ Odin D. @ 28.07.2008. 23:51 ] @
Vidim da se povela prica oko banki, pa da dodam i ja poneku, iako mozda ne bas konstruktivnu rijec.
Dosad vidjeni predlozi zvuce zanimljivo, medjutim meni se cini da je od toga slaba vajda. Logicki posmatrano, gdje god se u programu nalazi neko grananje, to je zato sto se u vrijeme kompajliranja ne moze znati kojim putem ce da krene program u vrijem izvrsavanja, inace grananje ne bi ni bilo potrebno ako bi unapred znali kojim tokom ce program da krene. To znaci da se svejedno prije pristupa bilo kojoj varijabli mora izvrsiti prebacivanje na odgovarajucu banku, odnosno ako se to prepusti kompajleru on mora ispred svake varijable dodati "switching" na odgovarajucu banku, cime se ne dobija nista, a dosta se gubi ako se u ubzir uzme koliko razno raznih interrupt-a i grananja moze da bude u prosjecnoj mikrokontrolerskoj aplikaciji. Napraviti algoritam optimizacije rasporeda tih varijabli po bankama za prosjecno komplikovan mikrokontrolerski program bi bio prilicno zametan posao sa sumnjivim rezultatima (meni vec pada na pamet xx uobicajenih slucajeva gdje nikakva optimizacija ne bi pomogla). Za uspjesnu optimizaciju svega toga bilo bi potrebno i znati sa kojom ucestanoscu (ili vjerovatnocom) ce se neki interupt ili funkcija pozivati i sl. a to kompajler ne moze znati osim ako mu programer ne naznaci, a najcesce ne zna ni programer tacno i tako sve u krug. A ako programer mora i o svemu tome da misli, onda u cemu je smisao toga? Imacemo kompajler koji dobro kompajlira samo sto programer dolazi uvece kuci cetvoronoske. Zatim, za uspjesnu optimizaciju trebalo bi koristiti uvijek neki mikrokontroler koji je najmanje 100-200% jaci od minimalno potrebnog kako bi se raspored varijabli mogao optimalno rasporedjivati po bankama, sto bas i nije neki veseo uslov.
Kada bi se taj problem sa bankama kod PIC-a mogao elegantno zaobici, onda to, jel'te, ne bi ni bio neki problem da se oko njega dize tolika prasina. Valjda bi ga i sam proizvodjac vec nekako rjesio ili bar pokusao da rjesi.

Na kraju se sve svede na to da se kolicina razmisljanja kod programera po tom pitanju ne moze smanjiti. Mozete promjeniti nacin na koji se to radi u odnosu na trenutnu situaciju, ali tesko da ce se nesto olaksati.
I meni pada na pamet, onako na prvu loptu, sijaset razno-raznih "rjesenja" tog problema, medjutim cim se to malo izanalizira dolazi se do onoga sto sam vec rekao: moze se napraviti da se drugacije radi, ali tesko da ce se postici da se manje radi.
Infromacija rezolucije 1 bita (banka 0 ili 1) ne moze se predstaviti sa pola bita. To sto se tonski zapis od 50MB moze sabiti u 3-4MB je samo zato sto nase usi ne cuju vecinu toga iz zapisa od 50MB, ali u programu mikrokontrolera nema informacija koje se mogu zanemariti. Tako bar kaze moja logika.

Ako se neko upusti u pokusaj realizacije ovog neizvjesnog poduhvata, u svakom slucaju trebalo bi prvo dobro da izanalizira sta ga ceka, prije nego izgubi suvise vremena da bi shvatio da je sve bilo uzalud. U svakom slucaju, ako neko ima problema sa matematickom analizom izvodjivosti ovog zadatka, moze da uzme neki uobicajeni program od 2-3 hiljade linija pa da samo za taj konkretan program proba da izvrsi tu optimizaciju banki, pa kad vidi kako bi to islo, onda da vidi da li moze da napise logiku za opsti slucaj i sa kakvim rezultatima.

O komercijalnoj stvari svega toga ne treba ni diskutovati: prvo se treba zapitati ko ce to htjeti kod nas da kupi, kad se uzme u obzir da vecina ljudi koji koriste PIC upravo ga i koriste zbog toga sto se tesko masaju za dzep. A ako razmisljate o firmama kao musterijama, pa mislim da su vam sanse priblizno jednake da ih ubjedite da koriste vas kompajler tome da ih ubjedite da koriste vas operativni sistem umjesto Windowsa ili UNIX-a npr. A u vecini slucajeva jedini kupci i jesu firme. Skoro sam gledao cijene nekih C++ kompajlera i cifre su 5-6 hiljada evra. Mislim da ce 99% hoby korisnika radije da radi na industrijski priznatom kompajleru od 5-6 hiljda evra koga je dzaba skinuo sa rapidshare-a, nego da kupi neki legalan relativno nepoznat kompajler za bilo koliku malu sumu.

No, nedajte da vas obeshrabri moje glediste, ja to zbog toga sto mi bude zao koliko se nekad vremena potrosi na nista, a moglo je za to vreme da se napravi nesto (drugo). Valjda zato sto sam ja uvijek u nedostatku sa vremenom....

Izvinjavam se na ovoj digresiji koja je skrenula malo sa teme, ali mozda nekom moze biti od koristi....
Pozdrav svima.
[ korak @ 29.07.2008. 05:58 ] @
Ako znate istoriju nastanka PIC-a onda ce vam biti jasno da proizvodjac nije mogao da resi problem sa bankama, jednostavno PIC se rodio sa bankama i to mu je karakteristika. To je zrtva Harvard strukturi koja nema dovoljno siroku magistralu prema flash-u.

Ja sam napravio razvojni sistem koji je na nivou asemblera (i ima njegovu snagu), a po efikasnosti pisanja softvera se priblizava C-u. Nije mi cilj nikoga da ubedjujem u to, jednostavno diskutujemo. Ako sam ja sa tako definisanim jezikom napisao vise stotina hiljada linija pouzdanog softvera koji radi u nekoliko desedina uredjaja, onda to predstavlja neku vrednost.

Da se vratimo bankama. Opsti cilj je da sve ono sto programer ne mora da radi, i nije do programskog zadatka, radi kompajler. Tako programeru ostaje koncentracija na pisanje softvera, a ne da se dekoncetrise zadovoljavajuci cudi mikrokontrolera. Kod PIC-a su to banke i zato o njima pricamo.

Uzmimo za primer 16F87x i definisimo prostor za varijable:
Code:


var bank 0 [0x20..0x6F]
  <deklaracija varijabli >

var bank 1 [0xA0..0xEF]
  <deklaracija varijabli >

var bank 2 [0x110..0x16F]
  <deklaracija varijabli >

var bank 3 [0x190..0x1EF]
  <deklaracija varijabli >

var general [0x70..0x7F]
  <deklaracija varijabli >


Stavio sam da svaka banka ima definisan prostor rezervisan za nju. To zato jer mi se cini da razni tipov imaju drugaciji ovaj prostor. Programer samo treba da bliske varijable, one koje zajedno ucestvuju u nekim operacijama smesta u istu banku. To nije tezak zadatak. Koriscenje bi izgledalo:

Code:

  SetBank 0 do
  begin
     <operacije sa varijablama banke 0>
     
     SetBank 3 do
     begin
        <operacije sa varijablama banke 3>

        SetBank 0 do <jedna operacije sa varijablom banke 0>

        <operacije sa varijablama banke 3>

        SetBank 2 do
        begin
           <operacije sa varijablama banke 2>
        end;

        <operacije sa varijablama banke 3>
     end;

    <operacije sa varijablama banke 0>
  end;


SetBank n do postavlja banku n i ona vazi u celoj strukturi begin..end. Na end se vraca predhodno postavljana banka. Ako iza do nema begin..end, onda se koristi samo jedna naredba iz definisane banke sa SetBank. Vidi se da se strukture SetBank..do mogu da gnjezde. Upotrebom varijable iz neodgovarajuce banke, zahvaljujuci ovakvoj strukturi, dozvoljava kompajleru da prijavi gresku. Greska jedino nece biti prijavljena ako se koristi varijabla iz banke general. Ovo je nesto najjednostavnije sto moze da se uradi, a da se omoguci kompajleru da na prost nacin kontrolise upotrebu i manipulisanje sa bankama na ispravan nacin.

Pozdrav.
[ Stojan Trifunovic @ 29.07.2008. 07:08 ] @
@Odin D.

Ima u vasoj analizi par propusta.

Pre svega nije uopste potrebno brinuti o bankama prilikom interapta. STATUS registar snima se sa ostalim, tako da se snima i trenutna banka. Takodje se vraca prilikom povratka. Oni su znaci eliminisani kao eventualni uzrok problema.

Dalje, prebacivanje banke se ne mora vrsiti za svaki registar. Taman posla da bi iko to zeleo tako uraditi. To jeste najlakse implementirati, ali daleko od toga da je to dobro resenje. Takvim pristupom krajnji program bi bio i sporiji i duzi, a to svakako nije cilj. Ukoliko je odredjeni kod (ili deo koda) koncipiran u obliku jasno definisanih procedura (kako je predlozio korak) onda je dovoljno da kompajler odabere odredjenu banku neposredno pre procedure. Svi registri korisceni unutar nje morali bi (zbog vece brzine) biti u istoj banci, a eventualni neophodan prelazak (zbog registara specijalne namene) bi se mogao resiti preko privremenog prelaska i nakon zavrsene operacije povratka.

Onda, grananje. To je verovatno i najveci problem (pogotovu kod 18F serije), ali ipak postoji konacan broj instrukcija kojima se moze realizovati grananje. U 16F seriji to su incfsz, decfsz, btfsc, btfss i bilo koja instrukcija koja direktno menja PCL (npr. addwf PCL,F).

Kako prilikom grananja incfsz, decfsz, btfsc, btfss instrukcijama kompajler pre nego sto dodje do njih zna u kojoj je banci, bez obzira na to gde skocio, nalazice se u potpuno istoj banci. Tako nema vece potrebe za njenom promenom.

Najveci problem moglo bi biti grananje direktnom izmenom PCL registra (cesto korisceno u tabelama ili ON W GOTO operacijom). Medjutim, i njihova struktura mogla bi se standardizovati unutar procedure.

Znaci, ukoliko kompajler zakljuci da nema grananja unutar procedure (instrukcije grananja ukoliko ih ima imaju skokove unutar iste procedure ili uopste nema instrukcija grananja) moze kompletnu proceduru procesirati kao obican linijski kod, a za svaki linijski kod dovoljno je (uz ranije navedene izuzetke) samo jednom izabrati banku.

Optimizacija rasporeda varijabli jeste problem, cak, rekao bih najveci izazov za kompajler. Moguce je da bi resenje bilo da kompajler isproba svaku mogucu kombinaciju banki i izabere onu koja pruza najmanje prelaza, i koja je tako generise najkraci program. Medjutim, ni to nije dovoljno dobro. Kao sto Odin D kaze nekada je brzina bitnija od velicine programa. Kompajler bi onda morao znati i koje procedure treba sto brze izvrsavati, a koje mu nisu toliko bitne, i na osnovu tih informacija dodatno optimizovati program. Prilicno zamrseno.
Mozda bi ipak bilo najjednostavnije izostaviti ovu mogucnost kompajlera i prebaciti vruc krompir programeru. Ako on ne zna kako optimizovati banke, nikakav kompajler mu ne bi mogao pomoci. Vidim da korak u zadnjem postu preferira upravo ovakav metod.

MPLAB na primer ima mogucnost generisanja programa iz vise fajlova (prog1.asm, prog2.asm, prog3.asm...) linkerom. Medjutim, i tu programer bira banke rucno.
Primenjen pristup mi se svidja jer se unutar svakog od tih fajlova definise koje se varijable koriste unutar njega, da li su interne za taj deo programa (fajl) ili im se moze pristupati i spolja, kao i da li se smeju prebrisati njihove vrednosti prilikom poziva neke druge procedure (sto stedi RAM memoriju). Takodje je potrebno definisati i tacku (tacke) ulaska.
Na taj nacin programer mora brinuti o bankama, ali svaki fajl ima standardnu deklaraciju poput zasebne procedure.
Nije mi toliko bitno sto se koristi vise fajlova (stavise, to moze i da smeta) koliko precizna i jasno definisana grupacija svih parametara koji se koriste unutar procedure. To poboljsanje je odmah uocljivo.
Sledece poboljsanje u ovakvom sistemu je sto se ne mora pamtiti adresa pocetka RAM-a i sto se unutar fajla (procedure) moze izabrati da li ce se za varijablu koristiti obican RAM ili onaj mapiran u svim bankama. Programer na osnovu svojih konkretnih potreba moze izabrati resenje.
Jos jedno poboljsanje je mogucnost linkera da brine o rasporedu varijabli i kompletnog programa u memoriji. Moje je da pozovem fajl (proceduru) navodeci njenu labelu, a linker ce se brinuti o ostalom.
Najbolja od svega je mogucnost koriscenja labela sa istim nazivom unutar razlicitih procedura. Ukoliko te labele nisu definisane kao eksterne, nemoguce im je pristupiti spolja.
Ovaj sistem mozda deluje sasvim solidno, i bio bi da mu je linkerska skripta malo "pametnija". Nazalost nije.


@korak

Ovo sto ste do sada pisali odnosi se jedino na linijske kodove (begin end) i kao takvo je sasvim u redu. Reseno je pozivanje, resene su banke. Kako mislite resiti grananje?
[ korak @ 29.07.2008. 08:33 ] @
U granjanjima tegeba izbeci GoTo, vec implementrirati strukture if..then..else, repeat..until, while..do i case..of. Na taj nacin kod ostaje 'zarobljen' u tim strukturama i moze se omoguciti kompajleru da kontrolise banke. Procedura mora biti definisana kao posebna programska struktura, a ne kao klasican podprogram. Onda se moze, posle poziva procedure, obnoviti ona banka koja je bila ukljucena pre poziva procedure. Na ovaj nacin, procedura moze koristiti razne banke, ali kada se vrati tamo odakle je pozvana, bice aktivna banka koja je to bila i pre poziva procedure. Cela caka je u tome da kompajler zna sa kojim bankama se radi. Na mestu poziva procedure on to zna ako se koristi struktura koju sam predlozio SetBank..do, pa ce biti u stanju da posle poziva procedure obnovi istu banku. Moze se desiti da to niije potrebno, ali kompajler to ne moze znati.

Moduli nisu include fajlovi. To su posebne programske strukture slicne programu samo sto imaju drukcije zaglavlje (unesto program imaju simbol unit) i imaju simbol implementation da bi sve iza ovog simbola bilo privatno za modul.

Iako nisam specijalista za PIC, cini mi se da je sve ovo izvodljivo i da moze biti vrlo efikasno.

Pozdrav.
[ Stojan Trifunovic @ 29.07.2008. 10:33 ] @
Mislim da bi jos jedno poboljsanje bilo moguce. Kazete da kompajler ne zna da li mu je potrebna izmena banke ili ne. Kako ne zna, kada mu je unapred definisana?
Code:

  SetBank 0 do
  begin
     <operacije sa varijablama banke 0>
     
     SetBank 3 do
     begin
        <operacije sa varijablama banke 3>

        SetBank 3 do
        begin
           <operacije sa varijablama banke 3>
        end;

        <operacije sa varijablama banke 3>
     end;

    <operacije sa varijablama banke 0>
  end;

U ovom slucaju procedura najvece dubine koristi istu banku kao i prethodna. Na osnovu toga kompajler moze lako zakljuciti da nema potrebe za promenom banke prilikom ulaska niti prilikom povratka.

Mnogo veci problem predstavljao bi poziv iste procedure sa dva (ili vise) razlicita mesta. Onda kompajler ne bi znao iz koje banke je pozvana procedura, tako da bi morao izvrsiti prelaz pri svakom pozivu procedure. Tacnije, mogao bi ako bi poredio banku svake procedure nizeg nivoa koja je poziva. Ipak, mislim da bi bilo bolje kada bi se programeru prepustio izbor. 2 instrukcije vise pri pozivu i jos dve pri povratku mozda deluju zanemarljivo, ali sta ako se bas ta procedura koristi u petlji kasnjenja!

Za strukture, npr. IF...THEN...ELSE mislim da bi trebalo najpre definisati sta se testira (bit, bajt, word...) a zatim napraviti posebne algoritme za svaki pojedinacni slucaj, kao i za svaku pojedinacnu operaciju (<, >, =, <=, >=, <> i eventualno logicke operacije). Sve ovo radi bolje optimizacije.
REPEAT...UNTIL struktura mogla bi koristiti iste delove koda za testiranje kao i IF...THEN...ELSE.
WHILE...DO struktura mi nije poznata (sta cu kada nisam ucio Paskal), ali pretpostavljam da je slicna REPEAT...UNTIL strukturi.
CASE...OF struktura bi se najjednostavnije implementirala koriscenjem updata PCL sa ON W GOTO metodom (uz obaveznu proveru i eventualni update PCLATH u slucaju prelaza preko 256b granice).

Sve ovo i meni deluje potpuno izvodljivo. Buduci da vec imam deo optimizovanih i jednostanih algoritama za testiranja (doduse samo za cele bajtove) ocekujte pomoc kada dodjete do konkretne implementacije struktura.
[ Odin D. @ 29.07.2008. 17:02 ] @
@korak

Kad sam rekao da PIC ima problem sa bankama, nisam mislio da je to nesto sto se neplanski pojavilo, pa sad kao u tom smislu treba nekako da se rjesava. PIC se jeste rodio sa bankama, samo u to vreme nije bio sa flash-om :)
Mislio sam na probleme koje memorijski prostor sa bankama pravi kod pisanja kompajlera i programa, i to je nesto sto je poznato i karakteristicno za PIC (a i neke druge arhitekture sa bankama).

(Za one citaoce koji mozda ne znaju zbog cega se koriste banke (kao sto ni meni nije bilo jasno kad sam nekad davno prvi put uzeo PIC16f84 datasheet, jer tamo nigdje nije pisao razlog tog marifetluka): banke se koriste da bi se povecao adresni prostor bez fizickog prosirenja adresne magistrale. Inace to ne mora biti obavezno uslovljeno hardward arhitekturom, jer hardward arhitektura nigdje ne propisuje kolika mora biti sirina adresne magistrale. Ako se napravi sira magistrala nema potrebe za bankama, ali to ima druge konsekvence sto se tice hardverskih zahtjeva.

Sto se tice kvaliteta tog kompajlera kojeg spominjete, moram da kazem da u mom komentaru uopste nisam imao namjeru da o tome nesto zakljucujem, sto je i nemoguce, jer ga nisam vidio. Jedino na sto sam se ja osvrnuo je opsta primjenjivost kod sireg kruga korisnika, moze i da se kaze npr. komercijalna strana svega toga. Posto se citava prica nalazi na javnom forumu, pretpostavio sam da bi i o toj strani price moglo ponesto da se kaze. A mozda bi i Vi stekli bolju sliku o kvalitetu tog kompajlera, ako biste probali taj Vas kompajler da pustite na trziste, pa da vidite reakcije drugih ljudi. Ovako sve ostaje misljenje jednog covjeka (a posto svi roditelji o svojoj djeci misle sve najbolje, to misljenje se vodi kao subjektivno barem dok ga ne potvrdi jos poneko :). Mozda je moguce da taj kompajler savrseno odgovara Vasim potrebama, ali ako nema nikakve informacije o iskustvima drugih ljudi koliko je to onda relevantno za bilo koga osim Vas?

U ostatku teksta kad sam govorio o kompajleru i bankama mislio sam iskljucivo na optimizaciju rasporeda varijabli po bankama, kako bi se ubrzalo izvrsavanje programa ili maksimalno smanjio broj preskakanja iz jedne banke u drugu, a po mogucstvu da se programer oslobodi razmisljanja o tome.
Ono sto ste napisali uglavnom je samo drugi sintaksni nacin da programer napise istu stvar koju u drugim nekim kompajlerima radi npr. pomocu makroa, a nikakve optimizacije nema. Jedino sto bi se donekle moglo podvesti pod optimizaciju je smjestanje "bliskih" varijbli u istu banku, ali to je trivijalno, to programer ionako moze da radi sa mozgom na ispasi. Znaci, nista znacajno nije skinuto sa grbace programeru, a sto je jos vaznije - ne mora da znaci i da je svaki put to dobro!

Dakle, opet naglasavam, da ne bude zabune: ne komentarisem sintaksu i to da li je ona povoljnija/laksa/citljivija/logicnija/razumljivija...itd. (meni je ionako svejedno, kad se naviknete na nesto nemate tih problema), nego optimizaciju. Ako se radi o citljivosti onda bi najlakse bilo izbaciti naredbe za setovanje banke, vec obojiti blok programa bojom banke u kojoj se radi, a u slicnom tonu i varijable iz te banke, pa ako se negdje boje ne slazu, sve bi se fino vidjelo, ali to bi svi smatrali za neozbiljno... Jos kad bi pogresno koriscene varijable blinkale...
Tih tekstualnih kompajlera ima vec prilicno, tako da je tesko dici glavu iz te poplave, medjutim kad bi neko zapeo da pravi neki graficki programski jezik, ja bih mu svaki dan slao bezrezervni mail podrske...


@Stojan

Ipak imam dovoljno iskustva da ne mislim da se po povratku iz interrupt-a mora ponovo selektovati banka, kao i da ne treba staviti selekciju banke prije svake varijable/registra. (Medjutim, ako se dobro sjecam, PIC16 serija nema bas narocito dubok stack, pa se za programe koji su zahtjevni u pogledu prekida ionako mora softwerski realizovati, pa prica o brzini gubi smisao).
Nesporazum ocigledno nastaje zbog razlicitih perspektiva iz kojih posmatramo problem. Ako razmisljamo o mikrokontrolerskom programu tipa: ugasi neku sijalicu kad dan svane, upali je kad se smrkne, onda ste Vi u pravu. Medjutim u tom slucaju ja ne vidim razlog praviti neki kompajler za pisanje programa tog nivoa. Tih Markovih, Dejvovih, Joe-vih, Perinih, Zikinih kompajlera za PIC ima vec sijaset na internetu.
Ako se ne radi o trivijalnom programu, u 80% slucajeva interupt ce pozivati neku funkciju, a ta funkcija mozda jos ko zna koliko. Uzmite obican senzor pokreta, detekcija pomjeraja nekog objekta ce izazvati interupt koji ce poceti da racuna koordinate pozivanjem trigonometrijskih funkcija iz math biblioteke, pa ce se pozivati funkcije za crtanje na displeyu da bi se to npr. nacrtalo, pa ce se pozivati funkcije za prenos podataka na displey, serijsku vezu sa senzorom i sl.
Ono sto prosjecnog potencijalnog korisnika zanima je sta cete vi da radite sa svime time i kako cete da uskladite vas kompajler sa rasporedom varijabli koje definisu koriscene gotove biblioteke? Hocete li napisati sve standardne biblioteke ponovo ili sta? Meni npr. ne bi ni palo na pamet da za svaki displey koji kupim ja sam pisem biblioteku, ili da pisem sin() i cos() funkcije iznova kad mi zatrebaju, ili da redefinisem funkcije za CAN, USB ili npr. neku drugu vezu. A ako pisem program tipa: kad ukucam ova tri broja brava se otkljuca, inace jok, pa to mogu da radim i u masincu.

Ako se manemo hobistickih projekata, onda vrlo ozbiljne stvari treba rjesiti, a ja pisem ovo jer sam stekao utisak da poneko nije svjestan sta to sve podrazumjeva.

U svakom slucaju, ako neko razmislja o optimizaciji programa u odnosu na memorijske banke moze pogledati dokument prikacen uz ovaj post.

Pozdrav!
[ Stojan Trifunovic @ 29.07.2008. 23:47 ] @
U redu, u redu. Nismo se razumeli.

Poduhvat jeste obiman. Tu nema sumnje. Medjutim, ono sto korak pokusava (bar kako sam ja to shvatio) je da napravi kompajler koji predstavlja ekstenziju asemblera, koji ce biti razumljiviji od asemblera, kojim ce se programi pisati brze nego u asembleru, a koji ce ipak sadrzati svu njegovu snagu u pogledu optimizacije i brzine.

U pogledu pisanja biblioteka se slazemo. Ni meni ne pada na pamet da ponovo izmisljam toplu vodu. Ako se koristi LCD ili sinus dovoljan je samo Copy/Paste obicnog proverenog .asm koda i resen problem. Medjutim, to bi trebalo biti moguce i u korakovom kompajleru, sa tom razlikom sto ce biti potrebno dodati deklaracije procedura i selekciju banke.
Code:

  SetBank 0 do
  begin
     <asemblerski program za isracunavanje sinusa>
  end;

Tako se kompletna procedura izracunavanja sinusa nalazi u jednom bloku. Ista struktura mogla bi se primenjivati i unutar interapta. Dobro, ovo jeste najjednostavniji moguci model, ali programer bi u njemu mogao grupisati registre tako da se registri vise procedura koje se izvrsavaju u petlji ili linijski nalaze u istim bankama. Definisanjem varijabli unutar procedura upravo je omoguceno njihovo lakse pracenje i (rucno) grupisanje kao na slici 7 sa sedme strane vaseg priloga.

Sigurno i sami uocavate prednost ovakvog grupisanja. Najveci broj programa uglavnom periodicno poziva ovako definisane procedure. Ukoliko vec postoje gotove biblioteke (ili u ovom slucaju procedure) za sav moguci hardver i softver (displej, serijsku vezu, matematicke funkcije...), korakov kompajler bi omogucio brze njihovo povezivanje. Kako to? Pa razumljivije je i brze (bar meni) pratiti program i pisati npr.
if W > 50 then ...
nego direktno u asembleru oduzimati pa testirati Carry flag. Osim toga zbog jasnih granica procedura celokupan program je pregledniji.

Svakako da je ovo moguce (stavise, vec postoji) i u PIC Basic-u, ali kod koji on generise uopste nije optimizovan. Kod njega se pre bas svakog registra selektuje odgovarajuca banka. Ne znam C, ali mi izgleda (sudeci po korakovim postovima) da i on pati od lose optimizacije.

Prilog koji ste postavili pruza odlican metod optimizacije, ali ne bih rekao da je objektivan po svojim rezultatima kada se uporedi sa asemblerskim kodom. Naime, za testiranje je izabran asemblerski kod generisan HI-TECH PICC kompajlerom, a banke registara su nasumice, rucno odabrane. Da je program pisan u asembleru svakako bi se povelo racuna o sto manje prelaza, pa bi i postignuta poboljsanja dobijena optimizacijom bila srazmerno manja. Ipak bi ova optimizacija bila previse komplikovana za implementaciju. Na kraju krajeva najbolju optimizaciju moze pruziti sam programer jer kompajler ne zna koje se procedure trebaju izvrsavati maksimalnom brzinom (za optimizaciju brzine), a koje ne (za optimizaciju koda).
[ sander @ 30.07.2008. 06:44 ] @
Kako sam ja razumeo koraka je pricamo o kompajleru za 18F seriju i o nacinu za smestaj varijabli. Kao sto sam ranije govorio, 18F serija mikrokontrolera moze direktno bez selekcije banaka da kontrolise donju polovinu banke 0 (128b) i jednu celu banku 1-14 kao i kompletne SFR registre. To je vise nego kompletan RAM kod 16F serije. Ako dodamo i 3 registarska para za indirekno adresiranje koji kontrolisu celi adresni prostor RAM-a i uz njihovo pametno koriscenje velicina memorije kojom bi se brzo pristupalo se u mnogome povecava.
Ako govorimo o 16F seriji tu se stvari malcice komplikuju. Korakova ideja nije losa ali ne znam kako bi se pokazala u praksi. Mozda nije lose pogledati kako su neke stvari resene kod konkurencije i njihovih basic, pascal,c .. kompajlera. U krajnjem slucaju, kompajler bi mogao da odredi koliko koji program ima zahteva prema smestaju varijabli pa da nesto od toga optimizuje a nesto koristi uz menjanje banaka, neki kompromis. Cak i da se pristupanjem varijabli uvek menja banka i to nam zbog brzine pravi problem uvek se moze koristiti kontroler koji ce moci to raditi brze, cena tu ne igra nikakvu ulogu, jedino mozda progrmerova nesigurnost zbog nedovoljnog poznavanja novijih serija.
[ korak @ 30.07.2008. 07:29 ] @
Odin D.

Uvodjenje banaka ne smanjuje adresnu magistraku. Adresna magistrala uvek mora da odgovara kapacitetu memorije. Valjda shvatas da se kod 16F uz 7 bita adrese dodaju jos 2 bita banke na mestu najvece tezine i tako formira 9-to bitna adresa koja moze da adresira 2KB memorije. Banke su uvedene da bi se smanjila duzina koda naredbe koja sadrzi adresiranje memorije. Harvard struktura moze da maksimalno razvije svoje dobre osobine samo ako je duzina koda naredbi koje baradaju sa memorijom iznosu 24 bita. Dakle flash mora da ima 24-o bitnu magistralu podataka. Ali postoje naredbe kojima ne treba 24 bita, i kod njih je to cist gubitak memorije. Kod 8-o bitnih mikrokontrolera je nadjen kompromis, na jedan nacin kod 8051 a na drugi kod PIC-a. DAkle, to su pravi razlozi.

Stojan Trifunovic je potpuno razumeo moju teznju, i ja mu se zahvaljujem na tome. Ti si preneo diskusiju na neko drugo polje. Govoris o optimizaciji prilikom rasporedjivanja varijabli po bankama. Naravno, to bi bilo najbolje, i to mora da se uradi u visim programskim jezicima, ako se zeli dobar kompajler. Zasto tamo to mora? Pa zato sto su ti jezici standardizovani da bi bili prenosivi. Nije dozvoljeno uvodjenje novih pojmova koji su specificni samo za neki mikrokontroler, deklaraciija varijabli mora biti jedinstvena i otud potrebe za pomenutom optimizacijom. Asembler nije prenosiv i on se pise za konkretan mikrokontroler i dozvoljeno je da se uvode novi pojmovi i strukture da bi on bio sto laksi za programiranje uz povecanje efikasnosti i pouzdanosti.

Izrazavajuci sumnju u ono sto radim vec 20 godina a ne videti to nije bas dobronamerno. Na kraju krajeva, ja radim sa Motorolom i nemam problem sa bankama. Cilj mi je bio samo da svoje iskustvo u razvoju komapajlera (i PASCAL kompajlera) podelim sa drugima, mladjima koji bi dobili ideju da i sami naprave nesto korisnoza svoj mikrokontroler. Mozes se pitati zasto ne govorim o PASCAL kompajleru. Vrlo prosto, C je neprikosnoven za programiranje mikrokontrolera, Napraviti PASCAL za jedan mikrokontroler nema smisla, jer kako cu iskoristiti njegovu osobinu prenosivosti, morao bi da razvijem PASCAL i za druge mikrokontrolere, a to je ogroman posao. Osim toga i C i PASCAL manje efikasno koriste resurse mikrokontrolera od asemblera, drukcije receno nemaju snagu asemblera. Zatim, kada nesto napisano na asembleru, pri cemu koristim i neke dosetke da bi kod bio kraci i brzi, pa to onda napisem na C-u, dobijem deprimirajuci rezultat. Zato sam odlucio da zadrzim snagu asemblera, a njega samog da popravim, koliko je god to moguce kako bi pobiljsao efikasnost pisanja programa i pouzdanost napisanog programa. To sam u speo sa mojim asemblerom za MC908.

U najboljoj nameri zeleo sam da dam neke ideje kako bi se nesto slicno uradilo i za popularni PIC. Dobronamerni ce to razumeti kao pozitivan napor, ali ja ne insistiram, ko nece neka ostane u svojoj ljusturi. Postavio si pitanje da li sam to komercializovao. Moja firma se bavi proizvodnjom raznih uradjaja, a ne razvojnih alata. Medjutim od prve verzije mog asemblera ziveo sam 2 godine (na prelazu 80-90 godine) i oni koju su imali iskustva sa asemblerima bili su odusevljeni, a oni koji nisu imali to iskustvo mislili su da asembleri trebaju da budu takvi. Taj kompajler je bio za HC11.

Vec treci put ponavljam da u asembleru postoje moduli. Vec imam zbirku modula za LCD, USB, RS232, matematiku u pokretnim zarezu, za rad sa stringovima i t. d. Kada mi nesto od toga treba, samo ukljucim modul i koristim vec razvijene i proverene funkcije i procedure.

Ako neko ima zelju da nastavimo caskanje o ovoj temi, ja sam raspolozen za to, ali necu odgovarati onima koji imaju oportuni stav klanjajuci se bozanstvu zapadne tehnologije a nipodastavajuci svaki kreativni napor ovde. Pa, zaboga, ovde se radi samo o idejama koje se mogu implementirati u neki bolji asemblerski kompajler za PIC. Zasto je bolje kada nas mladi strucnjak to radi za neku stranu firmu, a nije dobro ako to radi ovde na svoju ruku (tu ne racunam sebe, ne spadam u mladje). Muka mi je od takvog pristupa jer sam se uverio bezbroj puta u nedorecenim proizvodima ili proizvodima sa zakrpama koji su dosli sa zapada. Koliko sam gresaka nasao u njihovoj tehnickoj dokumentaciji i t. d. Narocito je interesantno kada ime se obratis i ukazes na gresku, dobijas odgovor kao da si idiot.

Pozdrav svima.

[ Stojan Trifunovic @ 30.07.2008. 11:56 ] @
@sander

Da vidimo! Sto se tice konkurencije u vidu MPLAB asemblera i njegovog relokativnog moda situacija je sledeca.
Iz glavnog programa koji jedini sadrzi apsolutne adrese reset i interapt vektora pozivaju se svi ostali (relokativni) programi.
Struktura mu je sledeca:
Code:

        list      pf628a            ; list directive to define processor
        #include <p16f628a.inc>        ; processor specific variable definitions

        ;; registers
DATA_VARIABLES_BANK1       UDATA      0x20
msec    res     1; milkisekunde unutar jednog registra
sec     res     1; sekunde unutar jednog registra
min     res     1; minuti unutar jednog registra

        extern  _interrupt      ; Interapt rutina - nalazi se u eksternom fajlu
        extern  _init_hard      ; Inicijalizacija hardvera - u eksternom fajlu
        extern  _init_soft      ; Inicijalizacija softvera - u eksternom fajlu
        
        global  msec, sec       ; registrima milisekunsi i sekundi mogu pristupati i
                                ; eksterni programi, ali ne mogu npr. registru minuta

        
Reset_vector    CODE 0x00       ; Start programa - ovako je definisana apsolutna adresa
        goto    _main           ; Odlazak na glavni program

Int_vector      CODE 0x04       ; Start interapta - isto sa apsolutnom adresom
        goto    _interrupt      ; Odlazak na interapt rutinu

MAIN    CODE                    ; Ovako je definisan programski kod koji ce linker sam razmestiti

_main
        call    _init_hard
        call    _init_soft
....


end

Osim jedine dve potrebne apsolutne adrese (za interapt i reset vektor) linker ce povezati sve ostale CODE delove u celinu, po sopstvenim setovanjima.
Tacke ulaska u potprograme i programe "spolja" moraju se prethodno definisati "ekstern" direktivom. U ovom slucaju to su programi sa labelama _interrupt, _init_hard i _init_soft, bez obzira gde se nalazili. Moguce je pozivati i delove eksternog programa (npr. _init_soft moze biti potprogram unutar fajla sa _init_hard delom).

Registri se mogu definisati ili u ovom fajlu ili pak u eksternim fajlovima, medjutim moraju im biti definisana pripadnost odredjenim blokovima pre nego sto se odredi da li ce im biti dozvoljen pristup spolja. Definisu se unutar UDATA (za sukcesivne adrese), UDATA_SHR (za registre deljene izmedju svih banaka) ili UDATA_OVR (za registre ciji se sadrzaj sme obrisati odmah nakon izlaska iz tog dela programa - fajla, i kasnije iskoristiti za druge programe - fajlove). Svim ovim blokovima moguce je rucno odrediti apsolutne adrese (kao sto je uradjeno za UDATA sekciju), ali moguce je i tu obavezu prepustiti linkeru (iako ce on verovatno - nisam probao za sve varijable izabrati banku 0, sto moze dsovesti do veoma komplikovanog pronalazenja problema).
Izbor odgovarajuce banke i njihova promena znaci u potpunosti su prepusteni programeru.

Oni registri koji se koriste "spolja" moraju biti definisani "global" direktivom. U ovom slucaju to su msec, sec, ali ne i min.

Struktura eksternog fajla je sledeca.
Code:

        #include <p16f628a.inc>        ; processor specific variable definitions

TEMP_VARIABLES     UDATA_OVR
temp1  res     1 ; privremeni registri - koriste se samo u ovom
temp2  res     1 ; fajlu i nakon izlaska mogu biti prebrisani

SHARED             UDATA_SHR
sh1    res     1 ; registar koji se moze deliti izmedju svih banaka

        global _init_hard ; oznacava labelu dostupnu spolja.
        extern  msec, sec, sporta, sportb ; msec i sec su ranije definisani unutar
        ; main fajla, a sporta i sportb definisani su unutar nekog drugog eksternog fajla.
        global  sh1 ; registar je definisan u ovom fajlu, ali mu se moze pristupati i spolja.

INIT_HARD       code
_init_hard
        banksel TRISA
        movlw   b'00000000'     ; svi pinovi su izlazni
        movwf   TRISA           ;

        ...

        
        call    Petlja
        ...
Petlja
        ...


        
        return
        end


Sto se tice flasha struktura eksternog fajla je takva da su u njoj strogo definisane labele kojima se moze pristupati spolja (_init_hard), dok su sve ostale interne za taj fajl (npr. Petlja), i samim tim nevidljive spolja.

Za varijable je takodje strogo definisano kojima se moze pristupati spolja, kojima ne, i koje su interne za taj fajl i mogu biti ponovo inicijalizovane i koriscene za neku drugu proceduru po izlasku. Ova zadnja mogucnost dosta pomaze (It is an ideal way of declaring temporary variables since it allows multiple variables to be declared at the same memory location. This directive is similar to udata, except that it allows you to reuse data space by "overlaying" one data area on another. It is used for temporary variables, as each data section may overwrite (and thus share) the same RAM address locations.).


@korak

Lakse malo covece! Pa lepo je Odin D. stavio smajlija. A i dao je prilicno konstruktivan pristup implementaciji promene banaka, iako teak za konkretnu implementaciju u okviru kompajlera. Nazalost, kako bi i u tom pristupu trebalo zbog maksimalne moguce optimizacije (code vs speed) definisati koje procedure trebaju biti brze a koje ne, ipak mislim da bi bilo bolje prepustiti programeru brigu oko promene banaka. Razvoj kompajlera bio bi brzi i daleko jednostavniji.
Inace, Odinova ideja sa oznacavanjem varijabli u kodu razlicitom bojom od koda deluje mi neverovatno simpaticno.
[ sander @ 30.07.2008. 16:15 ] @
@Stojan

Razumeo sam i tebe i Korak-a dobro i OK je to sto ti govoris. Definisati varijable kojim pristupa celi program (globalne) ili samo u okviru procedura (podprograma) je ok ako se one mogu razvrstati tako, sta se desava ako imas vise globalnih varijabli, nizove, stringove ili neke slozenije tipove koji ne mogu zaposesti samo jednu banku, oni se nece moci uskladiti u neki sablon ili u tom slucaju i nece biti optimizacije? Zato sam i napomenuo 18F seriju koja moze to lakse i jednostavnije da proguta. Uvek programer u asembleru moze da sam optimizuje koje varijable staviti gde ali zar sa stanovista programera ne bi bilo lakse da ako to nemora da o tome i ne razmislja i da to kompajler radi za njega.
[ Odin D. @ 30.07.2008. 17:29 ] @
@korak

pa dobro, majku mu, ja izgleda uvijek ispadam neki dezurni namcor cim postavim poneko pitanje koje ne ide kud i svi turci. Nije u redu odmah proglasavati nekoga nedobronamjernim i zacaurenim ako nema isto misljenje.

No, da kazem nesto o konkretnim pitanjima sa teme, bez uvijanja forme (ali ipak dobronamjerno):

9-bitna adresa i 9-bitna magistrala su babe i zabe. 9-bitna adresa je logicki pojam, a 9-bitna magistrala je fizicki pojam. Ako je kod PICa ta MAGISTRALA 7-bitna kako kazes, sa dodatna 2 bita kojima se programer zamajava se dobija efektivna 9-bitna ADRESA. Da bi se bez banaka mogla imati 9-bitna adresa, onda bi fizicka magistrala morala biti sa 9 linija, odnosno morao bi chip hardverski da se prosiruje. Posto je PIC 8-bitna masina, da bi mogao da radi sa 9-bitnim adresama fizicki, morao bi znacajno hardverski da se mijenja to jest da bude 9-bitni. Zbog toga se koristi implementacija memorijskog prostora sa bankama da bi se hardverska magistrala zadrzala na nivou procesora, iako se adresni prostor povecava iznad mogucnosti 8-bitne aritmetike.
Dakle, BANKE SE IPAK KORISTE DA BI SE SMANJILA FIZICKA MAGISTRALA u odnosu na ZELJENI ADRESNI PROSTOR koji prevazilazi mogucnosti npr. 8-bitne, 16-bitne itd masine.
A to sto si napisao da se koriste da bi se smanjila duzina koda naredbe koja sadrzi adresiranje memorije, to mozda moze biti samo nus pojava kod nekog procesora, ali u principu nema nikakve veze sa koriscenjem banaka i pravi razlog je onaj sto sam naveo gore.
I opet cu da kazem, da to nema narocito veze sa harvardskom arhitekturom. Sve sto harvardska arhitektura podrazumjeva je odvojen memorijski prostor za program i podatke i to je sve. Niko tu ne spominje nikakve sirine naredbe od 24 bita i sl. Harvardska arhitektura se srece svuda od 4-bitnih mikrokontrolera do specijalizovanih grafickih procesora, PC procesora i superskalarnih procesora, gdje su naredbe siroke od 4 pa do 256, pa cak i vise bita, gdje si ti tu iskopao bas sirinu od 24 bita i kako si dosao do nje kao karakteristicne za harvard arhitekturu to mi nije jasno.
Dalje, sa 9 bita moze da se adresira 512 lokacija, a ne 2K, a memorija za podatke je implementirana kao RAM, pa ne vidim kakve veze to ima sa flash memorijom koju navodis. Flash memorija kod PIC16 je za program i tu postoji 13-bitni PC koji adresira 8K mem. lokacija za program (ako se ne varam te lokacije su 14-bitne, odnosno programska rijec je siroka 14-bita), a banke se odnose na memoriju za podatke.

(Samo da napomenem da se pojam "bank" u svijetu hardvera i u vezi sa adresnom arhitekturom koristi u vise razlicitih konotacija, i iz vise razlicitih razloga, ali za ovaj slucaj koristi se u kontekstu koji sam gore napisao. To navodim za slucaj da ne iskopa neko nesto sto se slucajno zove "bank" (npr. kod vektorskih procesora ili za memory interleaving, pa da ide bez potrebe u off-topic.)

E sad sto se tice tih "dobrih namjera" prema mladjim generacijama, koje izgleda kod tebe igraju neku bitnu ulogu kod ocjene kvaliteta kompajlera, onda mogu i ja da kazem nesto o svojim iskustvima.
Dakle, jednog dana ce ti mladjani ljudi da odrastu i u cilju odrzanja svoje egzistencije ce pokucati na neka vrata i reci "Ja sam dosao povodom oglasa za posao...". Kada ih potencijalni poslodavac priupita sa kojim alatima barataju (posto se jezik podrazumjeva to ih nece ni pitati), mislim da nece bas ostaviti narocit utisak ako kazu "Baratam odlicno sa korakovim Pascal-asemblerom". Bez obzira koliko taj kompajler bio bolji standardi su standardi i sa standardima se radi. To je isto kao da dodjete da trazite posao u Londonu, i kazete: "Ja ne znam engleski, ali znam esperanto, to je znate, mnogo bolje." Mozda i jeste, ali posao ipak necete dobiti. A ako neko savjetuje mladjim generacijama da svoje vreme investiraju u nesto sto se nigdje ne koristi, ne uzimajuci u obzir kakve ce to posljedice kasnije da ima na njihov zivot i zaposlenje, onda su po meni te dobre namjere pogresno procjenjene.

Sledece, osvrnucu se jos i na iluziju o samozaposljavanju, red je da malo popricamo i o tome, posto je to jedina oblast u kojoj se, za sada, moze razgovarati o tom kompajleru. Prvo se, svako od nas moze preispitati koliko ljudi poznaje u svom zivotu. Zatim sracunajte otprilike koliko svi ti ljudi imaju uredjaja u kojima su mikrokontroleri (bice ih sigurno vise hiljada), a onda probajte da izbrojite koliko tih uredjaja je napravio neki usamljeni strelac iz komsiluka, pa sracunajte postotak.
Da biste sa diskutabilnim uspjehom poceli da radite u samostalnoj reziji potrebno je da imate odredjeno iskustvo koje ne mozete steci sa razvojnom plocicom od 99 evra koju ste kupili u obliznjoj prodavnici. Time mozete da se zabavljate, ali da hranite porodicu i sve drugo sta uz to ide, tesko.
Ako krenemo da ozbiljan osciloskop kosta minimum 2000 evra, osrednji razvojni sistem 500, ICE takodje minimum par hiljada, ozbiljan softwer takodje, Logic analyzer circa 1000, programatori, moduli, svi ostali alati i oprema, porezi, registracije, milion drugih stvari itd... onda tom mladom covjeku u startu treba minimum 30-tak hiljada za start. A sve to ne znaci nista ako prethodno nije stekao negdje neko iskustvo. I sve su to mali troskovi kad se uporedi sa troskovima probijanja na trziste (razni market-planovi, reklame itd...). U nasim uslovima, takvih nema mnogo.
Znaci, korak, od 1000 ljudi koji ce se baviti mikrokontrolerima, 999 njih ce poceti kao juniori u nekoj firmi, a ako vi bazirate vase savjete na onom jednom koji ce da radi sam i povremeno napraviti automatsko paljenje svjetla za komsijinu garazu ili pumpu za bunar koja se zaustavi kad voda dodje do nekog nivoa, to je onda druga stvar. Ja ne govorim o tom jednom covjeku.
A i od svih tih ljudi koji rade samostalno, 99% njih je prethodno radilo negdje drugo pa tek onda pocelo svoj biznis, sto je takodje vrlo vazna cinjenica u ovoj prici, ali se izgleda cesto precutkuje.
Jeste lijepa iluzija zamisljati da ce svako od nas da sjedi kod kuce, ustaje kad oce i radi kad oce, ceprka nesto sa mikrokontrolerima i to prodaje za velike pare itd... Medjutim, sto se prije rijesite te iluzije to bolje. Ko od vas ima mp3 player ili bilo sta drugo pravljeno kod nekog privatnika iz komsiluka?
Moze se i desiti da nekom upadne sjekira u med, ali to je izuzetak, a ne pravilo.

U svakom slucaju, put koji vi predlazete je po mom misljenju naopak od realnosti. Da se mladi ljudi u startu zamajavaju pisanjem kompajlera za svoje mikrokontrolere, a pri tom tek sto su poceli da rade sa tim, je isto sto i ohrabrivati covjeka koji je dva puta skocio padobranom da pocne konstruisati avione i to ne bilo kakve nego neke koji ne mogu da slecu ni na jednu poznatu pistu u svijetu, ali pri tom trose manje kerozina!
Vecina ljudi koji posjecuju ovu temu su mladi ljudi koji se interesuju za mikrokontrolere, a na tome ce i ostati ako se ne osposobe da dobiju neki posao u toj struci. A to osposobljavanje podrazumjeva dobro baratanje sa standardnim alatima. Nekad ste mogli lako da se zaposlite u nekoj firmi bez narocitih znanja o tome, pa vam daju neke knjige, pa vi kao citate pola godine o tome, pa zapitkujete starije kolege i tako dok ne naucite. Ta vremena su prosla. Danas tako mozete dobiti posao jedino ako vam je blizak rodjak direktor firme, ili je drzavna firma sa platom cirka 200 evra. Ja sam nedavno bio na jednom razgovoru za posao u firmi gdje se radilo sa opremom sa kojom nemam iskustva, ali bih za 15-tak dana mogao da se presaltam, jer su principske stvari valjda iste. Medjutim, pitanje poslodavca je bilo: "Mozete li vi od sutra da se ukljucite samostalno u projekat?". Ja sam rekao da ne mogu, da mi treba najmanje 10 dana, oni mi se zahvalili na razgovoru i rekli da im je zao, da im treba neko odmah. Medjutim, nije stvar u tih 10 dana, vjerovatno znaju i sami da nece naci nikog za tako kratko vreme, ali mislim da mi nisu povjerovali da uopste znam nesto o tome. Vjerovatno su mislili, evo jednog nema pojma, hoce da nas obmane, misli da ce za 10 dana stici nesto da nauci. Eto, tako je to u realnosti kad odrastete, izvjestaj iz prve ruke.

I na kraju, mene u ovoj raspravi uopste ne interesuju bilo cije subjektivne namjere. Ako vi napravite kompajler koji sabere da je 2+2=5, ja cu da kazem da je los. Cak i ako vi kazete da cete sav prihod od prodaje tog kompajlera pokloniti centru za nezbrinutu djecu, ja cu opet da kazem da je los. Nemojte me prozivati za nikakve namjere, jer me to ne zanima. Za mene je ovo tehnicki forum i ja komentarisem samo tehnicke aspekte proizvoda (a jedan od tih aspekata je i upotrebljivost u prakticnom zivotu) i nista drugo.


@Stojane

ako se radi samo o prosirenju asemblera radi lakse citljivosti onda ok. Ja sam se osvrnuo na optimizaciju koriscenja memorijskih banki jer se nesto o tome pricalo u par postova prije moga. Inace sve ostalo receno je samo po sebi jasno i ne zahtjeva neko dodatno objasnjenje. Ipak, moram jos jednom da napomenem da nisam imao namjeru da komentarisem kvalitet predlozenih rjesenja, samo da ukazem na primjenjivost svega toga u prakticnom zivotu.

Sto se tice ovog primjera koji sam okacio u attachmentu, opet mali nesporazum. To sam i naveo kao primjer koliko mali rezultati optimizacije se postizu cak i prilikom koriscenja slozenijih matematickih aparata i algoritama, a ne obratno, da bih pokazao to kao neki dobar metod optimizacije. U tom smislu irelevantno je koji asemblerski kod se optimizuje (hitec-ov ili neki drugi), jer se prikazuje ustvari poboljsanje te optimizacije nekog automatski generisanog asm koda. Da je optimizovan neki rucno pisan asemblerski kod (kao sto bi bio u slucaju korsicenja ovog korakovog kompajlera) poboljsanja bi sigurno bila zanemarljiva, ako ne i negativna. Time sam samo htjeo da skrenem paznju da mozda nema smisla razmsiljati o toj vrsti optimizacije kod pravljenja ovog kompajlera koji je blizak asembleru. Jedino mozda na neki vizuelni nacin povecati preglednost toga. Ali ne mora ni to biti od nekog znacaja. Ne znam koliko ko ima iskustva sa programiranjem mikrokontroelera, ali asembler se mahom koristi za krace i jednostavnije projekte, a kod programa tog obima programer koji to radi ionako sve to ima manje-vise u glavi, pa mu ni te informacije na ekranu u nekoj vizuelno preglednoj formi ne moraju nuzno biti od velikog znacaja (sto se tice tih memorijskih blokova). Medjutim, preglednost koja se postize pisenjem "if W > 50 then" o odnosu na klasicne asemblerske mneomonike je ipak znacajna, sa tim se bezuslovno slazem.
Sto se tice ukljucivanja funkcija iz vec gotovih biblioteka onako kako ste napisali nema problema, ali je problem sto se te biblioteke skoro nikad ne isporucuju sa izvornim kodom, tako da copy-paste otpada. Moze se iz hex ili iz binarnog coda dobiti asm kod, ali dok bi se on prepravio na ovaj pascal-asembler lakse bi ga bilo ispocetka napisati.

Pozdrav!


[ Stojan Trifunovic @ 30.07.2008. 23:41 ] @
@sander

Pri odgovorima se ogranicavan na 16F familiju jer nju najbolje poznajem. 18F familiju nisam dovoljno savladao, a i njena poboljsanja nisu mi nesto preterano potrebna.
16F serija nije mnogo zahvalna za stringove, nizove, matrice i ostale "naprednije" strukture. Ja bar pokusavam da ih ako je ikako moguce izbegnem u programima. Za njih je indirektno adresiranje idealno, a tu je PIC16 serija prilicno limitirana.

Ukoliko vec program zahteva vise registara, mogu se bez ikakvih problema u relokativnim programima definisati varijable koje se nalaze u njima UDATA direktivom. Znam i sam da ovo nije dobro resenje za vise podataka nego sto moze stati unutar jedne banke, ali 16F serija je takva, i tu je nemoguce ista uraditi.
Ovo je deo iz linkerske skripte za 16F628 u kome su definisane dozvoljene granice banaka.

DATABANK NAME=gpr0 START=0x20 END=0x6F
DATABANK NAME=gpr1 START=0xA0 END=0xEF
DATABANK NAME=gpr2 START=0x120 END=0x14F

SHAREBANK NAME=gprnobnk0 START=0x70 END=0x7E
SHAREBANK NAME=gprnobnk0 START=0xF0 END=0xFE
SHAREBANK NAME=gprnobnk0 START=0x170 END=0x17E
SHAREBANK NAME=gprnobnk0 START=0x1F0 END=0x1FE

Sa ovakvom strukturom slobodno se moze pisati:

NIZ_BANK1 UDATA 0xA0
niz res .79 ; (od 0xA0 do 0xEF)

Nazalost tako ce se dobiti niz od samo 79 neprekidnih registara. Tacnije, moglo bi i vise, ukoliko se zadje u oblast registara prisutnih u svim bankama.



@Odin D.

Situacija u nasoj zemlji je takva kakva je. Kinezi prave revoluciju dok mi stagniramo. Sigurno nije toliki problem znanje, koliko ostali aspekati (mnogo vece cene elektronike, zastarele tehnologije, porezi na sve i svasta, veze...). Za sada od mikrokontrolera bez obzira na znanje nema zarade. Mozda ce uskoro (za pedesetak godina) biti bolje.
Skoro sam cuo pricu kako je covek trazio posao ali gazda je bio zauzet obavezama, pa je na intervju poslao - svoju suprugu. Sta ce da upita kandidata, kako stoji sa engleskim. Kaze, solidno. Ne, ne moze solidno, vec morate da odlicno vladate njim. Pa dobro, ispitajte me. Ali ja ne znam engleski! Onda je dovela jednog od radnika i trazila da raspravljaju o tehnickim aspektima posla na engleskom. Kako je engleski bio apsolutno nebitan u celoj toj prici, njegovo znanje bilo je jos gore od znanja kandidata. Sve dok nasi poslodavci ne znaju sta hoce, zaposljavace kandidate koji vladaju svim znanjima ovoga sveta sve dok ne sednu za masinu. Mozda je i to dobro. Koliko znaju tako ce biti placeni, sve do bankrota.

Sto se tice banaka, korak pokusava naci najoptimalnije resenje za njihovu implementaciju. Sada ima mogucnost izbora. Moze prepustiti izbor programeru, ili probati da napravi potpuno automatski kompajler po uputstvima iz vaseg priloga.

Koliko sam ja shvatio, zaista se radi samo o prosirenju mogucnosti asemblera, a u cilju poboljsanja njegove preglednosti, smanjenja mogucnosti pojave gresaka i brzeg razvoja programa.

Kazete da se asembler koristi mahom za krace programe. Zasto je to tako? Licno mislim da je odgovor upravo u njegovoj losoj strukturi (tacnije nedostatku ikakve strukture) i teskoj citljivosti. Dzabe komentari kada se najobicnije IF W > 50 mora realizovati kako rekoh oduzimanjem, testiranjem Carry flaga, pa tek onda grananjem. Kada bi se ovo moglo uz dobru optimizaciju koda sakriti od programera, takav program bio bi daleko citljiviji, pa bi bili moguci slozeniji programi uz isto ili manje napora. Drago mi je da se sa ovim slazemo.

Verovatno se nismo razumeli za funkcije iz gotovih biblioteka. Tu nisam mislio na funkcije unutar biblioteke u njenom bukvalnom znacenju (libaries sa ekstenzijom .lib - iako bi se i one mogle disasemblirati) vec na asemblerske (.asm) programe, odnosno potprograme koji mogu (isto kao biblioteke) obavljati odredjenu funkciju (npr. sinus). U tom slucaju postoji gomila izvornog koda unutar Microchipovih AN (Aplication Note) .pdf fajlova. Cak se izvorni kod za vecinu AN moze naci u zipovanim .asm fajlovima. Mislim da je svaki programer koji zeli sebi olaksati rad vec sakupio (bez obzira da li su razvojene ili kopirane) dovoljan broj potrebnih rutina. Uz korakov kompajler samo ce ih ubaciti u zaglavlje procedure.

Moram ipak istaci da mislim da je korak pravilnije shvatio upotrebu magistrale (iako je ocigledno pogresio za 2Kb RAM-a).
Zbog harvardske strukture se unutar jedne instrukcije nalazi i kod i operand. Tako ne postoje dve magistrale (adresna i magistrala podataka) vec (kod PIC16 serije) jedinstvena 14-tobitna magistrala. Konstruktori 16F serije sigurno su verovatno mogli povecati broj bitova magistrale (kao sto su i uradili pri prelasku sa 12 na 16 seriju), medjutim imali su dobrih razloga da to ne ucine.

Svako povecanje broja bitova za adresiranje RAM-a ili flasha moralo bi potrositi srazmerno vecu flash memoriju. Idealno bi bilo kada bi 16F serija imala 16 (umesto 14) bitova po instrukciji. Tako bi kod instrukcije CALL umesto

100 kkkkkkkkkkk bio
100 kkkkkkkkkkkkk , odnosno mogao bi direktno adresirati celih 8Kb flasha.

Isto tako kod CLRF instrukcije bi umesto
0000011 fffffff bio
0000011 fffffffff , odnosno mogao bi direktno adresirati celih 512 registra RAM-a.

Zbog cega se Microchip nije opredelio za ovakvu arhitekturu? Jednostavno, ocenio je da ogranicenje sa bankama i stranama ne predstavlja preveliki problem (nije imao koraka u vidu :) ), a moglo bi se dosta ustedeti na flash-u. Kako?
Sa 14-tobitnim instrukcijama flash bi morao imati 14bitova * 8192instrukcija = 114688 bitskih celija flasha.
Sa 16-tobitnim instrukcijama flash bi morao imati 16bitova * 8192instrukcija = 131072 bitskih celija flasha. Usteda flasha je ocigledna.

Potpuno isti sistem se primenjuje i u 18F seriji. Korak je verovatno imao nju na umu kada je pricao o 24-bitnoj duzini instrukcija.

Mislim da je ovo verovatnije od vase teorije (da nisu mogli promeniti hardver), pogotovu jer je eto u 18F seriji povecan broj bitova magistrale, ali su banke i dalje ostale.
[ korak @ 31.07.2008. 11:51 ] @
Odin D.

Od svega sto nisam tacno rekao je da se sa 9 bita adresne magistrale adresira 2KB (imao sam ispred sebe jedan 18F sa 2K i napravio omasku). Treba znati razliku izmedju harvard i Fon Nojmanove strukture, pa onda pricati na tu temu. Hardvard struktura je uvedena sa ciljem da se ubrza rad procedora, da se uvede paralelnost u izvrsavanju jedne naredbe i citanju i dekodiranju sledece. Da bi se to postiglo, a cilj je da se to radi za jedan klok ciklus procesora, obe operacije treba toliko da traju. To je odlicna ideja i vrlo znacajna za povecanje brzine rada procesora, a da ne moraju da se ugradjeni elementi u procesor koji rade na nekoliko puta vecoj frekvenciji od one na kojoj radi procesor Fon Nojmanove strukture. Na primer MC9S08 ima klok od 50ns (sva unutrasnja kola moraju da rade sa tim klokom) a prosecno trajanje instrukcije je 150ns. Harvard struktura, ima dakle cilj da ucini da instrukcija radi na tih 50ns, usteda je ocigledna. Medjutim, ako procesor adresira 64KB memorije, da bi harvard struktura dala svoj maksimum programska memorija mora imati najmanje 24 bitnu sirinu. Jedan bajt za kod naredbe i 2 bajta za direktan pristup bilo kojoj lokaciji memorije. Naravno procesori sa vecom memorijom mogu da imaju i siru programsku memoriju. Medjutim, kako je sirina programske memorije ista za sve naredbe, cak i za one koje nemaju parametre, onda se javlja neracionalno koriscenje programske memorije. No, da se ne bi uludo bacali bitovi koji se ne koriste, kod takvih naredbi, dodaju im se jos neke osobine, kao uslovno izvrsavanje i tome slicno.

Druga stvar koju treba znati je da sami vodovi koji povezuju aktivne elementa na cipu zauzimaju znacajnu povrsinu cipa. Zato je problem kako u cip mikrokontrolera integrisati sto vise hardvera i obezbediti prostor za veze koje ce ih povezivati. Sa tog aspekta Fon Nojmanova struktura 8-o bitnih mikrokontrolera ima samo jednu 16-to bitnu adresnu magistralu, jednu 8-o bitnu magistralu podataka i jedan broj kontrolnih signala. Kod PIC-a postoji magistrala za pristup flash-u, magistrala za pristup RAM-u i svim drugim resursima mikrokontrolera, magistrala za pristup steku i magistrala za pristup EEPROM-u. Kao kompromis islo se na kracu sirinu programske memorije. To je dovelo do toga da adresni parametar naredbe kod pristupa podacima u RAM-u bide 7 ili 8 bita. Dakle, jednom naredbom se ne moze pristupiti proizvoljnoj lokaciji u RAM-u. To se moze uraditi sa dve: jednom se saopste visi nedostajuci bitovi (preko 7 ili 8) i to su bitovi koji odredjuju banku ili stranicu (kako ko voli) a sledecom naredbom se saopstava kod naredbe i nizi bitovi adrese. Naravno, uvek postoji mogucnost da se u nekom nizu naredbi pristupa lokacijama sa iste stranice, i nije potrebno uvek saopstavati nedostajuce bitove adrese jer oni ostaju zapamceni na nekom odredjenom mestu (u statusnom registru, ili u nekom posebnom registru). Slican mehanizam se koristi i kod skokova i poziva podprograma.

Dakle, Odine stranicenje memorije niije uvedeno da se suzi adresna magistrala, vec da se suszi sirina programske memorije, odnosno time i skrati naredba, a vidimo kako ona od 12 bita narasta sa svakim novim tipom PIC-a kako tehnologija napreduje i prelazi na sve uze veze (sada je valjda 0.25 mikrona).

Da se osvrnem i na ono sto si pisao, a van teme je, niko ko se ozbiljno bavi ovom tehnikom ne moze da bude konzervativan a istovremeno i uspesan. Iako koristim asembler u kojem sam odstranio vecinu mana koje on kao takav ima, ostala je samo jedna mana i ona je neresiva. To je neprenosivost. Zato svakom pocetniku savetujem da mu glavni jezik bude C, ne zato sto je najbolji, vec zato sto je prenosiv, a kod gazde ce biti u situaciji da cesto menja procesore sa kojima radi.

Inace, radio sam 2 godine za jednu firmu u Minhenu odavde iz Nisa, ali i kod njih par meseci. Svi rade na C-u, a u neobaveznom razgovoru sa gazdom (on srecom nije bio laik za elektriniku) cuh od njega da C programere moze da nadje na svakom koraku, ali one koji programiraju na asembleru nema, a rado bi ih zaposlio. Zasto, saznao sam vrlo brzo. Radili su sa nekim 16-to bitnim mikrokontrolerom (sa siromasnim integrisanim hardverom i spoljasnjim memorijama) izvedenim iz 80C51 i odlicnim razvojnim sistemom XA V3.0 Americke firme TASKING. Njihovi programeri nisu znali da otvore prozor sa prevedenim kodom da vide rezultat onoga sto rade, niti su znali arhitekturu mikrokontrolera. Sta ce im kada to od njih ne trazi razvojni sistem. Elem, posle godinu dana, narucilac ih je tuzio i trazio nadoknadu stete jer je uradjaj koji su razvijali lose radio u nekim specificnim situacijama. Ja sam dobio zadatak da dibagiram softver koji su oni pisali, i odnmah prvo trazio, na njihovo zaprepascenje, datasheet za mikrokontroler. Kao sta ce mi. Brzo sam shvatio da su njihovi programeri vesti na PC-u, da su kupili knjigu za C i naucili ga i sebe prozvali C programerima. A tamo, niko ti ne trazi diplomu, vec te pita sta znas da radis. I sad, on je pokazao da zna da radi, ali softver moze da pokaze da ima gresku i posle vise meseci rada. Vrlo brzo sam video nekoliko ociglednih gresaka koje verijem ne bi napravilo 80% ljudi na ovom forumu. Toliko o stvarnosti, mozda njenom nalicju, prosudite sami.

Dakle, kada bih imao para, i bio prisiljen da radim sa raznim mikrokontrolerima, sigurno bi kupio C kompajlere za sve te mikrokontrolere i tako pisao prakticno jedinstvene C programe bez obzira na kontroler. Ali, kako situacija nije takva, izabrao sam mikrokontroler koji ima veliki broj tipova da moze da pokrije sve projekte kojima se bavim, poboljsao asembler, i to je za mene kao privatnog preduzetnika najbolje resenje sa najmanje para. Drugi, u drukcijim situacijama treba da nadju najbolje resenje u okviru svoje situacije, i ja ne zelim da ih nagovaram. Naprotiv, samo sam zeleo onima koji rade samo sa PIC-om i pri tome su sami sebi gazde da prenesem svoje iskustvo, jer se kod mene pokazalo kao vrlo uspesno. Osim toga zasto bih se opterecivao kada ionako imam previse posla, i zasto bi trosio energiju na polemike gde mi se umesto svojim argumentima suprotstavlja linkovima.

Pozdrav svima,
ako neko misli da je interesantno ovo sto radim neka mi se obrati rado cu saradjivati.
[ Odin D. @ 31.07.2008. 12:26 ] @
@Stojane

PIC, kao i svaki drugi procesor harvardske arhitekture mora imati adresnu magistralu i magistralu podataka za program, a isto tako adresnu magistralu i magistralu podataka za podatke. To su ukupno 4 fizicke magistrale, a nema ni govora o postojanju jedne jedinstvene magistrale za sve, jer onda bi se sve prednosti harvardske arhitekture anulirale (ona je i napravljena zbog toga da bi se u isto vreme moglo pristupati programskim instrukcijama i podacima).
U flash memoriji se nalazi program. Instrukcije iz te memorije se dovlace u jezgro preko 14-bitne magistrale za podatke (taj 14-bitni podatak se npr. sastoji od 6 bitova kojima se kodira asemblerska instrukcija, 7 bitova npr. za adresu operanda ili slicno, zavisi koja je instrukcija u pitanju, jer kao sto si naveo, kod call ili goto instrukcije samo tri bita koduju operaciju, ostali predstavljaju neki dio adrese i sl., a kod ostalih je drugacije, no to nije bitno). A koja instrukcija ce se dovuci u procesor preko te 14-bitne magistrale podataka iz flash memorije, odlucuje se pomocu adrese koja se salje preko 13-bitne adresne magistrale. Dakle, to su dvije magistrale kojima se dovlace programske instrukcije iz flash memorije u jezgro procesora koji te instrukcije izvrsava. O adresiranju programske memorije brine se PC registar koji je 13-bitni i ima pridruzenu hardversku logiku koja mu omogucava da barata sa 13-bitnim adresama iako je procesor 8-bitni. To je uglavnom da se inkrementira, ili da mu se doda neki broj ili da se upise neki broj (zbog skokova i sl.) Medjutim, taj dio procesora je ipak ogranicene velicine i ne utice znatno na velicinu cipa.

Osim flash memorije ima i RAM memorija u kojoj se nalaze konfiguracioni registri i GPR registri koje program koristi za upravljanje mikrokontrolerom ali i kao memoriju za privremene podatke kojima program operise u toku rada. Naravno, da bi se pristupilo nekom bajtu u toj memoriji, taj bajt je prvo potrebno adresirati preko neke adresne magistrale, a zatim ga i dohvatiti preko magistrale podataka. U ovom slucaju magistrala podataka je 8-bitna, a adresna je valjda 9-bitna. Znaci i tu fizicki postoje 2 magistrale.
E sad, kad se radi o adresiranju te RAM memorije, osim direktne adrese koja moze da se nalazi u samoj instrukciji (kao npr. nizih 7 bitova i jos neki bit iz status registra koji odredjuje o kojoj banci se radi) postoje i razni drugi modovi adresiranja koji se intenzivno koriste ne samo kod mikrokontrolera nego i svih drugih procesora. To su npr. bazno, bazno-indeksno, pa varijacije sa auto-inkrementom, auto-dekrementom i sl. bez kojih se ne moze zamisliti npr. rad sa nizovima, sukcesivna obrada nekog niza podataka u memoriji, premjestanje bloka podataka sa jedne lokacije na drugu i sl. E sva ta izracunanja adresa kod takvih modova adresiranja zahtjevaju odredjeni hardver i razlike u velicini hardvera postaju drasticne izmedju 8-bitne i 9-bitne aritmetike. To obicno znaci da bi se citava arhitektura procesora morala kompletno mijenjati pocevsi od ALU jedinice, pa nadalje, znaci i velicine svih registara, brojaca, dekodera, magistrala itd... Prosirenje sirine flash memorije sa 14 na 16 bita je relativno zanemarljivo spram ovog povecanja koje sam upravo napisao (kod PIC16 cipova koji imaju implementirano svega 2KB flasha, prosirenje od dva bita bi znacilo svega dodatnih 512 bajtova flash memorije, to nije bila neka cifra cak ni u vreme kad je nastao, a kamoli danas, a tada to nije ni bio flash nego eeprom i sl.).
Ja zaista nisam 100% siguran iz kog razloga je kod PIC odabrano da se radi tako (a iskreno da kazem, mrzi me da sad listam data sheetove i bakcem se time), medjutim koriscenje banaka u cilju prosirenja adresnog prostora iznad aritmetickih mogucnosti procesora, a da se pri tome izbjegne hardversko komplikovanje procesora je (bila) uobicajena tehnika kod 8-bitnih procesora. Kazem "bila" jer je to nesto sto se danas uglavnom izbjegava.
Sta se desava sa PIC18 serijom nisam upucen, jer sam nakon PIC16 ja napustio pic i nisam nista dalje sa njim radio. Medjutim, cini mi se da je i PIC18 8-bitna masina i ako hoce da adresira vise od 256 bajtova RAM-a mora da koristi banke ili neki drugi trik, i to je to. Duzina instrukcije, kao sto rekoh moze da utice samo na direktno adresiranje u kom se adresa operanda u RAM memoriji nalazi direktno u instrukciji, a svi ostali nacini adresiranja zahtjevaju ili prosirenje hardvera ili koriscenje banki (i banke su neki vid "prosirenja", samo sto dodatna izracunavanja za ta 2 ili 4 bita nisu implementirana u chipu nego u glavi programera, odnosno, prenose se sa hardvera na softwer, a programer je duzan da sa njima ispravno barata u svom programu).

Sto se tice ovih "gotovih" funkcija koje se mogu pronalaziti u .pdf-ovima i skupljati po nekim dokumentima, mislim da to nije bas najsretnije rjesenje. Te su funkcije izolovane jedna od druge, nekonzistentne po pitanju koriscena varijabli i hardvera itd. Zamisli situaciju da ubacis funkciju koja racuna sinus, a onda ukljucis neku funkciju za serijsku komunikaciju, a one obe definisu neke medjupromjenjive na istoj memorijskoj lokaciji i jedna drugu zakopava. Pitanje je koliko su dokumentovane sve te stvari i koliko je pametno time se baktati. Naravno da se sve to moze sizifovskom metodom izgurati, ali bice potroseno ogromno vreme i trud, a rezultati ce u najbolju ruku biti osrednji.

Moje je misljenje, da ako naumis da pravis kucu, kupi alat i materijal i pocni da je pravis. A ako ti u svrhu pravljenja kuce pocnes prvo da sam pravis mjesalicu, pa da proizvodis cement, pa kopas glinu da bi pekao cigle i blokove i rudu gvozdja da bi dobijao gvozdje za eksere i armaturu itd. iskreno mislim da se tu vise radi o nekim drugim stvarima nego o pravljenju kuce.

Pozdrav.


#EDIT

@korak

Dok sam pisao poruku u medjuvremenu je stigla i tvoja poruka, medjutim mislim da ono sto sam pisao Stojanu o razlogu koriscenja banaka moze da bude i odgovor na tvoju poruku.

Sto se tice harvardske arhitekture:
Poznajem dobro i Von Neumann-ovu i harvardsku arhitekturu i mogu odmah da odgovorim da cilj da se instrukcije izvrsavaju u jednom taktu ili bilo kakve konstantacije tog tipa nemaju nikakve veze za definicijom harvardske arhitekture. Harvardska arhitektura znaci da se program i podaci nalaze na odvojenim mjestima i da im se pristupa odvojeno preko razlicitih magistrala. Poenta svega toga je da moze da im se pristupa istovremeno. Ako se u procesoru trenutno dekodira instrukcija koja zahtjeva neke operande iz npr. RAM-a, ti podaci mogu da se dovlace preko magistrale podataka, dok se istovremeno preko programske magistrale dovlaci sledeca instrukcija u jezgro. Kod Von Neumann-ove to nije slucaj, jer se i program i podaci nalaze u istoj memoriji i pristupa im se preko iste magistrale, tako da sledeca instrukcija mora da ceka dok se ne ucitaju operandi koje je npr. zahtjevala prethodna instrukcija.
A da li ce se instrukcije izvrsavati u jednom, deset ili sto taktova, to je sasvim druga prica. Postoje hiljade i hiljade razlicitih procesora sa setovima instrukcija od kojih se duzina izvrsavanja nekih instrukcija istog procesora razlikuju i vise od 100 puta i traju razlicit broj taktova (a neke su i asinhrone itd.). Naravno, kod mikrokontrolera je to cilj kome se tezi, ali zbog nekih drugih stvari, a ne sto je to filozofija harvardske arhitekture. Ima harvardske arhitekture implementirane i kod CISC i kod RISC a i kod nekih hibridnih setova instrukcija, zatim kod skalarnih i vektorskih procesora itd. i tu nema govora o nekom cilju harvardske arhitekture da se postigne da se sve instrukcije izvrsavaju za isto vreme i to u okviru jednog takta procesora.

Vec si u nekoliko postova naglasio averziju prema "linkovima" i pozivanju na neke autorite van sopstvene glave. Mislim da je to malo pretjerano. Postoje milioni stvari na internetu objasnjeni i dokazani od mnogo kompetentnijih ljudi nego sto sam ja. Ja cu se radije pozvati na te izvore nego tvrditi nesto iz svog nesigurnog iskustva. Bolje je nekom da procita strucan tekst, nego da mu je prepricavam nesto za sta nisam strucnjak. Na kraju krajeva i ja sam vecinu stvari naucio od nekog drugog, i ne pada mi na pamet da nipodastavam izvore na internetu, jer internet nije neka nedefinisana tvorevina nepoznatog porijekla izronila iz magline mlijecnog puta, nego sadrzaj koji su takodje napisali neki ljudi koji takodje mogu nesto znati o mikrokontrolerima. Tako bi se neko na nekom drugom forumu, u americi npr. mogao pozvati na neki tvoj ili moj post, a neko mu odgovori "mani me tih linkova sta tu ima vredno".
Na kraju krajeva, moras priznati da su i motoroline mikrokontrolere napravili tamo neki drugi ljudi na "trulom zapadu od koga dobijamo samo bagovite proizvode", i ove kompjutere na kojima radimo, i softwer itd. Mozda i ti ljudi pisu neke postove, clanke, blogove i svoja razmiljanja negdje na internetu i u najmanju ruku je neprimjereno ih je sve adresirati nipodastavajucim tonom.
Ja cu uvijek savjetovati svakom da aktivno prati bar jedan-dva vodeca sajta embedded svijeta, da bi mogao da vidi malo siru sliku od one koje bi stekao samo na osnovu svojih projekcija. Na kraju krajeva, tamo pisu ljudi koji su izmisljali ove stvari na kojima mi sada radimo.
Ja sam ovo sto sam napisao o razlogu koriscenju banaka naucio iz knjiga koje su pisali ljudi koji su izmislili te stvari, a ne na osnovu mojih licnih zakljucaka. Nije nista lose misliti sopstvenom glavom i donositi sopstvene zakljucke, ali to ne znaci da treba zatvoriti oci i usi za sve druge informacije.
Ovako mi se tvoj stav cini kao da si ti sam izmislio i te mikrokontrolere i kompjuter i sve ostalo i da si se sve sam naucio i da je citav svijet zastranio samo si ti nasao pravi put.

Ovo tvoje iskustvo sa tom firmom je, sta da kazem...ima svacega. Isto kao i onaj moj intervju za posao. Medjutim, ne mogu se stvari generalizovati, ima i takvih firmi ima i drugacijih. Da sam ja dosao popodne, mozda bi bio neki drugi ispitivac, mozda bi sve bilo drugacije....

[Ovu poruku je menjao Odin D. dana 31.07.2008. u 14:15 GMT+1]
[ sander @ 31.07.2008. 13:29 ] @
Da se vratimo na temu. Ako bi kompajler bio samo poboljsanje asemblera odnosno da olaksa rad ljudima koji rade u asembleru, pre svega zbog lakseg pisanja programa sa raznim petljama, grananjima itd. onda bi nacin deklaracije varijabli mogao ostati slican kao i kod asemblera odnosno da programer povede racuna o tome. Mozda bi neka prva verzija i trebala tako da radi pa tek za neke naredne da se uvode poboljsanja. Nisam siguran ali mislim da i PIC Basic nema vise tipova varijabli vec byte i bit sto je najlakse i uraditi u kompajleru i mozda za prvu verziju i ne treba ici na neke slozenije tipove. Ono sto bi trebao svakako da ima vec gotove biblioteke za LCD, USART, I2C, ADC, PWM itd. i tu se uglavnom slazemo. Jos jedna stvar koja mi se cini dobrom, da interupt rutina bude implementirana tako da svaki interapt bude kao posebna procedura nesto slicno su izveli u CCS C kompajleru. Znaci nesto kao :

#int_ad
adc_handler() {
.....
}

pa ako je omogucen interapt onda ce se izvrsti procedura za obradu tog interupta bez potrebe da se pise deo interatpr rutine za snimanje sadrzaja vaznih registara i proveru koji je interapt izazvan kao i za vracanje sadrzaja prilikom izlaska.

Prioritet nekog interapta bi bio odredjen redom definisanja interapt procedura.
[ korak @ 31.07.2008. 14:50 ] @
OK Odine,

ne mogu da zamislim da je cilj Hardvar strukture bio da se razdvoje memorijski prostori programa i podataka, a pri tome negirati da je konacni cilj bio postizanje vece brzine. Pogledaj AVR, on ima Harvard strukturu 2 nivoa, njegovi registri (32) imaju posebnu magistralu, iako pripadaju RAM prostoru samo da bi mogle da se ostvare dvoadresne naredbe. Citajuci o ovoj strukturi, jasno je naglaseno da je ona jedno od resenja da se poveca brzina procesora. Ti skoro isto zakljucujes, ali zelis da ono sto je isto prikazes kao razlicito, ok.

Kada sam pomenuo linkove, naravno i ja sam mnogo toga naucio sa interneta, a sve sto znam sam naucio i od drugih i iz knjiga. Ali kada polemises sa nekim, ne koristi se navodjenjem linkova, vec ako si naucio nesto sa tog linka iznesi svoj stav kao argument. Dakle, ne nipodastavam ono sto se moze naci na internetu, niti navedene linkove u slucajevima kada pitam nesto na forumu pa mi neko da neki link. Ali ako se upustas u debatu, onda neka to bude iz tvoje glave i sopstvenog iskustva. To je bila moja primedba.

Ako su procedure o kojima sender govori smestene u modulima, onda nece doci do kolizije prilikom deljenja RAM prostora, jer su sva imena u modulu privatna za modul i prilikom kompajliranja bice pravilno rasporedjene varijable u RAM prostoru.

Koliko sam shvatio PIC ima samo jedan interrupt vektor (ispravite me ako gresim) pa tako moze postojati samo jedna interrupt procedura. U njij se ispituju flegovi koji oznacavaju koji se interrupt aktivirao, i na osnovu toga se poziva odgovatajuca procedura. U principu mogu se pozvati sve interrupt procedure, a prva naredba u svakoj ce biti provera da li je njen interrupt fleg aktiviran, i ako nije procedura ce se tu zavrsiti. Ako se ne varam PIC troci malo vremena za ulazak i izlazak iz procedure (podprograma). Tada bi interrupt procedura bila uvek ista, a pisale bi se samo one procedure (koje se pozivaju iz interrupt procedure) koje su potrebne. Nisam siguran da je ovo najbolje, ali mozda neki dobar poznavalac PIC-a moze da komentarise.

Pozdrav
[ Odin D. @ 31.07.2008. 14:59 ] @
Da se ne bismo stalno vracali na temu...

Ako se namjerava dalje diskutovati na ovu temu i nesto u tom pravcu raditi, predlazem da se otvori nova tema sa naslovom "Razovj kompajlera za PIC" ili kako god vec nadjete za zgodno. Time bi sam naslov teme privlacio ljude koji su zainteresovani za to, pretraga bi davala bolje rezultate, informacije bi se drzale na jednom mjestu itd.
Ovako se ova tematika sa strane ubacuje vec nekoliko puta u teme koje su zapocete zbog sasvim drugih pitanja i postovi koji su pisani o tome su rastrkani po citavom forumu i uopste slaba je vajda od toga, a unosi se zbrka u ostalo. Npr. ova tema je zapoceta pitanjem o programskim jezicima koji se koriste kod mikrokontrolera, a stiglo se do razvoja novog kompajlera za PIC.
Dosta tema na ovom forumu zastrani, mnogo se caska, a malo sta uradi. Moderatori su prilicno liberalni po pitanju ko sta kome kako i gdje odgovara i jednim djelom i to doprinosi sto je forum takav kakav je.

Zbog postova koji se nalaze u neodgovarajucim temama pojavljuje se mnogo beskorisnih "odgovora". Konkretno u ovoj temi gdje covjek pita koje programske jezike da uci, skrenulo se na pricu o novom nepostojecem jeziku i kompajleru, i onda uvijek neko (npr. ja) u svjetlu naslova teme mogu da postavim pitanje "a sta ce ti to". Da npr. nije doslo do ovog skretanja u temi, ja bih mogao dati covjeku konkretniji i korisniji odgovor, npr. uci to i to. Lakse meni, bolje njemu. A da se o ovoj stranputici raspravlja u temi koja se zove "Razvoj kompajlera za PIC", ja tamo ne bih mogao postaviti pitanje "a sta ce vam to", zato sto se tamo o tome i radi. Time bi smo svi ustedjeli na vremenu, da ne odgovaramo na ono sto covjek nije pitao, da oni koji hoce da prave kompajler umjesto sto odgovaraju na moja pitanja rade nesto korisnije po razvoj kompajlera itd.

Ovom forumu je svakako potrebno malo sredjivanja.

Pozdrav svima!
[ Odin D. @ 31.07.2008. 16:09 ] @
@korak

Pojavljivanje harvard arhitekture jeste bilo zbog povecanja brzine i mogucnosti procesora (kao uostalom i bilo koja promjena u svijetu mikrokontrolera se iz 99% razloga radi zbog toga). Moja je primjedba bila samo na to da harvardska arhitektura to ubrzanje podrazumjeva upotrebom odvojenih magistrala za instrukcije i podatke (dakle brzi protok podataka kroz procesor), a da to ni na koji nacin nije spregnuto sa teznjom da se instrukcije izvrsavaju u jednom taktu. To je sasvim druga prica. Harvardska arhitektura se srece kod svih vrsta procesora (i kompjutera) pa cak i onih kod kojih nema govora o uniformnom trajanju instrukcija, ili cak kod onih koji rade asinhrono. Mozemo imati harvardsku arhitekturu kod bilo kog procesora ili racunara. Mikrokontroler moze da ima i spoljnu memoriju za podatke i program i to je opet harvardska arhitektura bez obzira kakav je sam procesor iznutra. A to kako je u samom procesoru realizovana jedinica za izvrsenje instrukcija i u koliko koraka (fetch, decode, fetch operands, execute....) ili taktova procesora ce to odigravati nije uopste dio price iz harvardske arhitekture.
Teznja da se instrukcije kod mikrokontrolera izvrsavaju sto brze i u jednom taktu je posljedica specificne upotrebe mikrokontrolera gdje ta osobina igra veliku ulogu (zbog sto brzeg i vremenski definisanog odgovora na interrupt i sl.), ali kao sto rekoh, to je stvar implementacije jezgra, ali nije povezano sa harvardskom arhitekturom, osim sto se te dvije stvari cesto zajedno upotrebljavaju u konstrukciji mikrokontrolera, ali ni jedna ne uslovljava onu drugu i odnose se na razlicite stvari.

Nisam najbolje razumio ovo o AVR procesorima, medjutim pretpostavljam da se radi o nekim GPR registrima koju su implementirani na posebnom bloku u chipu, van RAM-a, iako potpadaju pod isti adresni prostor. Ako je tako, onda treba te stvari razlikovati od harvard arhitekture. U vecini danasnjih procesora je implementirana neka tehnika ("trikovi") za ubrzanje rada. Najpoznatija tehnika je npr. cach memorija. To je memorija fizicki bliska jezgru procesora u koju se (obicno po nekom algoritmu) predefinisano ucitavuju programske instrukcije unapred, za vreme dok procesor izvrsava prethodne operacije. A kad mu zatreba sledeca instrukcija, ako je pri tom ona vec u toj cach memoriji on ce je odatle mnogo brze dohvatiti nego iz klasicne programske memorije u kojoj lezi program, cime se postize znacajno ubrzanje. Ta memorija ima jednau magistralu ka jezgru, a drugu ka RAM-u, ali to ne znaci da je u pitanju harvard arhitektura, cim postoji vise od jedne magistrale. Kod mikrokontrolera je uobicajeno tehnika korscenja tzv. shadow registara. To znaci da se dupliraju neki karakteristicni registri npr. razno razni statusni, kontrolni itd. a obavezno i GPR registri. U tim dupliranim registrima je isti sadrzaj kao i u orginalnim. Kad dodje do interupta (ili poziva neke funkcije, zavisi sta hocemo), nema snimanja karakteristicnih registara na stack, vec interupt rutina nastavlja da radi sa shadow registrima. Kad se interupt zavrsi, glavni program nastavlja odmah da radi sa orginalnim registrima (koji su ostali nepromjenjeni jer je interrupt rutina radila sa shadow registrima) i nema potrebe skidanja neceg sa stack-a i sl. Ti shadow registri postoje npr. kod Infineona, ali se sticajem okolnosti zovu memorijske banke (sto naravno nema veze sa ovim bankama kod PIC-a samo je ime isto :)), a osim toga to je i 5-portna memorija, zato sto postoji i 5-stage instruction execution pipeline i razlicite instrukcije mogu u isto vreme da pristupaju tim registrima (neke bi da citaju podatak odatle, neke bi da upisuju, itd.). Osim toga postoji isto jedan set registara dvoportnog RAM-a implementiran fizicki blizu jezgra koji sluzi kad bas treba izuzetno brz pristup memoriji, kao i jos nekoliko razno raznih setova specijalnih registara razlicitih osobina da sad ne nabrajam. Kod zahtjevnijih procesora moze biti npr. i 16 shadow setova, tj. interupti se mogu ugnjezdjivati do dubine 16, a da se nista ne snima na stack.
Razni prozivodjaci imaju razne dodatke u svojim procesorima kojima nastoje ubrzati svoj cip ili mu prosiriti mogucnosti. Ali kao sto rekoh, treba razlikovati te stvari od onoga sto se naziva harvardska arhitektura. U poslednje vreme to vise nije tako lako, jer dolazi sve vise do integracije raznoraznih tehnika u jedan proizvod. Infineo npr. nema ni CISC ni RISC set instrukcija, nego neku mjesavinu koja, kako oni kazu, uzima najbolje od oba svijeta. Ipak se skoro sve instrukcije izvrsavaju u jednom taktu i pored tih CISC petljanija. On ima npr. i Von Neumann-ovu arhitekturu, ali podacima i instrukcijama pristupa istovremeno zato jer ima instruction pipeline. Kad neka instrukcija stigne na red da se izvrsava u procesoru, potrebni operandi za nju su vec odavno ucitani, i ne samo to, vec i nekoliko sledecih instrukcija i njihovi operandi. I sad neko moze reci, to je Von Neumann, instrukcije moraju da cekaju podatke to ne moze biti brze od harvarda. Pa ne moze u sirovoj formi, ali ovdje ima nesto drugo sto mu omogucava da moze, a istovremeno koristi sve prednosti Von Neumann-a (kompaktniji kod i manje rasipanje memorije).
(Navodim primjer na Infenionu jer njega najbolje poznajem, ali sve te stvari postoje i kod ozbiljne konkurencije)

Znaci, vremena se mijenjaju, tehnika se mijenja, o nekim podjelama koje su nekad vazile danas se sve manje moze pricati.

Pozdrav.
[ sander @ 31.07.2008. 16:44 ] @
Nisam siguran da smo se bas najbolje razumeli. Tacno je da kod 16F serije postoji samo jedan interapt vektor, na programeru je da u interapt rutini snimi sadrzaj vaznih registara, proveri da li je pojedini interapt omogucen i da li je on izazvao interapt, obradi interapt, resetuje interapt flag, vrati sadrzaj vaznih registara i vrati se iz interapt rutine. Ono sto sam ja predlozio je da ono sto se svakako mora uraditi, snimanje, provera idu automatski ako se u programu pojavi procedura za interapt dok bi se procedura tog interapta bavila samo obradom istog (tu se nema sta optimizovati da bi programer morao to svaki put iznova raditi). Ako imamo samo interapt vazan za ADC onda definisemo proceduru za rezervisanom reci int_adc i u okviru nje samo ono sto treba uraditi na pojavu tog interapta. Ako se definise jedna interapt procedura samo se ona proverava, nema potreba proveravati sve. Takodje, moze se uraditi i da korisnik sam definise calokupnu interapt rutinu, recimo koriscenjem rezervisane reci int_user ili neke druge, kada bi se se sve druge int_xxx procedure stavile van snage ili bi kompajler prijavio gresku. E sad ako imamo vise interapta koje obradjujemo redosledom definisanja cemo dobiti koji ce se prvo proveravati (prioritet). Sto se tice ideje oko modula i banaka, ako mislis da ce to ici tako neka bude tako, probaj pa cemo videti kako ce se pokazati u praksi.
[ Odin D. @ 31.07.2008. 16:54 ] @
Citat:
korak
Ako se ne varam PIC troci malo vremena za ulazak i izlazak iz procedure (podprograma).


To sam i ja mislio dok nisam uporedio sa data sheet-ovima drugih proizvodjaca. Stvar je u tome sto Microchip koristi jeftin marketinski trik u kome pored vremena ulaska u interapt ne stoji referenca na fusnutu u kojoj bi napisali da se pri tom ulasku u interapt nista ne snima automatski na stack (kao kod vecine drugih proizvodjaca). Dok se to pop-uje na stack prosao voz....
[ Stojan Trifunovic @ 01.08.2008. 08:14 ] @
Dobro je sto se polako vracamo na temu.

@sander
Ne znam kakva je situacija sa Pic Basicom, ali meni je u PIC16 progamima cesto trebala dvobajtna vrednost. Njenu sintaksu bi najlakse mogli implementirati tako sto se u delu sa definicijama registara definise koliko ce bajtova zauzeti. U relokativnom asemblerskom modu to se radi ovako:
NIZ_BANK1 UDATA 0xA0
godina res .2
duzina res .3
flagovi res .2
sekunde res .1
broj res .4
Na osnovu ovih podataka kompajler bi mogao odmah znati koje je duzine odgovarajuca varijabla. Naravno, svaka postojeca operacija kompajlera (if godina > .2009 (dvobajtna vrednost) then ...; repeat ... until duzina = .2097152 (trobajtna vrednost)) morala bi podrzavati rad sa svim vrednostima (bitskim, jednobajtnim, dvobajtnim, eventualno 3 i 4-bajtnim), sto znaci da ce kompajler morati da sadrzi razne kodove optimizovane bas za taj tip varijabli.
Mislim da je ovo najjednostavnija sintaksa sa polozaja programera. Varijble se definisu samo na jednom mestu, odmah se odredjuje velicina memorije koje zauzimaju, a programer ih koristi kao da su to obicni jednobajtni registri.
Kompajler bi ukoliko programer pokusa uporedjivanje varijabli razlicitog broja bajtova, trebao prijaviti odgovarajucu gresku.

Jos jedan specifican slucaj je testiranje bitova. Kako se u asembleru za to vec koristi ovajanje broja bita od registra obicnim zarezom, mislim da bi programer najjednostavnije koristio ovu sintaksu i za visebajtne varijable. Na primer if W,5 = sekunde,4 then ... za jednobajtne, i if flagovi,3 = flagovi,15 then ... za visebajtne. Naravno trebalo bi odabrati i odgovarajuci izraz za setovane bitove, na primer if flagovi,3 = ON (ili SET) then ...

Znaci, kompajler bi mogao da ima sledece tipove testiranja:
bit definisan nazivom registra, zarezom i rednim brojem bita (pocev od LSB)
bajt definisan nazivom registra
word (dva bajta) definisana nazivom registra, sa tim sto se za njih u definicijama varijabli rezervisu 2 registra
tri bajta definisana nazivom registra, sa tim sto se za njih u definicijama varijabli rezervisu 3 registra
long (4 bajta) definisana nazivom registra, sa tim sto se za njih u definicijama varijabli rezervisu 4 registra

Za testiranje svih ovih tipova kompajler bi morao sadrzati odgovarajuci kod za svaki pojedinacni slucaj. Namerno predlazem nestandardni (za C) oblik varijable od 3 bajta jer bi ceste operacije sa trobajtnim varijablama zauzele manje programske memorije i brzine od cetvorobajtnih, a glavni cilj korakovog kompajlera je sto bolja optimizacija.
Za pocetak, moglo bi se krenuti sa testiranjem samo bitova i celih bajtova, ali bi bilo dobro da korak predvidi i mogucnost eventualne nadogradnje.


@Odin D.

Poznato mi je o cemu pricate (Igrao sam se kao klinac 6510 procesorom Commodora 64) medjutim, rekao sam da se za PIC koristi samo jednu magistrala, (pogresno, slazem se) jer interna struktura PIC-a nije previse bitna za razvoj kompajlera. Koraku je bitno ono sto vidi spolja, a to su svakako samo cetrnaestobitne instrukcije.

Sto se tice gotovih funkcija, Microchip je pored gotovih primera sa projektima predvideo i par AN sa gotovim matematickim funkcijama (u kojima se mogu naci cak i funkcije sa pokretnim zarezom sto je po meni cista perverzija), a koje su upravo namenjene lakoj implementaciji u asemblerskim programima. Nazivi registara definisani su u jednom bloku, i izabrani su tako da budu po nazivu unikatni. Veoma lako se mogu samo iskopirati i ubaciti u odgovarajuci projekat. Precizno su definisane varijable koje trebaju biti dostupne "spolja" za svaku matematicku operaciju, sa primerima njihove primene.

ADC, EEPROM ili RS232 rutine su prilicno jednostavne, i mogu se isto kao i matematicke, veoma lako iskopirati. Za ostale, Microchip je predvideo samostalnu Maestro aplikaciju koja sadrzi sasvim dovoljan broj drajvera, a i na netu se moze naci dosta toga. Bice, naravno tesko sve ovo ubaciti u module, ali mislim da bi vredelo zbog poboljsanja koja bi se dobila mnogo jednostavnijom strukturom jezika.


@korak

Ovako otprilike izgleda standardna interapt rutina za tri interapta:
1. Sacuvaj stanje STATUS i W registra

2. Testiraj flegove i na osnovu njihovog stanja skoci na deo za njihovu obradu (tacke 3, 4 ili 5). Prioriteta nema, iako se mogu definisati unutar ovog koraka (koji fleg ce se prvi testirati).

3. Obrisi fleg1, izvrsi potrebnu operaciju i nastavi od tacke 6

4. Obrisi fleg2, izvrsi potrebnu operaciju i nastavi od tacke 6

5. Obrisi fleg3, izvrsi potrebnu operaciju i nastavi dalje (automatski se nastavlja od tacke 6)

6. Vrati stanje STATUS i W registra

7. retfie (instrukcija za povratak iz interapta)

Ukoliko se bas pogodi da istovremeno nastupe dva (ili vise) interapta, pri prvom pozivu interapta izvrsice se onaj ciji se fleg prvi testira. Onda ce odmah nakon retfie instrukcije nastati sledeci interapt (zbog i dalje setovanog drugog interapt flega) u kome ce se izvrsiti naredni deo. I tako dalje...
Fleg je uvek preporucljivo obrisati odmah na pocetku, kako se ne bi slucajno propustio koji interapt.
[ sander @ 01.08.2008. 08:29 ] @
Samo da dopunim, dokazano u praksi a i mislim da i microchip tako nesto pominje da kod provere koji je interapt aktiviran ide prvo provera da li je taj interapt omogucen pa tek onda da li je interapt flag za taj interapt aktivan da se ne bi desilo da se obradjuje interapt koji nije omogucen.
[ Stojan Trifunovic @ 01.08.2008. 13:22 ] @
To je ipak malo specifican slucaj, i mogao bi se dogoditi jedino da je program tako koncipiran da mu se u jednom delu koristi vise izvora interapta (npr. promenom na RB0 pinu i prekoracenjem tajmera), a da se kasnije jedan od ovih izvora iskljuci.

Zbog cega se to moze dogoditi? Jer se interapt flegovi setuju uvek pri spoljnim uticajima, bez obzira da li je odgovarajuci interapt dozvoljen ili ne. Jedina je razlika sto se onda nece skociti na interapt vektor u slucaju zabranjenog interapta. U tom slucaju, ukoliko je dozvoljen interapt promenom na RB0 pinu, a zabranjen interapt tajmera, prilikom promene na RB0 pinu interapt rutina bi mogla (ukoliko je testiranje flaga tajmera ispred testa RB0 pina - veceg prioriteta) na osnovu flega tajmera zakljuciti da je on izazvao interapt, iako su interapti tajmera ranije zabranjeni.

Problem se moze efikasno resiti kao sto je navedeno prethodnim testom bita dozvole interapta tajmera, ili promenom prioriteta, tako da se uvek najpre testira flag interapta koji se ne iskljucuje u programu.

Da bi se ipak i taj slucaj predvideo, korak bi mogao da interapt proceduru napravi tako da ona jedino snima i vraca sadrzaje registara, a da sve ostalo prepusti programeru.

Jos jedan specifican slucaj predstavlja zabrana svih interapta iz glavnog programa, jer je moguce da ne bude uvek izvrsena, pa je onda potrebno proveriti da li je bit dozvole zaista obrisan, ali to je neka druga prica.
[ Odin D. @ 01.08.2008. 20:23 ] @
@Stojane

Meni se cini da je u ovom slucaju teznja da se napravi kompajler koji bi trebao sacuvati brzinu asemblera koliko god je to moguce. Koliko ce asemblerski program biti efikasan u najvecoj mjeri zavisi od programerovog umijeca, koje izmedju ostalog podrazumijeva i odredjeno razumijevanje sta se tacno u hardveru zbiva prilikom izvrsenja svake instrukcije. To mu omogucava da ih kombinuje na nacin koji je najoptimalniji. Vec sam ranije na nekoj temi naveo jedan jednostavan primjer (doduse ne za pic) gdje se promjenom redoslijeda naredbi znacajno ubrzava dio koda. Kad covjek radi u asembleru on ima mogucnost da na odredjeni nacin iskoristi neke detalje hardvera ako zna. Ako ne zna, onda nikom nista.
Kada se programski jezik podigne cak i na malo veci nivo od asemblera, programer neminovno gubi kontrolu nad nekim stvarima. Naveden je primjer " if W>50 then..." ili tako nesto slicno. To ce kompajler zamjeniti nizom asemblerskih naredbi, ali je pitanje da li ce taj niz biti optimalan ako se ne poznaju detalji hardvera. Medjutim, primjer nije bas najbolji, bolji je npr. ovaj:
ako ja napisem:

c = a * b;

logicno je da je na programskom jeziku ovog nivoa to isto kao i:

c = b * a;

Medjutim, onaj ko poznaje hardver zna da operacija mnozenja kod 99% procesora nece trajati isto za slucaj

mul 2, 100
i
mul 100, 2

vec se moze razlikovati u trajanju i do npr. 50 puta zavisi koji operand gdje stoji.
I sad ako moj mikrokontroler npr. treba zbog skaliranja da svaku izmjerenju vrednost sa AD konvertora (iz opsega 0 do 256) mnozi npr. sa 2, onda ce meni biti vrlo vazno da li cu napisati "mul AD_conv, 2" ili "mul 2, AD_conv". U jednom slucaju ce mikrokontroler mozda stizati da prebacuje analogni snimljeni zvuk u mp3 u realnom vremenu, a u drugom ce mozda kasniti do neupotrebljivosti. Pitanje je da li ce konstruktor kompajlera voditi o tim detaljima racuna ako ne poznaje detaljno hardver. Naravno, teznja je da ja ne moram svaki put da pregledam generisani asm kod, jer u cemu je onda poenta ovog kompajlera ako opet sve moram da pregledam na nivou obicnog asemblera.

Kvalitativne razlike izmedju razlicitih kompajlera upravo i poticu od toga kako ti kompajleri i koliko efikasno koriste hardver. Meni se desavalo da mi neki programi pisani u C-u ne mogu stati u flash ciljnog mikrokontrolera, a kompajlirani sa kompajlerom drugog proizvodjaca stanu u pola istog flasha.
[ Stojan Trifunovic @ 01.08.2008. 22:57 ] @
Jeste, buduci da je korak razocaran brzinom i duzinom koda koji generisu C kompajleri, pretpostavljam da bi mu maksimalna optimizacija ovde bila imperativ.

Upravo zbog bolje optimizacije koda predlazem par "nestandardnih" stvari kao sto su trobajtne varijable, zatim razliciti kod za razlicite slucajeve (npr. testiranje dvobajtnih ili trobajtnih varijabli...).
U principu, kompajler bi se mogao napraviti tako da testira samo cetvorobajtne varijable za sve moguce situacije, ali onda kod uopste nece biti optimizovan.

Dali ste malo nezgodan primer, jer se eto bas mnozenje (i deljenje) sa dva moze realizovati u PIC16F seriji sa dve instrukcije najobicnijom rotacijom. Matematicke rutine (koje bi u kompajleru bile u modulima) svakako bi se mogle dodatno optimizovati i za ove slucajeve, ali smatram da bi ipak to bio preveliki posao. Ako su dovoljno dobre za proizvodjace PIC mikrokontrolera, onda su dobre i za nas. Ionako se uvek trudim da nadjem alternativne metode za mnozenje i deljenje, i uglavnom uspevam. Dobar programer ce uvek biti u stanju da prepozna ovakve situacije i da umesto matematickih modula koristi mnogo, mnogo jednostavnije metode.

Konkretno za primer "if W>50 then" planiram napraviti bar desetinu razlicitih kodova.
1. za slucaj if W>50
2. za slucaj if W>=50
3. za slucaj if W<50
4. za slucaj if W<=50
5. za slucaj if W==P
6. za slucaj if W<>50

pa onda
1. za slucaj if 50>W
2. za slucaj if 50>=W
3. za slucaj if 50<W
4. za slucaj if 50<=W
5. za slucaj if 50==W
6. za slucaj if 50<>W

pa onda
1. za slucaj if W>JednobajtnaVarijabla
2. za slucaj if W>=JednobajtnaVarijabla
3. ...

pa
1. za slucaj if JednobajtnaVarijabla>W
2. za slucaj if JednobajtnaVarijabla>=W
3. ...

i dalje
1. za slucaj if JednobajtnaVarijabla>50
2. za slucaj if JednobajtnaVarijabla>=50
3. ...

i na kraju
1. za slucaj if JednobajtnaVarijabla_A>JednobajtnaVarijabla_B
2. za slucaj if JednobajtnaVarijabla_A>=JednobajtnaVarijabla_B
3. ...

To je ukupno 36 mogucih slucajeva samo za jednobajtne vrednosti. Ako to onda ne bude optimizovano najmanjim mogucim brojem instrukcija ne znam sta bi uopste moglo da bude.

Eventualno, mozda bi se kod mogao dodatno optimizovati za situacije poput "if W>50 AND W<80 then". Njegova optimizacija zahtevala bi dosta veci broj slucajeva, tako da sumnjam da bi se uopste isplatio ulozeni trud zbog ustede samo jedne ili dve instrukcije.

[Ovu poruku je menjao Stojan Trifunovic dana 02.08.2008. u 12:16 GMT+1]
[ korak @ 04.08.2008. 13:02 ] @
Vidim da navodite neke primere i da diskutujete o njima. Kako nemam asembler za PIC, a pricamo o tome da li bi vredeko da takav bide i za njega, navescu kako moj kompajler resava ta slucajeve. Pre toga: cilj mi je bio da jedan iskaz bude jedna asemblerska instrukcija, sem tamo gde ne mora.

Dakle W > 50:

Code:


  ldaa [w];
  cmpa 50;
  if > then
  begin
    <naredbe programa>
  end
  else    //ako treba
  begin
    <naredbe programa>
  end;

;

Drugi slucaj C = A* B u situaciji kada je A konstanta 2^n se svodi na siftanje. Za ovakve funkcije koristim makroe.

Code:

macro Pomnozi(a,b)
begin
  _if VarOf(A) and VarOf(B) then result := Mult(A,B); //Mult je procedura koja mnozi
  quit;  //prekida dalji prevod makroa
  
  _if not VarOf(a) then    
  begin
    _if A  in[2,4,8,16,32,64] then result := Shl(B,A)     //moze i vise od 64, dok to ne postane duze od mnozenja
                              else result := Mult(A,B);
  end
  else 
  begin
     _if B  in[2,4,8,16,32,64] then result := Shl(A,B)     //moze i vise od 64, dok to ne postane duze od mnozenja
                               else result := Mult(A,B);
  end;
end;



_if je komapajlersko if o odredjuje koji delovi programa ce se prevoditi. VarOf() je funkcija koja vraca true ako je parametar varijabla.

Pozdrav.
[ Stojan Trifunovic @ 04.08.2008. 22:47 ] @
U redu. Sada imamo smernice.

16F za razliku od 18F serije ima prilicno limitirane funkcije poredjenja, pa bi se za W > 50 moralo pisati sledece:
Code:

Test                      ; if
        sublw   .50       ; Oduzimanje ce setovati Carry ako je W manje ili jednako broju 50.
        btfss   STATUS,C  ; Preskoci sledecu instrukciju ako je Carry setovan
        goto    Veci      ;

Manji                     ; else ili nastavak - ako je W <= 50
....

Veci                      ; then - ako je W > 50
.....

Kako ovo radi? Najpre se od W oduzme broj 50. Rezultat se smesta u W cime se on menja. Ukoliko je ovo nepozeljno, mogao bi se privremeno sacuvati i kasnije vratiti, kao u interaptima.
Oduzimanje se u 16f seriji hardverski obavlja sabiranjem sa drugim komplementom, tako da ce Carry biti setovan ukoliko ima pozajmice, ili ukoliko su brojeci isti.
Ako je Carry setovan preskocice se sledeca instrukcija (goto Veci) i nastavice se od labele Manji. Ako nije, izvrsice se instrukcija goto Veci, i program ce nastaviti odatle.

Za slucaj da je neophodno sacuvati W moglo bi se pisati sledece:
Code:

Test                      ; if
        movwf   TEMP      ; W u TEMP
        sublw   .50       ; Oduzimanje ce setovati Carry ako je W manje ili jednako broju 50.
        movf    TEMP,W    ; Povratak iz TEMP u W
        btfss   STATUS,C  ; Preskoci sledecu instrukciju ako je Carry setovan
        goto    Veci      ;

Manji                     ; else ili nastavak - ako je W <= 50
....

Veci                      ; then - ako je W > 50
.....

Znaci, za Vas slucaj
Code:

  ldaa [w];
  cmpa 50;
  if > then

kompajler bi trebao kopirati jedan od gornjih kodova. Koji, zavisi od toga da li se zeli da W registar ostane nepromenjen.


Mnozenje bi se i u 16F i u 18F serijama moglo obavljati na potpuno isti nacin (rotacijom). Nisam znao da imate i mogucnost uslovnog kompajliranja! Utoliko bolje.
[ korak @ 05.08.2008. 12:13 ] @
Ja sam napisao primer:

Code:

  ldaa [w];
  cmpa 50;
  if > then
  begin
    inca;
  end
  else
  begin
    deca;
  end;


Ali evo i prevoda da vidis kako kompajler prevodi if..then..else

Code:

   $6010 : $b652       [3] ldaa    [$52]
   $6012 : $a132       [2] cmpa     $32
   $6014 : $2303       [3] bls      $6019

   $6016 : $4c         [1] inca
   $6017 : $2001       [3] bra      $601a
   --------------------------------------
   $6019 : $4a         [1] deca
   $601a :


Prva kolona je adresa, zatim kod naredbe u heksa ciframa, u srednjim zagradama trajanje naredbe u ciklusima i na kraju asemblerska naredba. Naredba bls je granjanje ako je manje ili jednako. Mislim da ti je prevod jasan.

Slicno tome za PIC bi bilo:
Code:

  sublw 50;
  if >= then  //uzet uslov >= jer kod 16F je komplikovanije realizovati uslov >
  begin
     incf [49].0;
  end
  else
  begin
     decf [49],0;
  end;


Komapajler bi to trebao da prevede nekako ovako:

Code:

  $0100 :  sublw $32;
  $0101 :  btfsc STATUS,C;
  $0102 :  goto $0105;
  $0103 :  incf [$31],0;
  $0104 :  goto $0106;
  $0105 :  decf [$31],0;
  $0106 :


sto nije neki problem za realizaciju. Primecujes da je za ovo potrebno uvesti dve labele u klasicnom asembleru, a u ovom mom nema ni jedne. Nisam siguran da li sam dobro napisao asemblerski kod za PIC, ispravite me ako sam pogresio.

Pozdrav
[ Stojan Trifunovic @ 05.08.2008. 23:02 ] @
Prevod mi je jasan (stavise, skoro je isti kao za 6510), ali program za PIC nije ispravan. Sa btfsc instrukcijom koju ste upotrebili, Vas program bi izvrsio inkrementaciju bas za istinit slucaj "if W > 50", odnosno za onaj koji ste naveli kao tezi. Uopste nije tezi. Dovoljno je izokrenuti oduzimanje po sledecem:
Code:

   movf    BROJ,W ; BROJ u W
   sublw   .2     ; W = 2 - BROJ

   movlw   .2      ; 2 u W
   subwf   BROJ,W  ; W = BROJ - 2

Ovakav nacin pruza mogucnost lakog dobijanja poredjenja <, >, <= i >=. Za == i <> testirao bi se Zero flag.

Koliko sam ukapirao, ukoliko se u vasem kompajleru stavi znak ; iza instrukcije, onda to oznacava asemblersku instrukciju koju kompajler samo prepisuje (eventualno menjajuci brojni sistem). Medjutim, jedna stvar mi onda nije jasna. Na koji nacin je u tom slucaju u kompajleru definisano nad kojim ce se varijablama vrsiti testiranje? Mislim, bilo bi jasnije da se stavi "if W >= 50" nego "if >=". A sta u situacijama kada bi bilo potrebno porediti "if 50 < W" ili dve varijable "if A <= B"?

I jos nesto! Ne bi li bilo zgodnije da se umesto
Code:

  sublw 50;
  if >= then  //uzet uslov >= jer kod 16F je komplikovanije realizovati uslov >
  begin
....

pise samo
Code:

  if W >= 50 then  //uzet uslov >= jer kod 16F je komplikovanije realizovati uslov >
  begin
....

Zbog toga predlazem da za svaki pojedinacni slucaj (<, >, <=, >=, =, <>) i za sve moguce oblike varijabli (W, jednobajtna i eventualno visebajtne varijable) kompajler kopira poseban kod, bas za tu operaciju. Onda bi kompajler sam brinuo o oduzimanju, skokovima i testiranju flegova. Ovako samo eliminise labele (nije ni to mala prednost) ali za racunanje koliko mi se cini ostavlja programeru pisanje instrukcija koje ce na odgovarajuci nacin promeniti flegove.

Tih 36 razlicitih slucajeva (za jednobajtne varijable) i nije toliko mnogo, za ono sto bi se njima dobilo. Ipak bi takav kod bio maksimalno optimizovan bas za svaki pojedinacni slucaj.
[ korak @ 06.08.2008. 13:23 ] @
Da, u pravu si,
jos uvek razmisljam na 'motorola' nacin. Ovde se testira bit u statusnoj reci, i za '>=' C = 0, a za '<' C = 1, zar ne. U pravu si i za ono drugo, ako se obrne oduzimanje, onda moze da se ostvari ono sto sam rekao da je komplikovano. Opet iz razloga koje sam malopre naveo, otelo mi se da kazem da je komplikovanije, jer motorola za '>' testira istovremeno C i Z bit.

Ipak, iz opreza da kazem da mi se cini komplikovanim, uporedjivanje oznacenih brojeva kod PIC-a. Na primer u w ja 10 a uporedujes sa $FF sto je -1. Ovde bi uporedjenje pokazalo da je manja vrednost u w, a ustvari je veca. Ja znam da za svaki MCU postoji posebna tehnika pisanja softvera koja resava sve slucajeva, pa me interesuje kako se ovaj slucaj resava.

Moj cilj, kada sam pisao asembler nije bio da napravim visi programski jezik, jer bi onda taj jezik izgubio na snazi. Cilj mi je bio da to i dalje bude asembler, ali da je kompajler u stanju da uradi umesto programera sve ono sto moze sa ciljem da se olaksa programeru posao. Postoje tu i druge stvari repeat..until petlja, while..do petlja case..of struktura, vrlo mocni makroi, prenos parametara procedurama i funkcijama i moduli kao posebne programske celine u posebnim fajlovima i koji mogu da se koriste u raznim softverskim projektima. Dakle, to mi je bio cilj, da se ne udaljim previse od asemblera.

Pozdrav.

[ Stojan Trifunovic @ 06.08.2008. 23:13 ] @
@korak
"za '>=' C = 0, a za '<' C = 1, zar ne."
U principu jeste, ali zavisi od toga kako je reseno prethodno oduzimanje.

Uporedjivanje oznacenih brojeva? Moram da priznam da o njima uopste nisam razmisljao. Nemam mnogo iskustava sa njima, ali mislim da bi najjednostavniji nacin poredjenja podrazumevao da se najpre uporedi bit znaka (MSB). Ukoliko se ne slaze, rezultat poredjenja se moze odmah dobiti (+ je uvek > od -). Ukoliko je znak isti i pozitivan nastavlja se sa obicnim poredjenjem, a ako je isti i negativan obe varijable se komplementuju i obrise im se MSB, pa se onda standardno porede. Kod za obicno poredjenje je uvek isti, tako da kompletan kod ne bi morao biti previse dug.
Mozda postoji i jednostavniji nacin. Zna li ko?

Mislim da bi bilo najbolje pre ikakve dalje diskusije definisati tipove varijabli i njihovu sintaksu.

Predlazem sledece:
bit sa sintaksom W,3 (ON,OFF)
bit sa sintaksom REGISTAR,5 (ON,OFF)
neoznaceni bajt sa sintaksom W
neoznaceni bajt sa sintaksom REGISTAR (0,+255)
oznaceni bajt sa sintaksom nestoW (-128,+127)
oznaceni bajt sa sintaksom nestoREGISTAR (-128,+127)
word (2 bajta) sa sintaksom REGISTAR (0,+65535)
oznaceni word sa sintaksom nestoREGISTAR (-32768,+32767)
tri bajta sa sintaksom REGISTAR (0,+16777215)
Oznacena tri bajta sa sintaksom nestoREGISTAR (-8388608,+8388607)
long (4 bajta) sa sintaksom REGISTAR (0,+4294967295)
Oznaceni long sa sintaksom nestoREGISTAR (-2147483648,+2147483647)

To "nesto" mogao bi biti neki od znakova interpunkcije. Sigurno da negde postoji standardizovani oblik predstavljanja oznacenih brojeva, ali meni eto nije poznat.

Jednobajtne i visebajtne varijable ovako bi imale istu sintaksu, ali kompajler bi pravio razliku izmedju njih na osnovu podataka iz deklaracionog bloka.

Za pocetak, mogli biste krenuti samo sa bit i bajt tipovima, ali tako da predvidite moucnost nadgradnje kompajlera i za ostale tipove.

Takodje, predlazem da deklaracija varijabli bude jedino unutar deklaracionog bloka, i da se odmah u njemu definise oznacenost i velicina varijabli (jedan ili vise bajtova).
Code:

var bank 0 [0x20..0x6F]
  <deklaracija varijabli >

var bank 1 [0xA0..0xEF]
  <
   DAN    res 1
   MESEC  res 1
   GODINA res 2
   TROBAJTNA_VARIJABLA res 3
   nestoOZNACENA_DVOBAJTNA_VARIJABLA res 2
   >


Buduci da se ne biste previse udaljavali od asemblera, pojasnite nam da li uopste nameravate ubaciti visebajtne varijable i oznacene brojeve (ukoliko ne postoji jednostavniji nacin poredjenja).
Takodje, da bi kod bio sto blizi asembleru, prakticnije bi bilo ne uporedjivati direktno dve varijable ili varijablu sa konstantnom vrednoscu, vec samo W sa konstantnom vrednoscu ili W sa varijablom.

Dakle definisite do koje dubine zelite ici, a konkretne kodove prepustite meni. Bar za if..then, repeat..until, while..do i case..of. Za makroe, prenose parametara i module ne verujem da cu Vam moci pomoci.
[ korak @ 07.08.2008. 11:50 ] @
Evo ovako,
MMA (makro mega asembler, tako ga zovem) ima sledece preddefinisane tipove:

Code:

Ime tipa    Duzina u bajtovima    Opseg vrednosti
byte                1                  0..255
shortint            1                -128..127
char                1                #0..#255
word                2                0..65535
integer             2             -32768..32767
longword            4             0..4294967295
longint             4         2147483648..2147483647
real                4         ±(5.88e-39..6.81e+38),0
boolean             1            true, folse (1,0)
string             256           0..254 karaktera



Pa bi primer tvojih deklaraciija bio:

Code:


var bank 0 [0x20..0x6F]
  <deklaracija varijabli >

var bank 1 [0xA0..0xEF]
  <
   DAN  : byte
   MESEC  : byte
   GODINA : word
   TROBAJTNA_VARIJABLA : array[0..2] of byte
   nestoOZNACENA_DVOBAJTNA_VARIJABLA : integer
   >


Sto se programskih struktura tice, pogledaj prikaceni fajl, koji je jedno nedovrseno uputstvo, i samo njegov podnaslov 'Karakteristicne programske strukture'. Bice mi vazno kako ti kao poznavalac PIC-a mislis da se tako nesto moze sto efikacnije implementirati na PIC.

Pozdrav.
[ Stojan Trifunovic @ 07.08.2008. 12:47 ] @
Trenutno nemam vremena za fajl (pogledaću ga sutra), ali recite mi želite li znači u asembler za PIC ubaciti sve te oblike varijabli?
[ korak @ 07.08.2008. 14:45 ] @
Da, to je dobro za povecanje pouzdanosti softvera, a olaksava i odrzavanje.

Pozdrav.
[ Stojan Trifunovic @ 08.08.2008. 07:10 ] @
Pogledao sam fajl, i mislim da ce za PIC16 seriju biti najteze realizovati operacije sa oznacenim brojevima, jer jednostavno u PIC16 seriji ne postoje instrukcije koje ih podrzavaju. Ostale strukture ne bi trebale predstavljati problem. U principu mogu se odraditi i oznaceni brojevi, ali uz duzi kod.

Evo (za pocetak) primera za testiranje W sa konstantom.
Radi lakseg razumevanja uzeo sam da se registar inkrementuje ako je uslov ispunjen, da se dekrementuje ako nije, i jednu praznu instrukciju (nop) pri nastavku programa.

if W > konstante 50 then inc else dec
Code:

  if W > 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $0100 : sublw   $32;
 $0101 : btfsc   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if W < konstante 50 then inc else dec
Code:

  if W < 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0100 : movwf   TEMP;
 $0101 : movlw   $32;
 $0102 : subwf   TEMP,W;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if W >= konstante 50 then inc else dec
Code:

  if W >= 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0100 : movwf   TEMP;
 $0101 : movlw   $32;
 $0102 : subwf   TEMP,W;
 $0103 : btfss   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if W <= konstante 50 then inc else dec
Code:

  if W <= 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0100 : sublw   $32;
 $0101 : btfss   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],0;
 $0104 : goto    $0106;
 $0105 : decf    [$31],0;
 $0106 : nop;


if W == konstante 50 then inc else dec
Code:

  if W == 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $0100 : xorlw   $32;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if W <> konstante 50 then inc else dec
Code:

  if W <> 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $0100 : xorlw   $32;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;





Sada evo primera za testiranje konstante sa W. Naravno, kod koji bi proizvodio kompajler je isti kao i ranije, jedino je znak poredjenja (<, >, <= i >=) promenjen.
Opet je radi lakseg razumevanja uzet prethodni slucaj (inkrementuja, dekrementacija i nop).

if konstanta 50 < W then inc else dec
Code:

  if 50 < W then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $0100 : sublw   $32;
 $0101 : btfsc   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if konstanta 50 > W then inc else dec
Code:

  if 50 > W then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0100 : movwf   TEMP;
 $0101 : movlw   $32;
 $0102 : subwf   TEMP,W;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if konstanta 50 <= W then inc else dec
Code:

  if 50 <= W then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0100 : movwf   TEMP;
 $0101 : movlw   $32;
 $0102 : subwf   TEMP,W;
 $0103 : btfss   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if konstanta 50 >= W then inc else dec
Code:

  if 50 >= W then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0100 : sublw   $32;
 $0101 : btfss   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],0;
 $0104 : goto    $0106;
 $0105 : decf    [$31],0;
 $0106 : nop;


if konstanta 50 == W then inc else dec
Code:

  if 50 == W then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $0100 : xorlw   $32;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if konstanta 50 <> W then inc else dec
Code:

  if 50 <> W then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $0100 : xorlw   $32;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


Sve ovo su slucajevi za if...then...else... strukturu. Za obicnu if...then... strukturu izbacio bi se donji deo.
TEMP varijablu je pozeljno staviti u deljene (izmedju svih banki) registre.
Code:

var shared_bank [0x70..0x7E]
  <
   TEMP  : byte
  >


Koriscenjem "nestandardnog" W registra kao varijable se malo pobeglo od osnovnih tipova varijabli vaseg MMA, ali smatram da bi ipak pozeljno bilo uvesti i ovaj tip, jer se (relativno) najkrace prevodi, a cesto se srece u asemblerskim programima, bar za PIC.

[Ovu poruku je menjao Stojan Trifunovic dana 08.08.2008. u 08:38 GMT+1]
[ Stojan Trifunovic @ 08.08.2008. 08:40 ] @
Da ne bih duzio sa ostalim if...then...else... primerima, da probam da implementiram i ostale programske strukture.

Buduci da u korakovom uputstvu programska struktura repeat...until... koristi nizove koje PIC16 serija ne podrzava najbolje, ogranicicu se na (za PIC16) jednostavnije primere.

Struktura repeat SABIRAK + 5 until SABIRAK > 50 bi izgledala ovako:
Code:

repeat
  movlw   5;
  addwf   SABIRAK,F;
until SABIRAK > 50
nop;


$0100 : movlw    $05;
$0101 : addwf    SABIRAK,F;
$0102 : movf     SABIRAK,W
$0103 : sublw    $32;
$0104 : btfsc    STATUS,C;
$0105 : goto     $0100;
$0106 : nop;


Ovaj kod bi se mogao dodatno optimizovati za slucajeve brojenja unapred (samo do 256) ili unazad (samo do 0) koristeci incfsz ili decfsz instrukciju:

repeat SABIRAK + 5, dec INDEX until INDEKS = 0
Code:

repeat
  movlw   5;
  addwf   SABIRAK,F;
  decfsz  INDEX,F;
until INDEX = 0
nop;


$0100 : movlw    $05;
$0101 : addwf    SABIRAK,F;
$0102 : decfsz   INDEKS,F;
$0103 : goto     $0100
$0104 : nop;


Ovaj slucaj bio bi ipak tezi za implementaciju jer bi kompajler morao gledati i instrukciju pre until direktive, i na osnovu nje detektovati da li moze dodati samo goto instrukciju ili mora izvrsiti i odgovarajuce testiranje.
[ Stojan Trifunovic @ 08.08.2008. 11:26 ] @
Da pogledamo ostale strukture. Case...of... struktura bi se mogla ovako napraviti:
Code:

case W of
1,9,21,30 : incf [49],F;
31,50,70,90 : decf [49],F;
else clrf [49];
end;
nop;


 $0100 : xorlw $01;  // Da li je W == 1?
 $0101 : btfsc STATUS,Z;
 $0102 : goto  $011A;
 $0103 : xorlw $08;  // Da li je W == 9? W je sada postao (W XOR $01) XOR ($01 XOR $09), sto je isto kao W XOR $09.
 $0104 : btfsc STATUS,Z;
 $0105 : goto  $011A;
 $0106 : xorlw $1D;  // W == 21? ($08 XOR $15)
 $0107 : btfsc STATUS,Z;
 $0108 : goto  $011A;
 $0109 : xorlw $03;  // W == 30? ($1D XOR $1E)
 $010A : btfsc STATUS,Z;
 $010B : goto  $011A;
 
 $010C : xorlw $1C;  // W == 31? ($03 XOR $1F)
 $010D : btfsc STATUS,Z;
 $010E : goto  $011C;
 $010F : xorlw $2E;  // W == 50? ($1C XOR $32)
 $0110 : btfsc STATUS,Z;
 $0111 : goto  $011C;
 $0112 : xorlw $68;  // W == 70? ($2E XOR $46)
 $0113 : btfsc STATUS,Z;
 $0114 : goto  $011C;
 $0115 : xorlw $32;  // W == 90? ($68 XOR $5A)
 $0116 : btfsc STATUS,Z;
 $0117 : goto  $011C;
 
 $0118 : clrf  [49];    // deo za else
 $0119 : goto  $011D;
 
 $011A : incf  [49],F;  // incf
 $011B : goto  $011D;
 
 $011C : decf  [49],F;  // decf
 $011D : nop;           // nastavak

Kompajler bi morao automatski izracunavati XOR za svaki sledeci clan.
Zasto je upotrebljen ovako nerazumljiv (spagete) kod? Zato sto je najoptimizovaniji, i zato sto ne zahteva TEMP registar. Kada se W dva puta XOR-uje istom vrednoscu, vraca mu se originalna vrednost. Jeste komplikovanije, ali komplikovaniji je i quick sort algoritam, pa je ipak najbrzi. Ionako ce kod biti skriven od programera.
Naravno da se ovo moglo izbeci, ali onda bi se za svako poredjenje pored TEMP registra trosila instrukcija vise.

Verovatno bi prakticnije bilo da se instrukcije koje slede u slucaju ispunjenja (i neispunjenja) uslova stave u bloku ovako:
Code:

case W of
1,9,21,30 :
  begin
    incf [49],F;
  end
31,50,70,90 :
  begin
    decf [49],F;
  end
else
  begin
    clrf [49];
  end;
nop;



Mislim da nisam najbolje shvatio sintaksu i komparaciju iz vaseg uputstva . Konkretno, sta ce se dogoditi sa sledecim kodom:
[/code]
ldaa [bb];
case AccA of
1,9,21..30 : inca;
31..50,70..90 : deca;
else clra;
end;
staa [bb];
[/code]
Znaci li to inkrementaciju ukoliko je vrednost u akumulatoru u opsegu od 21 do 30 i dekrementaciju ukoliko je od 31 do 50 i od 70 do 90 ili nesto drugo?
[ korak @ 08.08.2008. 13:01 ] @
Sto se toce primera za koji kazes da nisi shvatio, ustvari, dobro si ga shvatio. Ako se brojevi nalaze jedan za drugim nema potrebe komparacija sa njuma nego samo sa granicama opsega,to je krace, zar ne.

Sve primere si odlicno rucno preveo, i sigurno naslucuhes da bi to bilo lako i kompajleru. Uslov koji pises kao w > 50 nije praktican, on nije upotrebljiv za dvobajtve i visebajtbe varijable. Video si da ja tu koristim samo znake uporedjenja koji u stvari testiraju flegove u statsusnom registru. Tako ako longint testiras da li je nula, orujes sve bajtove, i testitas dali je resultat orovanja 0, odnosno da li se setovao Z fleg.

Simbolne znake za uslov koristim sa znacenjem:

Code:

Za neoznacene brojeve:

IfSimbol      Zavisnost od flegova   Mnemonik
   =                  if Z = 1         beq
  <>                  if Z = 0         bne
   <                  if C = 1         bcs/blo
  <=                  if C+Z = 1       bls
   >                  if C+Z = 0       bhi
  >=                  if C = 0         bcc/bhs


Za oznacene brojeve:

IfSimbol      Zavisnost od flegova      Mnemonik
   +            if N = 0                  bpl
   -            if N = 1                  bmi
  =0            if Z = 1                  beq
 <>0            if Z = 0                  bne
  <0            if N eor V                blt
 <=0            if Z+(N eor V) = 1        ble
  >0            if Z+(N eor V) = 0        bgt
 >=0            if N eor V = 0            bge


Ostali simboli zna~e:

IfSimbol       Zavisnost od flegova    Mnemonik
  cc                  if C = 0          Bcc/bhs
 sc/cs                if C = 1          Bcs/blo
 cv/vc                if V = 0          bvc
 sv/vs                if V = 1          bvs





N je fleg za znak, a V je fleg za prekoracenje oznacenih brojeva

Kao sto vidis, posle bilo kojih operacija sa visebajtnim brojevima testiram flegove statusnoig registra. Da ne buh pamtio, sto mi nikada ne bi uspelo, da koristim ble, bgt, bge i t. d. vec mi je to jednostavnije sa uvodjenjem ovih znakova uporedjenja. Zapazas da kada se testira uporedjenje oznacenih brojeva, da se uz znake uporedjenja pise 0.

I repeat..until si dobro uradio, ali ja bih uz until napisao:

until decr(INDEX) =0;

a izostavio decfsz INDEX,F; ali bi kompajler preveo:

decfsz INDEX,F;
goto $0100;

Tablica koju sam prikazao je potpuna sa svim skokovima. Ali PIC nema potpunu tablicu, i u pravu si sto kazes da bi se tu potrosilo malo vise koda kako bi se obuhvatili svi slucajevi.

Dakle, ovo sa uslovnim granjanjima bi se dalo resiti, ostaje problem brojeva sa znakom. Jedna od tehnika je da svako osnaceni bajt bude uvecan za 128, kako bi uvk bio pozitivan. Ali, pri svakom sabiranju takva dva bajta treba oduzeti 128 (jer bi rezultat bio uvecan za 256), a kod oduzimanja treba dodati 128. Dvobajtne oznacene vrednosti trebaju da budu uvecane za 32768 i t. d. No, srecom malo se koriste oznaceni brojevi.

Ostaje za mene nepoznata stvar, a to su lokalne dinamicke varijable. Video sam kako to rade C kompajleri, ali mi nije mnogo jasno. Oni kao da prvo analiziraju koja funkcija poziva neku drugu, i koliko u jednom trenutku ima najvise lokalnih varijabli, i onda prostor za njih obezbedjuje na RAM-u. Taj mehanizam mi se cini komplikovanim. Ima li neko ilju ideju?

Pozdrav
[ Stojan Trifunovic @ 08.08.2008. 23:02 ] @
Uslov W < 50 (i ostali) svakako nije praktican za visebajtne varijable, ali jos nisam poceo ni implementaciju jednobajtnih, a kamoli visebajtnih varijabli. Kada budem, krenucu od if...then...else strukture sa testom npr. if GODINA > 2008 then inc else dec.

U pravu ste za decfsz. Ipak je bolje "until decr(INDEX) =0;".

Za dinamicke varijable, ne znam kako su resene u C, ali u relokativnom asemblerskom modu o njima brine linker. Kako je prethodno potrebno definisati sve varijable koje se koriste u programu kao i pripadnost bankama (BANK0, BANK1, SHARED, OVR-za dinamicke varijable) ali ne stavljajuci im apsolutnu adresu, linker ce svaku varijablu koja pripada OVR sekciji jednostavno prebrisati nakon izlaska iz tekuce procedure (fajla). To naravno nije resenje ukoliko se zeli gnezdjenje procedura, ali je ipak kakvo takvo resenje.
[ Stojan Trifunovic @ 09.08.2008. 06:46 ] @
Kako mi je sada jasnija case...of... struktura, nastavljam sa njom, ali i dalje samo za W.
Code:

case W of
1,9,21..30 : incf [49],F;
31..50,70..90 : decf [49],F;
else clrf [49];
end;
nop;

 $0100 : movwf TEMP;
 $0101 : xorlw $01;       // Da li je W == 1?
 $0102 : btfsc STATUS,Z;
 $0103 : goto  $0121;     // Jeste. Idi na inc
 $0104 : xorlw $08;       // Da li je W == 9?
 $0105 : btfsc STATUS,Z;
 $0106 : goto  $0121;     // Jeste. Idi na inc
 
 $0107 : movf  TEMP,W;
 $0108 : sublw $15;       // W > 21?
 $0109 : btfsc STATUS,C;
 $010A : goto  $010F;     // Nije, idi dalje na provere.
 $010B : movlw $1E;       // Jeste. W < 30
 $010C : subwf TEMP,W;
 $010D : btfss STATUS,C;
 $010E : goto  $0121;     // Jeste. Idi na inc

 $010F : movf  TEMP,W;
 $0110 : sublw $1F;       // W > 31?
 $0111 : btfsc STATUS,C;
 $0112 : goto  $0117;     // Nije, idi dalje na provere.
 $0113 : movlw $32;       // Jeste. W < 50?
 $0114 : subwf TEMP,W;
 $0115 : btfss STATUS,C;
 $0116 : goto  $0123;     // Jeste. Idi na dec

 $0117 : movf  TEMP,W;
 $0118 : sublw $46;       // W > 70?
 $0119 : btfsc STATUS,C;
 $011A : goto  $011F;     // Nije, idi dalje na provere.
 $011B : movlw $32;       // Jeste. W < 5A?
 $011C : subwf TEMP,W;
 $011D : btfss STATUS,C;
 $011E : goto  $0123;     // Jeste. Idi na dec

 $011F : clrf  [49];      // deo za else
 $0120 : goto  $011D;
 
 $0121 : incf  [49],F;    // inc
 $0122 : goto  $011D;
 
 $0123 : decf  [49],F;    // dec
 $0124 : nop;             // nastavak


Sve pojedinacne case slucajeve kompajler bi trebao (za slucaj da programer to nije uradio) prebaciti na pocetak koda, ovako:
Code:

Umesto:
case W of
1,9,21..30,18,93 : incf [49],F;
31..50,70..90,55,99 : decf [49],F;

staviti:
case W of
1,9,18,93,21..30 : incf [49],F;
55,99,31..50,70..90 : decf [49],F;
[ korak @ 09.08.2008. 06:59 ] @
Upravo si mi dao jednu korisnu ideju.

Izraza sam naravno izbacio jer zapravo oni cine kod manje efikasnim (na primer a+b*c >= d*(d-c) i t. d.) u asembleru zavisno od varijabli programer moze bolje iskoristiti neke specificnosti i napisati kraci i brzi kod od onog koji bi na primer C generisao. Negde sam video PASCAL kompajler (zaboravio sam za koji MCU) gde izrazi mogu da budu samo tipa c := a opeaija b; i nista vise. Dakle, nema medjurezultata i ima sanse da kod bude vrlo efikasan. Tako i tvoje Godina > 2008 mi daje ideju da izraz bude sto prostiji: a := b ili a operator uporedjivanje b. Zapravo izraz bi bio a operator b, gde operator moze da bude samo operator dodele ili relacioni operator (oparator uporedjivanja).

Posto sam zavrsio 3 verziju kompajlera, sada bas radim na ovim finesama. Ideja po kojoj radim je da koristim makroe, Tako sam napisao macro Value() koja se koristi a := Value(b). Vec sam napravio da makro moze da bude parametar funkcije ili procedure, i namera mi je da makro ubacim u if..then i ostale uslovne strukture. Prednost makroa je sto moze da ima vise parametara i da realizuje i slozenije izraze. Zato mi tvoja ideja stvara dilemu, vrlo je ocigledna i citljiva za razliku od makroa, koje jos moras i da pises, doduse samo jednom. Najvise mrzim kada imam dilemu, moracu da dobro odvagam ove dve mogucnosti.

Pozdrav.
[ Stojan Trifunovic @ 09.08.2008. 07:31 ] @
Da krenem sa testom jednobajtne neoznacene varijable (byte) i konstante. Neka naziv varijable bude BROJ.

if BROJ > konstante 50 then inc else dec
Code:

  if BROJ > 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    BROJ,W
 $0100 : sublw   $32;
 $0101 : btfsc   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if BROJ < konstante 50 then inc else dec
Code:

  if BROJ < 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0101 : movlw   $32;
 $0102 : subwf   BROJ,W;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if BROJ >= konstante 50 then inc else dec
Code:

  if BROJ >= 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0101 : movlw   $32;
 $0102 : subwf   BROJ,W;
 $0103 : btfss   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if BROJ <= konstante 50 then inc else dec
Code:

  if BROJ <= 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    BROJ,W
 $0100 : sublw   $32;
 $0101 : btfss   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],0;
 $0104 : goto    $0106;
 $0105 : decf    [$31],0;
 $0106 : nop;


if BROJ == konstanta 50 then inc else dec
Code:

  if BROJ == 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    BROJ,W
 $0100 : xorlw   $32;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if BROJ <> konstante 50 then inc else dec
Code:

  if BROJ <> 50 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    BROJ,W
 $0100 : xorlw   $32;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;




Sada evo primera za testiranje konstante sa jednobajtnom varijablom BROJ.

if konstanta 50 < BROJ then inc else dec
Code:

  if 50 < BROJ then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    BROJ,W
 $0100 : sublw   $32;
 $0101 : btfsc   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if konstanta 50 > BROJ then inc else dec
Code:

  if 50 > BROJ then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0101 : movlw   $32;
 $0102 : subwf   BROJ,W;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if konstanta 50 <= BROJ then inc else dec
Code:

  if 50 <= BROJ then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0101 : movlw   $32;
 $0102 : subwf   BROJ,W;
 $0103 : btfss   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if konstanta 50 >= BROJ then inc else dec
Code:

  if 50 >= BROJ then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    BROJ,W
 $0100 : sublw   $32;
 $0101 : btfss   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],0;
 $0104 : goto    $0106;
 $0105 : decf    [$31],0;
 $0106 : nop;


if konstanta 50 == BROJ then inc else dec
Code:

  if 50 == BROJ then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    BROJ,W
 $0100 : xorlw   $32;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if konstanta 50 <> BROJ then inc else dec
Code:

  if 50 <> BROJ then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    BROJ,W
 $0100 : xorlw   $32;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;

Ocigledno je da je kod samo neznatno izmenjen.



Nisam bas najbolje shvatio Vas zadnji post, ali pretpostavljam da je u pitanju sledeci slucaj.
Na pocetku "GODINA := (((A + B) * C) / D)" i kasnije "if GODINA == 2009 then...else..."
Mislim da je ovo daleko prakticnije od "if (((A + B) * C) / D) == 2009 then...else..." u pogledu razumljivosti koda, ali mozda malo manje prakticno u pogledu njegove optimizovanosti. U ovom slucaju, ipak bih namerno zrtvovao par instrukcija zbog bolje citljivosti.

Ne bih se toliko brinuo oko izraza. U asembleru ce se moci odraditi na koji god moguci nacin, pa eto i makroima. Ipak, uporedjivanje visebajtnih varijabli je itekako dobrodoslo.

Jedino eventualno poboljsanje koje bi bilo korisno uvesti su naprednije mogucnosti uslovnog grananja sa OR, AND i NOT logickim operacijama poput: "if GODINA >= 2009 AND GODINA <= 2011 then PRESTUPNA_GODINA == false", medjutim nisam siguran koliko bi njih bilo moguce optimizovati.
[ korak @ 09.08.2008. 14:37 ] @
Sa primerom izraza sam samo hteo da ukazem na cinjenicu da dok se on prevodi postoje medjurezultati koji negde mora da se pamte. Obocno se oni pamte na steku, ali to nije moguce kod PIC-a osim da se za to odvoji poseban prostor na RAM-u.

Teoretski ne postoji prepreka da visi programski jezik ne prevodi 100% efikasno, ali prakticno to je nemoguce. Postoje razradjeni metodi optimizacije prevodjenja ali svi oni uvode neke predpostavke da bi postupak kompajliranja mogao da se realizuje. Upravo te predpostavke dovode do toga da se smanjuje efikasnost prevodjenja.

Na primer sabiramo dve varijable koje su kompatibilnih tipova, sto znaci da mogu da se saberu.

1. svaka od njih moze biti: byte, shortint, integer, word, longint, longword, to je 15 kombinacija;
2. svaka od njih moze biti karakter ili string, to je 4 kombinacije
3. svaka moze biti skup, to je 1 kombinacija

Ukupno imamo 20 kombinaija koda samo za sabiranje. Ako svaka varijabla moze biti staticka i dinamicka to je 20 x 4 = 100 kombinacija. Kada se tome dodaju i druge operacije (oduzimanje, mnozenje, deljenje, siftanje, logicke operacije i t. d.) broj kombinacija kodova pravoda se priblizava broju od oko 800. Ovu analizu sam pravio. E sada, moguce je uvesti niz predpostavki, ogranicenja na kojim registrima ce se vrsiti operacije i t. d. i da se problem pojednostavi tako da moze da se resi za razumno vreme. Cena toga je smanjenje efikasnosti.

Ja sam se opredelio da ostanem sto blize asembleru, a da napravim snazan mehanizam makroa kojima mogu da se resavaju problemi sa slozenijim izrazima Osim toga makroi, kako sam ih ja koncipirao pruzaju i neke sitne elemente objektnog programiranja, mada mi to nije bilo ni na kraj pameti.

Dakle, treba drzati sto tesnju vezu sa asemblerom. Ono sto si napisao odgovara tome, ali ako budes sirio problem komplikovace se geometrijskom progresijom.

Pozdrav.
[ Stojan Trifunovic @ 09.08.2008. 16:44 ] @
Pa nista. Realizujte onda samo poredjenje ovih varijabli, a matematiku prepustite programeru i asembleru.

Evo sada primera za poredjenje dve varijable (A i B) byte tipa.

if A > B then inc else dec
Code:

  if A > B then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    A,W;
 $0100 : subwf   B,W;
 $0101 : btfsc   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if A < B then inc else dec
Code:

  if A < B then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0101 : movf    B,W;
 $0102 : subwf   A,W;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if A >= B then inc else dec
Code:

  if A >= B then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0101 : movf    B,W;
 $0102 : subwf   A,W;
 $0103 : btfss   STATUS,C;
 $0104 : goto    $0107;
 $0105 : incf    [$31],W;
 $0106 : goto    $0108;
 $0107 : decf    [$31],W;
 $0108 : nop;


if A <= B then inc else dec
Code:

  if A <= B then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    A,W;
 $0100 : subwf   B,W;
 $0101 : btfss   STATUS,C;
 $0102 : goto    $0105;
 $0103 : incf    [$31],0;
 $0104 : goto    $0106;
 $0105 : decf    [$31],0;
 $0106 : nop;


if A == B then inc else dec
Code:

  if A == B then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    A,W;
 $0100 : xorwf   B,W;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


if A <> B then inc else dec
Code:

  if A <> B then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    A,W;
 $0100 : xorwf   B,W;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0105;
 $0103 : incf    [$31],W;
 $0104 : goto    $0106;
 $0105 : decf    [$31],W;
 $0106 : nop;


Narednih 6 slucajeva (npr. "if B >A then...") nema smisla obradjivati, jer se koristi potpuno isti kod.
[ Stojan Trifunovic @ 09.08.2008. 21:46 ] @
Sledi dvobajtna neoznacena varijabla (word) i konstanta. Kompajler bi morao razdvojiti konstantu u LO HI oblik i tako je ubaciti u instrukcije.

@korak
Definisite mi kako MMA uzima LO HI oblik iz dvobajtne i iz visebajtnih varijabli, kako bih kasnije pisao kod ispravnom sintaksom. Ovde sam podelio varijablu GODINA u LO_GODINA i HI_GODINA.


if GODINA > konstante 2008 (HI-7, LO-216) then inc else dec
Code:

  if GODINA > 2008 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    HI_GODINA,W;
 $0100 : sublw   $07;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0107;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $010B;
 $0105 : incf    [$31],W;
 $0106 : goto    $010C;
 $0107 : movf    LO_GODINA,W;
 $0108 : sublw   $D8;
 $0109 : btfss   STATUS,C;
 $010A : goto    $0105;
 $010B : decf    [$31],W;
 $010C : nop;


if GODINA < konstante 2008 (HI-7, LO-216) then inc else dec
Code:

  if GODINA < 2008 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0101 : movlw   $07;
 $0102 : subwf   HI_GODINA,W;
 $0103 : btfsc   STATUS,Z;
 $0104 : goto    $0109;
 $0105 : btfsc   STATUS,C;
 $0106 : goto    $010D;
 $0107 : incf    [$31],W;
 $0108 : goto    $010E;
 $0109 : movlw   $D8;
 $010A : subwf   LO_GODINA,W;
 $010B : btfss   STATUS,C;
 $010C : goto    $0107;
 $010D : decf    [$31],W;
 $010E : nop;


if GODINA >= konstante 2008 (HI-7, LO-216) then inc else dec
Code:

  if GODINA >= 2008 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $00FF : movf    HI_GODINA,W;
 $0100 : sublw   $07;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0107;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $010B;
 $0105 : incf    [$31],W;
 $0106 : goto    $010C;
 $0107 : movlw   $D8;
 $0108 : subwf   LO_GODINA,W;
 $0109 : btfsc   STATUS,C;
 $010A : goto    $0105;
 $010B : decf    [$31],W;
 $010C : nop;


if GODINA <= konstante 2008 (HI-7, LO-216) then inc else dec
Code:

  if GODINA <= 2008 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $0101 : movlw   $07;
 $0102 : subwf   HI_GODINA,W;
 $0103 : btfsc   STATUS,Z;
 $0104 : goto    $0109;
 $0105 : btfsc   STATUS,C;
 $0106 : goto    $010D;
 $0107 : incf    [$31],W;
 $0108 : goto    $010E;
 $0109 : movf    LO_GODINA,W
 $010A : sublw   $D8;
 $010B : btfsc   STATUS,C;
 $010C : goto    $0107;
 $010D : decf    [$31],0;
 $010E : nop;


if GODINA == konstanta 2008 (HI-7, LO-216) then inc else dec
Code:

  if GODINA == 2008 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $00FF : movf    HI_GODINA,W;
 $0100 : xorlw   $07;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0109;
 $0103 : movf    LO_GODINA,W;
 $0104 : xorlw   $D8;
 $0105 : btfss   STATUS,Z;
 $0106 : goto    $0109;
 $0107 : incf    [$31],W;
 $0108 : goto    $010A;
 $0109 : decf    [$31],W;
 $010A : nop;


if GODINA <> konstante 2008 (HI-7, LO-216) then inc else dec
Code:

  if GODINA <> 2008 then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $00FF : movf    HI_GODINA,W;
 $0100 : xorlw   $07;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0107;
 $0103 : movf    LO_GODINA,W;
 $0104 : xorlw   $D8;
 $0105 : btfsc   STATUS,Z;
 $0106 : goto    $0109;
 $0107 : incf    [$31],W;
 $0108 : goto    $010A;
 $0109 : decf    [$31],W;
 $010A : nop;



A sada konstanta i dvobajtna neoznacena varijabla (word).

if konstanta 2008 < GODINA then inc else dec
Code:

  if 2008 < GODINA then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $00FF : movf    HI_GODINA,W;
 $0100 : sublw   $07;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0107;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $010B;
 $0105 : incf    [$31],W;
 $0106 : goto    $010C;
 $0107 : movf    LO_GODINA,W;
 $0108 : sublw   $D8;
 $0109 : btfss   STATUS,C;
 $010A : goto    $0105;
 $010B : decf    [$31],W;
 $010C : nop;


if konstanta 2008 > GODINA then inc else dec
Code:

  if 2008 > GODINA then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $0101 : movlw   $07;
 $0102 : subwf   HI_GODINA,W;
 $0103 : btfsc   STATUS,Z;
 $0104 : goto    $0109;
 $0105 : btfsc   STATUS,C;
 $0106 : goto    $010D;
 $0107 : incf    [$31],W;
 $0108 : goto    $010E;
 $0109 : movlw   $D8;
 $010A : subwf   LO_GODINA,W;
 $010B : btfss   STATUS,C;
 $010C : goto    $0107;
 $010D : decf    [$31],W;
 $010E : nop;


if konstanta 2008 <= GODINA then inc else dec
Code:

  if 2008 <= GODINA then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;


 $00FF : movf    HI_GODINA,W;
 $0100 : sublw   $07;
 $0101 : btfsc   STATUS,Z;
 $0102 : goto    $0107;
 $0103 : btfsc   STATUS,C;
 $0104 : goto    $010B;
 $0105 : incf    [$31],W;
 $0106 : goto    $010C;
 $0107 : movlw   $D8;
 $0108 : subwf   LO_GODINA,W;
 $0109 : btfsc   STATUS,C;
 $010A : goto    $0105;
 $010B : decf    [$31],W;
 $010C : nop;


if konstanta 2008 >= GODINA then inc else dec
Code:

  if 2008 >= GODINA then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $0101 : movlw   $07;
 $0102 : subwf   HI_GODINA,W;
 $0103 : btfsc   STATUS,Z;
 $0104 : goto    $0109;
 $0105 : btfsc   STATUS,C;
 $0106 : goto    $010D;
 $0107 : incf    [$31],W;
 $0108 : goto    $010E;
 $0109 : movf    LO_GODINA,W;
 $010A : sublw   $D8;
 $010B : btfsc   STATUS,C;
 $010C : goto    $0107;
 $010D : decf    [$31],W;
 $010E : nop;


if konstanta 2008 == GODINA then inc else dec
Code:

  if 2008 == GODINA then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

 $00FF : movf    HI_GODINA,W;
 $0100 : xorlw   $07;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0109;
 $0103 : movf    LO_GODINA,W;
 $0104 : xorlw   $D8;
 $0105 : btfss   STATUS,Z;
 $0106 : goto    $0109;
 $0107 : incf    [$31],W;
 $0108 : goto    $010A;
 $0109 : decf    [$31],W;
 $010A : nop;


if konstanta 2008 <> GODINA then inc else dec
Code:

  if 2008 <> GODINA then
  begin
    incf [49],W;
  end
  else
  begin
    decf [49],W;
  end
  nop;

  
 $00FF : movf    HI_GODINA,W;
 $0100 : xorlw   $07;
 $0101 : btfss   STATUS,Z;
 $0102 : goto    $0107;
 $0103 : movf    LO_GODINA,W;
 $0104 : xorlw   $D8;
 $0105 : btfsc   STATUS,Z;
 $0106 : goto    $0109;
 $0107 : incf    [$31],W;
 $0108 : goto    $010A;
 $0109 : decf    [$31],W;
 $010A : nop;


Svi kodovi su pisani iz glave (uz par prepisivanja), i nisu simulirani. Veoma je moguce da se potkrao neki bag. On ce se ipak lakse otkriti kasnije, kada se rutine ubace u MMA, i pojedinacno testiraju.
[ korak @ 10.08.2008. 07:47 ] @
Ovako:

Visebajtna vrednost mora da ima mogucnost da se pristupi svakom bajtu. Ako je ona tipa longint (4 bajta) i ima vrednost $12345678 (ovo mi se vise svidja od (0x12345678, mada je to stvar ukusa). Ako je ime varijable Brojac, onda najstarijem bajtu pristupam sa Brojac.0. Dakle:

Brojac.0 = $12
Brojac.1 = $34
Brojsc.2 = $56
Brojac.3 = $78

ali ce Brojac.4 biti prijavljeno od kompajlera kao greska.

Kada 16-to bitni registar uzima vrednosti onda:

ldhx [Brojac.0]; //u HX je $1234
ldhx [Brojac.1]; //u HX je $3456
ldhx [Brojac.2]; //u HX je $5678

a ldhx [Brojac.3] ce prijaviti gresku.

Kod Motorole u smeru rasta memorijskih adresa ide prvo bajt najvece tezine, a na kraju je bajt najmanje tezine. Zato se bajtu najvece tezine pristupa sa .0 (dodaje na adresu 0 i t. d.). Kod Intela je obrnuto, a mislim da je tako i kod PIC-a, potvrdi mi ovo. Ako je tako ti pristupaj bajtu najmanje tezine sa .0 i tako redom koliko ima bajtova. Kada iza tacke stoji ime, onda se radi o pristupanju polju record tipa, to kompajler lako razlikuje.

Kada deklarises varijablu, ti je upises u neku tablicu koja sadrzi mnoge podatke o varijabli. Obavezno mora da sadrzi adresu varijable i njen tip. Kada kompajler naidje na ime te varijable, on ime zamenjuje sa adresom. Tako ako napisem

ldhx Brojac; //HX uzima adresu varijable brojac
a
ldhx [Brojac.0]; //HX uzima dva visa bajta varijable Brojac.

Ovakvu sintaksu Motorola koristi kod MC68000 i kasnijih 32-o bitnih procesora, dok kod 8-o bitnih koristi:

ldhx #Brijac; //da HX uznme adresu varijable Brojac (literal kod PIC-a)
i
ldhx Brojac; //da HX uzme dva bajta vece tezine
a
ldhx Brojac+2;//da HX uzme dva niza bajta varijable Brojac (ovde nema zastite od promasenog pristupa bajtu varijable)

Ovo mi se ne svidja, zbog jednog znaka # mogu da napravim gresku i da se ubijem trazeci ga u 10..20000 redova programa. Mnogo je teze izostaviti istovremeno obe zagrade ([ i ]) pa su i greske redje. Nisu dzabe presli na drugu sintaksu kod 32-o bitnih procesora.

[ Stojan Trifunovic @ 13.08.2008. 16:40 ] @
@korak
16F serija je osmobitna, pa nema apsolutno nikakvu preddefinisanu strukturu LO/HI oblika. Potpuno je svejedno, jer se registrima može pristupati iskljucivo pojedinacno. Na programeru je da odabere koji ce format koristiti (little ili big endian). Cak su moguce i egzibicije poput cuvanja LO dela na adresi $4C a HI dela na $25.

Sledi case...of... struktura za word. Uzeo sam little endian slucaj, pa je GODINA.0 isto što i HI_GODINA, a GODINA.1 je isto što i LO_GODINA.

Code:

var shared_bank [0x70..0x7E]
  <
   GODINA  : word
  >

case GODINA of
2005, 2008, 2012..2015 : incf [49],F;
2018..2030, 2040..2050 : decf [49],F;
else clrf [49];
end;
nop;

$0100 : movf    GODINA.0,W;   // GODINA = 2005 ($07,D5)
$0101 : xorlw   $07;
$0102 : btfss   STATUS,Z;
$0103 : goto    _2008
$0104 : movf    GODINA.1,W;
$0105 : xorlw   $D5
$0106 : btfss   STATUS,Z;
$0107 : goto    $010A;

$0108 : incf    $31,W;        // inc
$0109 : goto    $0154;

$010A : movf    GODINA.0,W;   // GODINA = 2008 ($07,D8)
$010B : xorlw   $07;
$010C : btfss   STATUS,Z;
$010D : goto    $0112;
$010E : movf    GODINA.1,W;
$010F : xorlw   $D8;
$0110 : btfsc   STATUS,Z;
$0111 : goto    $0108;


$0112 : movf    GODINA.0,W;   // GODINA >= 2012($07,#DC)
$0113 : sublw   $07;
$0114 : btfsc   STATUS,Z;
$0115 : goto    $0119;
$0116 : btfsc   STATUS,C;
$0117 : goto    $0127;
$0118 : goto    $011D;
$0119 : movlw   $DC
$011A : subwf   GODINA.1,W;
$011B : btfss   STATUS,C;
$011C : goto    $0127;
$011D : movlw   $07;           // GOSINA <= 2015 ($07,$DF)
$011E : subwf   GODINA.0,W;
$011F : btfsc   STATUS,Z;
$0120 : goto    $0123;
$0121 : btfsc   STATUS,C;
$0122 : goto    $0127
$0123 : movf    GODINA.1,W;
$0124 : sublw   $DF;
$0125 : btfsc   STATUS,C;
$0126 : goto    $0108;



$0127 : movf    GODINA.0,W;   // GODINA >= 2018($07,#E2)
$0128 : sublw   $07;
$0129 : btfsc   STATUS,Z;
$012A : goto    $012E;
$012B : btfsc   STATUS,C;
$012C : goto    $013E;
$012D : goto    $0132;
$012E : movlw   $E2
$012F : subwf   GODINA.1,W;
$0130 : btfss   STATUS,C;
$0131 : goto    $013E
$0132 : movlw   $07;           // GOSINA <= 2020 ($07,$E4)
$0133 : subwf   GODINA.0,W;
$0134 : btfsc   STATUS,Z;
$0135 : goto    $0138;
$0136 : btfsc   STATUS,C;
$0137 : goto    $013E
$0138 : movf    GODINA.1,W;
$0139 : sublw   $E4;
$013A : btfss   STATUS,C;
$013B : goto    $013E

$013C : decf    $31,W;         // dec
$013D : goto    $0154;


$013E : movf    GODINA.0,W;   // GODINA >= 2040 ($07,#F8)
$013F : sublw   $07;
$0140 : btfsc   STATUS,Z;
$0141 : goto    $0145;
$0142 : btfsc   STATUS,C;
$0143 : goto    $0153;
$0144 : goto    $0149;
$0145 : movlw   $F8
$0146 : subwf   GODINA.1,W;
$0147 : btfss   STATUS,C;
$0148 : goto    $0153
$0149 : movlw   $08;           // GOSINA <= 2050 ($08,$02)
$014A : subwf   GODINA.0,W;
$014B : btfsc   STATUS,Z;
$014C : goto    $014F;
$014D : btfsc   STATUS,C;
$014E : goto    $0153
$014F : movf    GODINA.1,W;
$0150 : sublw   $02;
$0151 : btfsc   STATUS,C;
$0152 : goto    $013C;

$0153 : clrf    0x31;         // else
$0154 : nop                   // end
[ Stojan Trifunovic @ 14.08.2008. 04:30 ] @
repeat...until programska struktura malo je teza za word varijablu, zbog cestog postojanja potrebe direktne izmene varijable unutar strukture. Kako ne zelite ubacivati izraze u kompajler, mislim da je najbolje prepustiti sav racun asembleru, a kompajleru ostaviti samo testiranje.

Potrebno je obraditi sve moguce slucajeve (<, >, <=, >=, ==). Test razlicitosti je, mislim, ovde suvisan.

repeat GODINA + 5 until GODINA > 2050
Code:

 repeat
   movlw   5;
   addwf   LO_GODINA,F;
   btfsc   STATUS,C;
   incf    HI_GODINA,F;
 until GODINA > 2050
 nop;

$0100 : movlw   $05;
$0101 : addwf   LO_GODINA,F;      // GODINA = GODINA+5
$0102 : btfsc   STATUS,C;
$0103 : incf    HI_GODINA,F;
        
$0104 : movlw   $08;             // GODINA > 2050 ($08,$02)?
$0105 : subwf   HI_GODINA,W;
$0106 : btfsc   STATUS,Z;
$0107 : goto    $010B;
$0108 : btfsc   STATUS,C;
$0109 : goto    $0100;
$010A : goto    $010F;
$010B : movf    LO_GODINA,W
$010C : sublw   $02;
$010D : btfsc   STATUS,C;
$010E : goto    $0100;
$010F : nop;



repeat GODINA + 5 until GODINA >= 2050
Code:

 repeat
   movlw   5;
   addwf   LO_GODINA,F;
   btfsc   STATUS,C;
   incf    HI_GODINA,F;
 until GODINA >= 2050
 nop;

$0100 : movlw   $05;
$0101 : addwf   LO_GODINA,F;      // GODINA = GODINA+5
$0102 : btfsc   STATUS,C;
$0103 : incf    HI_GODINA,F;

$0104 : movlw   $08;              // GODINA >= 2050?
$0105 : subwf   HI_GODINA,W;
$0106 : btfsc   STATUS,Z;
$0107 : goto    $010B;
$0108 : btfsc   STATUS,C;
$0109 : goto    $0100;
$010A : goto    _nop;
$010B : movlw   $02;
$010C : subwf   LO_GODINA,W
$010D : btfsc   STATUS,C;
$010E : goto    $0100;
$010F : nop



repeat GODINA - 5 until GODINA < 2000
Code:

 repeat
   movlw   5;
   subwf   LO_GODINA,F;
   btfsc   STATUS,C;
   decf    HI_GODINA,F;
 until GODINA < 2000
 nop;

$0100 : movlw   $05;              // GODINA = GODINA-5
$0101 : subwf   LO_GODINA,F;
$0102 : btfsc   STATUS,C;
$0103 : decf    HI_GODINA,F;

$0104 : movlw   $07;              // GODINA < 2000 ($07,$DA)?
$0105 : subwf   HI_GODINA,W;
$0106 : btfsc   STATUS,Z;
$0107 : goto    $010B;
$0108 : btfsc   STATUS,C;
$0109 : goto    $010F;
$010A : goto    $0100;
$010B : movlw   $DA;
$010C : subwf   LO_GODINA,W
$010D : btfss   STATUS,C;
$010E : goto    $0100;
$010F : nop



repeat GODINA - 5 until GODINA <= 2000
Code:

 repeat
   movlw   5;
   subwf   LO_GODINA,F;
   btfsc   STATUS,C;
   decf    HI_GODINA,F;
 until GODINA <= 2000
 nop;

$0100 : movlw   $05;              // GODINA = GODINA-5
$0101 : subwf   LO_GODINA,F;
$0102 : btfsc   STATUS,C;
$0103 : decf    HI_GODINA,F;

$0104 : movlw   $07;              // GODINA <= 2000 ($07,$DA)?
$0105 : subwf   HI_GODINA,W;
$0106 : btfsc   STATUS,Z;
$0107 : goto    $010B;
$0108 : btfsc   STATUS,C;
$0109 : goto    $010F;
$010A : goto    $0100;
$010B : movf    LO_GODINA,W
$010C : sublw   $DA;
$010D : btfsc   STATUS,C;
$010E : goto    $0100;
$010F : nop



repeat GODINA + 1 until GODINA == 2050
Code:

 repeat
   incf    LO_GODINA,F;
   btfsc   STATUS,Z;
   incf    HI_GODINA,F;
 until GODINA == 2050
 nop;

$0100 : incf    LO_GODINA,F;     // GODINA = GODINA+1
$0101 : btfsc   STATUS,Z;
$0102 : incf    HI_GODINA,F;

$0103 : movf    HI_GODINA,W;     //  GODINA == 2050 ($08,$02)?
$0104 : xorlw   $08;
$0105 : btfss   STATUS,Z;
$0106 : goto    $010B;
$0107 : movf    LO_GODINA,W;
$0108 : xorlw   $02;
$0109 : btfsc   STATUS,Z;
$010A : goto    $0100;
$010B : nop;
[ korak @ 14.08.2008. 09:09 ] @
Bez obzira sto je mikrokontroler 8-o bitni, cak je za njega to vaznije, on obradjuje u visebajtne podatke. Programer mora oznaciti koji bajt visebajtnog podatka trenutn obradjuje. Zato sam uveo notaciju o kojoj san oisao. 32-o bitnim mikrokontrolerima to ne treba, oni ce uzeti u obradu odjednom 4 bajta.

U if..then..else kao uslov uzimas ceo izraz (GODINA > 2050) ali ne valja ako ga ogranicavas. Sa druge strane ako imas komplikovan izraz onda kompajler mora da prevodi izraze, a onda na kraju jrajeva svi asemblerski iskazi mogu da budu zamenjeni takvim izrazima, i vec si napustio asembler i imas neki visi programski jezik.

Moj pristup je da napises kod koji oduzima od GODINA vrednost 2050, u asembleru, a onda napises samo if > then.

Inace sve si dobro napisao, ostaje samo da se napravi kompajler koji ce sam da generise kod koji si naoisao.

Pozdrav.

Na odmoru sam od danas 7 dana.
[ Stojan Trifunovic @ 23.08.2008. 20:06 ] @
Mislim da se nismo najbolje razumeli. PIC16 serija apsolutno nema ijednu instrukciju (niti adresni mod) kojom bi bilo moguce adresiranje dva bajta. Takodje nema ni "povlascene" sesnaestobitne registre (kao sto AVR ima X, Y i Z).

Znaci za sledecu situaciju:
Code:

var bank 0 [0x20..0x6F]
  <
   GODINA : word
  >

je potpuno svejedno da li ce GODINA.0 biti HI ili LO bajt. Neka bude kako je zgodnije za kompajler.

Sledi if...then...else... struktura za dve dvobajtne varijable (word). Namerno sam pisao LO_GODINA1 umesto npr. GODINA1.0 jer je zamena laka (Edit - Replace), a lakse je za razumevanje.

if GODINA1 >= GODINA2 then inc else dec
Code:

$0100 : movf    HI_GODINA1,W;
$0101 : subwf   HI_GODINA2,W;
$0102 : btfsc   STATUS,Z;
$0103 : goto    $0108;
$0104 : btfsc   STATUS,C;
$0105 : goto    $010C;
$0106 : incf    $31,W;
$0107 : goto    $010D;
$0108 : movf    LO_GODINA2,W;
$0109 : subwf   LO_GODINA1,W;
$010A : btfsc   STATUS,C;
$010B : goto    $0106;
$010C : decf    $31,W;
$010D : nop;


if GODINA1 <= GODINA2 then inc else dec
Code:

$0100 : movf    HI_GODINA1,W;
$0101 : subwf   HI_GODINA2,W;
$0102 : btfsc   STATUS,Z;
$0103 : goto    $0108;
$0104 : btfss   STATUS,C;
$0105 : goto    $010C;
$0106 : incf    $31,W;
$0107 : goto    $010D;
$0108 : movf    LO_GODINA1,W;
$0109 : subwf   LO_GODINA2, W;
$010A : btfsc   STATUS,C;
$010B : goto    $0106;
$010C : decf    $31,W;
$010D : nop;


if GODINA1 > GODINA2 then inc else dec
Code:

$0100 : movf    HI_GODINA1,W;
$0101 : subwf   HI_GODINA2,W;
$0102 : btfsc   STATUS,Z;
$0103 : goto    $0108;
$0104 : btfsc   STATUS,C;
$0105 : goto    $010E;
$0106 : incf    $31,W;
$0107 : goto    $010F;
$0108 : movf    LO_GODINA2,W;
$0109 : subwf   LO_GODINA1,W;
$010A : btfsc   STATUS,Z;
$010B : goto    $010E;
$010C : btfsc   STATUS,C;
$010D : goto    $0106;
$010E : decf    $31,W;
$010F : nop;


if GODINA1 < GODINA2 then inc else dec
Code:

$0100 : movf    HI_GODINA1,W;
$0101 : subwf   HI_GODINA2,W;
$0102 : btfsc   STATUS,Z;
$0103 : goto    $0108;
$0104 : btfss   STATUS,C;
$0105 : goto    $010E;
$0106 : incf    $31,W;
$0107 : goto    $010F;
$0108 : movf    LO_GODINA1,W;
$0109 : subwf   LO_GODINA2,W;
$010A : btfsc   STATUS,Z;
$010B : goto    $010E;
$010C : btfsc   STATUS,C;
$010D : goto    $0106;
$010E : decf    $31,W;
$010F : nop;


if GODINA1 == GODINA2 then inc else dec
Code:

$0100 : movf    HI_GODINA1,W;
$0101 : xorwf   HI_GODINA2,W;
$0102 : btfss   STATUS,Z;
$0103 : goto    $010A;
$0104 : movf    LO_GODINA1,W;
$0105 : xorwf   LO_GODINA2,W;
$0106 : btfss   STATUS,Z;
$0107 : goto    $010A;
$0108 : incf    $31,W;
$0109 : goto    $010B;
$010A : decf    $31,W;
$010B : nop;


if GODINA1 <> GODINA2 then inc else dec
Code:

$0100 : movf    HI_GODINA1,W;
$0101 : xorwf   HI_GODINA2,W;
$0102 : btfss   STATUS,Z;
$0103 : goto    $0106;
$0104 : incf    $31,W;
$0105 : goto    $010B;
$0106 : movf    LO_GODINA1,W;
$0107 : xorwf   LO_GODINA2,W;
$0108 : btfss   STATUS,Z;
$0109 : goto    $0104;
$010A : decf    $31,W;
$010B : nop;
[ Stojan Trifunovic @ 23.08.2008. 22:01 ] @
Uops, provukla mi se losa optimizacija (dve instrukcije duza) kod primera sa < i >.
Trebali bi biti ovakvi:

if GODINA1 < GODINA2 then inc else dec
Code:

$0100 : movf    HI_GODINA1,W;
$0101 : subwf   HI_GODINA2,W;
$0102 : btfsc   STATUS,Z;
$0103 : goto    $0108;
$0104 : btfsc   STATUS,C;
$0105 : goto    $010C;
$0106 : decf    $31,W;
$0107 : goto    $010D;
$0108 : movf    LO_GODINA2,W;
$0109 : subwf   LO_GODINA1,W;
$010A : btfsc   STATUS,C;
$010B : goto    $0106;
$010C : incf    $31,W;
$010D : nop;



if GODINA1 > GODINA2 then inc else dec
Code:

$0100 : movf    HI_GODINA1,W;
$0101 : subwf   HI_GODINA2,W;
$0102 : btfsc   STATUS,Z;
$0103 : goto    $0108;
$0104 : btfss   STATUS,C;
$0105 : goto    $010C;
$0106 : decf    $31,W;
$0107 : goto    $010D;
$0108 : movf    LO_GODINA1,W;
$0109 : subwf   LO_GODINA2,W;
$010A : btfsc   STATUS,C;
$010B : goto    $0106;
$010C : incf    $31,W;
$010D : nop;
[ korak @ 24.08.2008. 11:03 ] @
Da, nismo se razumeli.

Ako je MCU 8-o bitni a treba da obradjuje podatke koji su u opstem slucaju visebajtni, onda sintaksa kompajlera treba da to omoguci programeru. Kada deklarises varijablu GODINA, kompajler imenu GODINA dodeljuje u jednoj tablici imena adresu na kojoj pocinje varijabla, tip vatijable (iz cega proistice i duzina u bajtovima) i t. d. Kada napises u programu ime GODINA, kompajler ga odnah zamenjuje njegovom adresom. Dakle:

movf GODINA,W;

ce u W staviti prvi bajt od varijable GODINA u W. Ali kako se GODINA sastoji od 2 bajta, a ti zelis onaj drugi, mozes to sa:

movf GODINA+1,W;

i u W ce biti bajt sa adrese za 1 vece od one koja je pridruzena varijabli GODINA, dakle onaj koji ti treba.

Ja sam samo uveo sintaksu u kojoj je GODINA i GODINA.0 isto, a drugom bajtu se pristupa sa GODINA.1.

Ti umesto jedne varijable GODINA uvodis dve HI_GODINA i LO_GODINA, sto je potpuno nepotrebno, neprakticno i nepregledno, sto znaci i da je vise podlozno gresci.

Sta raditi sa varijablom koja ima 4 bajta? Na primer imas brojac ciklusa koje obavi jedna masina i to cuvas u varijabli:

BrCiklusa : longWord; //cetvorobajtna varijabla

Uvek svakom bajtu ove varijable mozes da pristupis sa BrCiklusa.0, BrCiklusa.1, BrCiklusa.2 i BrCiklusa.3.

Suprotno ovome, MCU koji je 32-o bitni ne mora to da radi jer on odmah pristupa celoj varijabli BrCikljusa. Dakle, ova sintaksa je upravo namenjena 8-o bitnim MCU-ovima.

Pozdrav.
[ Stojan Trifunovic @ 24.08.2008. 13:38 ] @
Kazem, konverzija je laka, i svakako da je sintaksa koju predlazete bolja. LO_GODINA i HI_GODINA napisao sam samo zbog ostalih clanova foruma (nismo sami) kako bi po potrebi mogli koristiti ove strukture u svojim programima. Za NJIH je LO HI oblik razumljiviji, jer ne moraju lutati po postovima i traziti da li je LO_GODINA isto sto i GODINA,0.
[ korak @ 24.08.2008. 16:27 ] @
OK,

logicno je. Ali ne mislim da treba stalno da se drzimo nekih davnasnjih stvari koje je neko mozda slucajno tako definisao. Oko nas se sve menja, pa treba dati oduska kreativnosti i ici napred. Ko ima problem da shvati, treba mu objasniti. Samo tako se obezbedjuje napredak. U suprotnom bice u pravu globalisti koji kazu da predstoji vreme bez istorije, a to ce biti vreme kada ce sve da stane i nista se novo nece desavati.

Umetnik nikada ne pravi dva ista dela, uvek pravi nova i nova, a to treba da vazi za svaku profesiju.

Pozdrav.
[ Stojan Trifunovic @ 25.08.2008. 21:43 ] @
Sledi repeat...until... struktura uz poredjenje dve dvobajtne varijable (word).

GODINA.0 je bajt vece (HI), a GODINA.1 je bajt manje tezine(LO).


repeat GODINA1 + 4 until GODINA1 > GODINA2
Code:

repeat
   movlw   4;
   addwf   GODINA1.1,F;
   btfsc   STATUS,C;
   incf    GODINA1.0,F;
until GODINA1 > GODINA2
nop;

$0100 : movlw   $04;
$0101 : addwf   GODINA1.1,F;      // GODINA1 = GODINA1+4
$0102 : btfsc   STATUS,C;
$0103 : incf    GODINA1.0,F;

$0104 : movf    GODINA1.0,W;      // GODINA1 > GODINA2?
$0105 : subwf   GODINA2.0,W;
$0106 : btfsc   STATUS,Z;
$0107 : goto    $010B;
$0108 : btfss   STATUS,C;
$0109 : goto    $010F;
$010A : goto    $0100;
$010B : movf    GODINA1.1,W;
$010C : subwf   GODINA2.0,W;
$010D : btfsc   STATUS,C;
$010E : goto    $0100;
$010F : nop;



repeat GODINA1 + 4 until GODINA1 >= GODINA2
Code:

repeat
   movlw   4;
   addwf   GODINA1.1,F;
   btfsc   STATUS,C;
   incf    GODINA1.0,F;
until GODINA1 >= GODINA2
nop;

$0100 : movlw   $04;
$0101 : addwf   GODINA1.1,F;      // GODINA1 = GODINA1+4
$0102 : btfsc   STATUS,C;
$0103 : incf    GODINA1.0,F;

$0104 : movf    GODINA1.0,W;      // GODINA1 >= GODINA2?
$0105 : subwf   GODINA2.0,W;
$0106 : btfsc   STATUS,Z;
$0107 : goto    $010B;
$0108 : btfss   STATUS,C;
$0109 : goto    $010F;
$010A : goto    $0100;
$010B : movf    GODINA2.0,W;
$010C : subwf   GODINA1.1,W;
$010D : btfss   STATUS,C;
$010E : goto    $0100;
$010F : nop;



repeat GODINA1 - 5 until GODINA1 < GODINA2
Code:

repeat
   movlw   5;
   subwf   GODINA1.1,F;
   btfss   STATUS,C;
   decf    GODINA1.0,F;
until GODINA1 < GODINA2
nop;

$0100 : movlw   $05;
$0101 : subwf   GODINA1.1,F;      // GODINA1 = GODINA1-5
$0102 : btfss   STATUS,C;
$0103 : decf    GODINA1.0,F;

$0104 : movf    GODINA1.0,W;      // GODINA1 < GODINA2?
$0105 : subwf   GODINA2.0,W;
$0106 : btfsc   STATUS,Z;
$0107 : goto    $010B;
$0108 : btfsc   STATUS,C;
$0109 : goto    $010F;
$010A : goto    $0100;
$010B : movf    GODINA2.0,W;
$010C : subwf   GODINA1.1,W;
$010D : btfsc   STATUS,C;
$010E : goto    $0100;
$010F : nop;



repeat GODINA1 - 5 until GODINA1 <= GODINA2
Code:

repeat
   movlw   5;
   subwf   GODINA1.1,F;
   btfss   STATUS,C;
   decf    GODINA1.0,F;
until GODINA1 <= GODINA2
nop;

$0100 : movlw   $05;
$0101 : subwf   GODINA1.1,F;      // GODINA1 = GODINA1-5
$0102 : btfss   STATUS,C;
$0103 : decf    GODINA1.0,F;

$0104 : movf    GODINA1.0,W;      // GODINA1 <= GODINA2?
$0105 : subwf   GODINA2.0,W;
$0106 : btfsc   STATUS,Z;
$0107 : goto    $010B;
$0108 : btfsc   STATUS,C;
$0109 : goto    $010F;
$010A : goto    $0100;
$010B : movf    GODINA1.1,W;
$010C : subwf   GODINA2.0,W;
$010D : btfss   STATUS,C;
$010E : goto    $0100;
$010F : nop;



repeat GODINA1 - 1 until GODINA1 = GODINA2
Code:

repeat
   decfsz   GODINA1.1,F;
   goto     $+2;
   decf     GODINA1.0,F;
until GODINA1 = GODINA2
nop;

$0100 : decfsz  GODINA1.1,F;      // GODINA1 = GODINA1-1
$0101 : goto    $+2;
$0102 : decf    GODINA1.0,F;

$0103 : movf    GODINA1.0,W;      // GODINA1 = GODINA2?
$0104 : xorwf   GODINA2.0,W;
$0105 : btfss   STATUS,Z;
$0106 : goto    $0100;
$0107 : movf    GODINA1.1,W;
$0108 : xorwf   GODINA2.0,W;
$0109 : btfss   STATUS,C;
$010A : goto    $0100;
$010B : nop;



Mislim da je test razlicitosti i ovde suvisan.

Korak, mislim da bi bilo prakticno (a svakako bi bilo lakse) da umesto kompletnog kompajlera za PIC napravite samo preprocesor. Znaci, on bi samo raspakovao osnovne programske strukture (eventualno bi ubacio svoje nazive registara, labele i komentare kako bi korisnik znao da ne cacka taj deo koda), a sve ostalo bi samo prekopirao i dobio novi .asm fajl. Na taj nacin omogucio bi naknadnu izmenu koda standardnim (i besplatnim) microchipovim alatima, uz zadrzavanje asemblerske snage osnovnih programskih struktura. Korisniku je ovo samo par klika dalje.
[ korak @ 26.08.2008. 12:05 ] @
Vidim da razumes u potpunosti sta treba da bude rezultat onoga sto treba da uradi komapajler, a vidim da imas i volju za to.

Skrenuo bih ti paznju na sledece. if..then i repeat..until struktura imaju svoj uslov koji je izraz. Napisati until Izraz, dovodi do toga da kompajler mora da prevodi izraze, a tada vec zalazimo u sveru visih programskih jezika. Ja sam izabrao da se taj izraz napise na asembleru, a da se kao uslov koristi stanje flega.

dakle until GODINA1 > GODINA2, zahteva da kompajler prevede izraz iza until. Ja to radim tako sto ispred until (znaci na kraju petlje) u asembleru izrazunam ovaj izraz pa tako da imam samo until >; Kompajler samo treba da na oznovu znaka uslova '>' ubaci potrebnu naredbu uslovnog skoka. Na ovaj nacin petlju mozes ubrzati, ako je GODINA1.0 > GODINA2.0 odmah izlazis iz petlje, a ako ne, vec je GODINA1.0 = GODINA2.0, onda izlazis iz petlje ako je GODINA1.0 > GODINA2.0.

Sto se tvog predloga tice, imam jednu ideju, alo ne znam dali da je realizujem. Ako bi je realizovao onda bih naptavio kompajler za bilo koji MCU. Sam programer bi napravio pomocu makroa sve naredbe svog MCU-a. Jedini mi je problem kako bi onda trebalo da definisem disassembler i softverski simulator, ako bi i to resio, mozda bi se odlucio da ubacim i tu opciju u svoj kompajler.

Pozdrav
[ Stojan Trifunovic @ 26.08.2008. 18:42 ] @
Jeste. GODINA1 < GODINA2 je svakako izraz, ali ukoliko je vec taj izraz maksimalno optimizovan pri prevodjenju u asembler, koga je briga za to. Svi grese. I meni se u pretproslom postu potkrala losa optimizacija. Ovako prevedeni izrazi bili bi maksimalno optimizovani u okviru date programske strukture, programer bi ih brze napisao, razumljiviji su, ne bi se koristile labele pa sto se onda ne bi koristili! Zamislite tek rucni kod za poredjenje longword varijabli! U svakom slucaju kao programer bih zeleo da izbegnem njegovo pisanje od nule, pa makar koristio copy/paste metod. Jeste, zagazilo bi se malo u oblast visih programskih jezika, ali upravo zato sam u proslom postu predlozio samo preprocesor umesto kompletnog kompajlera.

Problem sa flegovima je sto PIC16 serija jednostavno nema dovoljno flegova u STATUS registru (od koristi za strukture su samo Zero i Carry) kojima bi se odgovarajuci test mogao nedvosmisleno predstaviti njihovim stanjem, a samim tim ni odgovarajuce instrukcije uslovnog skoka. U strukturama koje sam napisao uslovni skok se nekad obavlja sa setovanim, a nekad sa resetovanim Carry flegom. Mogao bih u zavisnosti od rezultata osnovnih izraza postavljati bitove (koji bi sluzili kao flagovi C, Z, N, V) u posebnom registru, ali tek bi to onda licilo na visi programski jezik.

PIC18 serija je tu mocnija jer ima obilje instrukcija uslovnog skoka (kao AVR).

Mislim da Vam se potkrala greska ovde: "Na ovaj nacin petlju mozes ubrzati, ako je GODINA1.0 > GODINA2.0 odmah izlazis iz petlje, a ako ne, vec je GODINA1.0 = GODINA2.0, onda izlazis iz petlje ako je GODINA1.0 > GODINA2.0.". To bi valjda trebalo da glasi ovako "Na ovaj nacin petlju mozes ubrzati, ako je GODINA1.0 > GODINA2.0 odmah izlazis iz petlje, a ako ne, vec je GODINA1.0 = GODINA2.0, onda izlazis iz petlje ako je GODINA1.1 > GODINA2.1.".
To nisam mogao implementirati u izrazima, jer se Carry menja (setuje ili resetuje, u zavisnosti od toga kako je realizovano oduzimanje) i ukoliko je rezultat oduzimanja 0. Zato sam morao najpre testirati jednakost (Zero flag), pa tek onda (kada GODINA1.0 nije isto sto i GODINA2.0) prekoracenje. Bilo bi brze kada bi PIC16 serija imala instrukciju uslovnog skoka koja istovremeno testira i Carry i Zero fleg, ali eto, nema je. U svakom slucaju ovo jeste maksimalna moguca optimizacija za PIC16 seriju.

Kompajler za bilo koji mikrokontroler? Pa jos i simulator? Mislim da je ovo preveliki posao (bez uvrede) za jednog coveka.
Jos jedna prednost preprocesora bila bi sto je moguce koristiti gotove asemblerske rutine (iz Microchipovih Aplication Notes ili sa neta), i odmah simulirati njihovo izvodjenje MPLAB SIM-om. Da bi ovo bilo moguce u Vasem kompajleru, bilo bi potrebno ubaciti u kompajler sve moguce direktive koje standardno podrzava Microchipov MPASM asembler (sa svim svojim specificnostima), a to je ipak preveliki posao. Mene na primer uopste ne interesuje kako radi Microchipova rutina za mnozenje dva broja. Za mene je ona "black box". Najpre je testiram (da li stvarno radi i koliko dobro), onda je kopiram, pozovem u okviru potprograma i to je sve.
[ korak @ 27.08.2008. 13:19 ] @
Da, omakla mi se greska jer sam kopirao prvi izraz, a u drugom nisam umeso 0 stavio 1, hvala na ispravci. U pravu si da bi ovakav metod ispitivanja bio komplikovan za PIC16, ali sam ga naveo kao mogucnost.

A kompajler za sve MCU-ove nije problem, problem je samo disasembler i simulator. Kompajler bi lako generisao kod jer bi u jednom modulu bili makroi za sve naredbe zeljenog MCU-a. Ime makroa bi bilo ime asemblerske naredbe, a u samom makrou bi se generisao kod za du naredbu. Moj kompajler je tako koncipiran da to ne bi bilo tesko, osim dosadnog pisanja drfinicija svih naredbi. Problem je zaista disasembler koji iz koda treba da prepozna naredbu, a ako mu to nije definisano on to ne moze ni da uradi. Isto se odnosi i na softverski simulator. Mogu da predpostavim da disasembler i nije toliko neophodan, ali ne znam koliko programera koristi softverski simulator i koliko je on potreban. Eto to mi je dilema.

Pozdrav.
[ Stojan Trifunovic @ 27.08.2008. 21:22 ] @
A sto ne probate promeniti pristup? Umesto da makroi generisu .hex, neka generisu .asm kod, ili eventualno oba fajla istovremeno. Tako se ne bi izgubila osnovna korisnicki definisana struktura koda (prazni redovi i komentari ostali bi u .asm kodu na mestima gde su bili u source fajlu).

Mmmmmmmm Simulator!
Licno ga dosta koristim. Medjutim, ne bi li posao oko njegovog razvoja bio previse veliki? Jeste da ga u osnovi cine sitnice, ali ima ih previse. Pa jos za bilo koji mikrokontroler!!!
MPLAB SIM na primer u PIC16 seriji cak nema mogucnost simuliranja tajmer 1 modula jer on koristi sopstveni kristalni oscilator. Ovo bi pak bilo jednostavno dodati, ali, to bi zahtevalo izmenu programskog menija, dodavanje jos jednog oscilatora, njegove stoperice, njegovu (sto je moguce precizniju) sinhronizaciju sa glavnim oscilatorom prilikom simulacije, novih pravila stimulusa... Previse posla.
Ukoliko ima ikoga ko se bavi mikrokontrolerima a ne koristi simulator, neka ga obavezno nauci.

Evo, danas sam na primer simulirao deo koda objavljenog u prethodnim postovima, i nasao gomilu gresaka. Nazalost, MPLAB SIM ne prihvata oblik GODINA.0 (jer tacka prefiksa u njemu oznacava decimalni broj), pa se mozda opet potkrala neka. Postovacu izmene ovde, kada proverim sav kod.

Ne razumem sta je to toliko tesko oko disasemblera. Pa binarni kod svake instrukcije je potpuno nedvosmisleno predstavljen. Moguce da bi Vam problem predstavljali imenovani registri cije nazive bi morali cupati iz modula sa njihovim definicijama, ili pak potreba za disasembliranjem samo delova koda (neophodna kod Fon Nojmanove arhitekture da ne bi otpocelo disasembliranje od polovine instrukcije).
[ korak @ 28.08.2008. 14:06 ] @
Da bi se bolje razumeli pokusacu da dam primer kako bi moj kompajler (koji je inace za MC9S08 i MC908) generisao kod recimo za PIC.

macro addwf s;
begin
P1 := KonstVrd(s);

_if Leks.Vrednost <> ',' then ErrorMSG('Nedostaje zarez');
Leks;

P2 := KonstVrd(s);

_if P1 > 127 then ErrorMSG('Prevelika adresa');
_if not(P2 in['f','w']) then ErrorMSG('Neispravno odrdiste');
_if P2 = 'f' then P1 := P1+128;

(7,P1);
end;

Kada napises addwf GODINA.1,f onda se ukljucuje makro addwf sa vrednoscu stringa s = 'GODINA.1,f'. Funkcija KonstVrd(s) analizira string s pomocu proceure Leks, koja izdvaja leksicke simbole. U primeru, ona ce izdvojiti prvo GODINA.1 (kao ime) a onda separator ','. Tako ce KonstVrd da da adresu za GODINA.1 sto ce biti dodeljeno u P1. Pri tome Leks.Vrednost je ',' sto se proverava, a string s je ',f'. Sledeci poziv procedure Leksika dovodi string s na vrednost 'f' sto se preko KonstVrd(s) dodeljuje kao karakter u P2. Dalja analiza i kontrola vrednosti P1 i P2 je jasna. Na kraju kada se nesto napise izmedju malih zagrada, to kompajler direktno upisuje u programsku memoriju. U primeru je to kod i parametar za napisanu asemblersku naredbu.

Ovako bi se definisale sve asemblerske naredbe PIC-a ili nekog drugog MCU-a. Problem je kako sada napraviti disasembler koji ce $07 i P1 da prepozna addwf GODINA.1,f. Jos je veci problem simulator.

Pozdrav.
[ Stojan Trifunovic @ 28.08.2008. 16:56 ] @
Aha, znaci problem je kako zadrzati (imenovane) registre unutar disasemblovanog fajla!

Najjednostavniji nacin bi podrazumevao da se kao izlaz makroa addwf instrukcije doda jos par parametara. Tacnije, najlakse bi bilo dodati samo "addwf "+(originalni string s) kao izlazni parametar, pre bilo kakvog poziva Leks i Leksika procedura. Ja bih pak ovde kao izlazni parametar dodao i kompletne komentare (od pocetka do kraja), kako bi se i oni zadrzali u disasemblovanom fajlu.

Ne vidim da bi bilo koji drugi nacin bio dovoljno dobar zbog nemogucnosti prepoznavanja odgovarajuce banke. Drugim recima ukoliko postoje dva registra sa istom adresom, a unutar razlicitih banaka, disasembler ne bi znao kojoj banci da im pridruzi imena. Vidjao sam disasemblere koji na primer uvek pominju PORTA umesto TRISA (na istoj su adresi gledano u kodu instrukcije).
[ korak @ 29.08.2008. 11:25 ] @
Da u pravu si, odmah moze i da se generise fajl sa disasemblerskim tekstom, gde bi mu se linije dodavale u svakom makrou.

Dakle, ostaje mi vazniji problem, a to je simulator.

Pozdrav.
[ Stojan Trifunovic @ 29.08.2008. 19:26 ] @
Sledi deo trobajtnih poredjenja. Kako mi je sintaksa sa rednim brojevima programske memorije nezgodna zbog simulacije, preci cu na oznacavanje sa labelama. Za kompajler ovo ne bi trebalo da bude bitno, jer bi on ipak sam sukcesivno dodeljivao programsku memoriju, a bitne su mu samo tacke skokova koje su ionako ovde oznacene labelama.

Labele sam namerno oznacavao sa donjom crtom prefiksa jer su THEN i ELSE rezervisane reci u MPLAB asembleru, pa bi smetale simulaciji.

if BROJ > 10000000 (0-152, 1-150, 2-128) then inc else dec
Code:

                movf    BROJ.0,W
                sublw   d'152'
                btfsc   STATUS,Z
                goto    _eq0
                btfsc   STATUS,C
                goto    _else
_then           incf    0x31,W
                goto    _end

_eq0            movf    BROJ.1,W
                sublw   d'150'
                btfsc   STATUS,Z
                goto    _equal
                btfss   STATUS,C
                goto    _then
                goto    _else

_equal          movf    BROJ.2,W
                sublw   d'128'
                btfss   STATUS,C
                goto    _then
_else           decf    0x31,W
_end            nop



if BROJ >= 10000000 (0-152, 1-150, 2-128) then inc else dec
Code:

                movf    BROJ.0,W
                sublw   d'152'
                btfsc   STATUS,Z
                goto    _eq0
                btfsc   STATUS,C
                goto    _else
_then           incf    0x31,W
                goto    _end

_eq0            movf    BROJ.1,W
                sublw   d'150'
                btfsc   STATUS,Z
                goto    _equal
                btfss   STATUS,C
                goto    _then
                goto    _else

_equal          movlw   d'128'
                subwf   BROJ.2,W
                btfsc   STATUS,C
                goto    _then
_else           decf    0x31,W
_end            nop



if BROJ < 10000000 (0-152, 1-150, 2-128) then inc else dec
Code:

                movf    BROJ.0,W
                sublw   d'152'
                btfsc   STATUS,Z
                goto    _eq0
                btfss   STATUS,C
                goto    _else
_then           incf    0x31,W
                goto    _end

_eq0            movf    BROJ.1,W
                sublw   d'150'
                btfsc   STATUS,Z
                goto    _equal
                btfsc   STATUS,C
                goto    _then
                goto    _else

_equal          movlw   d'128'
                subwf   BROJ.2,W
                btfss   STATUS,C
                goto    _then
_else           decf    0x31,W
_end            nop



if BROJ <= 10000000 (0-152, 1-150, 2-128) then inc else dec
Code:

                movf    BROJ.0,W
                sublw   d'152'
                btfsc   STATUS,Z
                goto    _eq0
                btfss   STATUS,C
                goto    _else
_then           incf    0x31,W
                goto    _end

_eq0            movf    BROJ.1,W
                sublw   d'150'
                btfsc   STATUS,Z
                goto    _equal
                btfsc   STATUS,C
                goto    _then
                goto    _else

_equal          movf    BROJ.2,W
                sublw   d'128'
                btfsc   STATUS,C
                goto    _then
_else           decf    0x31,W
_end            nop



if BROJ == 10000000 (0-152, 1-150, 2-128) then inc else dec
Code:

                movf    BROJ.0,W
                xorlw   d'152'
                btfss   STATUS,Z
                goto    _else

                movf    BROJ.1,W
                xorlw   d'150'
                btfss   STATUS,Z
                goto    _else

                movf    BROJ.2,W
                xorlw   d'128'
                btfss   STATUS,Z
                goto    _else

_then           incf    0x31,W
                goto    _end
_else           decf    0x31,W
_end            nop



if BROJ <> 10000000 (0-152, 1-150, 2-128) then inc else dec
Code:

                movf    BROJ.0,W
                xorlw   d'152'
                btfss   STATUS,Z
                goto    _then

                movf    BROJ.1,W
                xorlw   d'150'
                btfss   STATUS,Z
                goto    _then

                movf    BROJ.2,W
                xorlw   d'128'
                btfsc   STATUS,Z
                goto    _else

_then           incf    0x31,W
                goto    _end
_else           decf    0x31,W
_end            nop


Uzgred, Vasa sintaksa oznacavanja bajtova unutar visebajtnih varijabli unutar .asm fajla bila bi dosta nezgodna za naknadno asembliranje i simulaciju standardnim Microchipovim alatima. Tacnije, korisnik bi morao (edit/replace opcijom) zameniti GODINA.1 u npr. GODINA1 ili GODINA_1 jer je kako sam ranije napomenuo tacka rezervisana za decimalne brojeve. Ipak, mislim da se MPLAB SIM simulator previse koristi da bi mogao biti tek tako ignorisan. Da ne biste menjali strukturu celog kompajlera, najlakse resenje bi bilo (ukoliko zelite to uraditi) da u makrou instrukcije izmenite string s.

Mislim da je pravljenje sopstvenog simulatora previse komplikovan zadatak. Jednostavno, tesko da biste mogli u jednom projektu objediniti sve HARDVERSKE specificnosti, poput na primer integrisane RS232 veze. MPLAB SIM ima na primer cak i mogucnost simulacije AD konverzije sukcesivnim ucitavanjem unapred zadatih vrednosti iz eksternog fajla pri svakoj AD konverziji (Register Injection tab u Stimulus-u), ili snimanje stanja registara u eksternom fajlu (Registar Trace tab). Ne kazem da nije moguce, vec da je komplikovano, i da uvek iskrsavaju nove i nove sitnice.

U prilogu prilazem sve do sada postovane, a ispravljene kodove.
[ Stojan Trifunovic @ 12.09.2008. 09:25 ] @
Nastavljam sa trobajtnim CASE i REPEAT...UNTIL strukturama.


Code:

case BROJ of
  10000000, 11000000, 15000000..16000000 : incf [49],F;
  7000000..8000000, 8500000..9000000 : decf [49],F;
 else clrf [49];
end;
nop;

                movf    BROJ.0,W                ;   // BROJ == 10000000 (h'98 96 80')
                xorlw   0x98                    ;
                btfss   STATUS,Z                ;
                goto    _11000000               ;
                movf    BROJ.1,W                ;
                xorlw   0x96                    ;
                btfss   STATUS,Z                ;
                goto    _11000000               ;
                movf    BROJ.2,W                ;               
                xorlw   0x80                    ;
                btfss   STATUS,Z                ;
                goto    _11000000               ;
                
_then1  incf    0x31,W                          ;   // inc
                goto    _end                    ;

_11000000       
                movf    BROJ.0,W                ;   // BROJ == 11000000 (h'A7 D8 C0')
                xorlw   0xA7                    ;
                btfss   STATUS,Z                ;
                goto    _15000000               ;
                movf    BROJ.1,W                ;
                xorlw   0xD8                    ;
                btfss   STATUS,Z                ;
                goto    _15000000               ;
                movf    BROJ.2,W                ;
                xorlw   0xC0                    ;                       
                btfsc   STATUS,Z                ;
                goto    _then1                  ;


_15000000
                movf    BROJ.0,W                ;   // BROJ >= 15000000 (h'E4 E1 C0')
                sublw   0xE4                    ;
                btfsc   STATUS,Z                ;
                goto    _eq15000000_0           ;
                btfsc   STATUS,C                ;
                goto    _7000000                ;
                goto    _16000000               ;

_eq15000000_0
                movf    BROJ.1,W                ;
                sublw   0xE1                    ;
                btfsc   STATUS,Z                ;
                goto    _eq15000000_1           ;
                btfss   STATUS,C                ;
                goto    _16000000               ;
                goto    _7000000                ;

_eq15000000_1
                movlw   0xC0                    ;
                subwf   BROJ.2,W                ;
                btfss   STATUS,C                ;
                goto    _7000000                ;

_16000000
                movf    BROJ.0,W                ;    // BROJ <= 16000000 (h'F4 24 00')
                sublw   0xF4                    ;
                btfsc   STATUS,Z                ;
                goto    _eq16000000_0           ;
                btfss   STATUS,C                ;
                goto    _7000000                ;
                goto    _then1                  ;

_eq16000000_0
                movf    BROJ.1,W                ;
                sublw   0x24                    ;
                btfsc   STATUS,Z                ;
                goto    _eq16000000_1           ;
                btfsc   STATUS,C                ;
                goto    _then1                  ;
                goto    _7000000                ;

_eq16000000_1
                movf    BROJ.2,W                ;
                sublw   0x00                    ;
                btfsc   STATUS,C                ;
                goto    _then1                  ;
                


_7000000
                movf    BROJ.0,W                ;   // BROJ >= 7000000 (h'6A CF C0')
                sublw   0x6A                    ;
                btfsc   STATUS,Z                ;
                goto    _eq7000000_0            ;
                btfsc   STATUS,C                ;
                goto    _8500000                ;
                goto    _8000000                ;

_eq7000000_0
                movf    BROJ.1,W                ;
                sublw   0xCF                    ;
                btfsc   STATUS,Z                ;
                goto    _eq7000000_1            ;
                btfss   STATUS,C                ;
                goto    _8000000                ;
                goto    _8500000                ;

_eq7000000_1
                movlw   0xC0                    ;
                subwf   BROJ.2,W                ;
                btfss   STATUS,C                ;
                goto    _8500000                ;
        
_8000000
                movf    BROJ.0,W                ;    // BROJ <= 8000000 (h'7A 12 00')
                sublw   0x7A                    ;
                btfsc   STATUS,Z                ;
                goto    _eq8000000_0            ;
                btfss   STATUS,C                ;
                goto    _8500000                ;
                
_then2  decf    0x31,W                          ;   // dec
                goto    _end                    ;

_eq8000000_0
                movf    BROJ.1,W                ;
                sublw   0x12                    ;
                btfsc   STATUS,Z                ;
                goto    _eq8000000_1            ;
                btfsc   STATUS,C                ;
                goto    _then2                  ;
                goto    _8500000                ;

_eq8000000_1
                movf    BROJ.2,W                ;
                sublw   0x00                    ;
                btfsc   STATUS,C                ;
                goto    _then2                  ;


_8500000
                movf    BROJ.0,W                ;   // BROJ >= 8500000 (h'81 B3 20')
                sublw   0x81                    ;
                btfsc   STATUS,Z                ;
                goto    _eq8500000_0            ;
                btfsc   STATUS,C                ;
                goto    _else                   ;
                goto    _9000000                ;

_eq8500000_0
                movf    BROJ.1,W                ;
                sublw   0xB3                    ;
                btfsc   STATUS,Z                ;
                goto    _eq8500000_1            ;
                btfss   STATUS,C                ;
                goto    _9000000                ;
                goto    _else                   ;

_eq8500000_1
                movlw   0x20                    ;
                subwf   BROJ.2,W                ;
                btfss   STATUS,C                ;
                goto    _else                   ;

_9000000
                movf    BROJ.0,W                ;    // BROJ <= 9000000 (h'89 54 40')
                sublw   0x89                    ;
                btfsc   STATUS,Z                ;
                goto    _eq9000000_0            ;
                btfss   STATUS,C                ;
                goto    _else                   ;
                goto    _then2                  ;

_eq9000000_0
                movf    BROJ.1,W                ;
                sublw   0x54                    ;
                btfsc   STATUS,Z                ;
                goto    _eq9000000_1            ;
                btfsc   STATUS,C                ;
                goto    _then2                  ;
                goto    _else                   ;

_eq9000000_1
                movf    BROJ.2,W                ;
                sublw   0x40                    ;
                btfsc   STATUS,C                ;
                goto    _then2                  ;

_else   clrf    0x31                            ;   // else
_end    nop                                     ;   // end



; repeat BROJ + 5 until BROJ > 9000000
Code:

 repeat
   movlw   5;
   addwf   BROJ.2,F;
   btfss   STATUS,C;
   goto    _until;
   incf    BROJ.1,F;
   btfsc       STATUS,Z;
   incf    BROJ.0,F;
 until BROJ > 9000000
nop;

 
_repeat         movlw   0x05                    ;   // BROJ = BROJ+5
                addwf   BROJ.2,F                ;
                btfss   STATUS,C                ;
                goto    _until                  ;
                incf    BROJ.1,F                ;
                btfsc   STATUS,Z                ;
                incf    BROJ.0,F                ;

_until          movf    BROJ.0,W                ;   // BROJ > 9000000 (h'89 54 40')?
                sublw   0x89                    ;
                btfsc   STATUS,Z                ;
                goto    _eq0                    ;
                btfsc   STATUS,C                ;
                goto    _repeat                 ;
                goto    _end                    ;

_eq0    movf    BROJ.1,W                        ;
                sublw   0x54                    ;
                btfsc   STATUS,Z                ;
                goto    _eq1                    ;
                btfss   STATUS,C                ;
                goto    _end                    ;
                goto    _repeat                 ;

_eq1    movf    BROJ.2,W                        ;
                sublw   0x40                    ;
                btfsc   STATUS,C                ;
                goto    _repeat                 ;

_end    nop                                     ;



repeat BROJ + 5 until BROJ >= 9000000
Code:

 repeat
   movlw   5;
   addwf   BROJ.2,F;
   btfss   STATUS,C;
   goto    _until;
   incf    BROJ.1,F;
   btfsc       STATUS,Z;
   incf    BROJ.0,F;
 until BROJ >= 9000000
nop;

_repeat         movlw   0x05                    ;   // BROJ = BROJ+5
                addwf   BROJ.2,F                ;
                btfss   STATUS,C                ;
                goto    _until                  ;   // ovde se moze pisati i goto $+4
                incf    BROJ.1,F                ;
                btfsc   STATUS,Z                ;
                incf    BROJ.0,F                ;

_until          movf    BROJ.0,W                ;       // BROJ >= 9000000 (h'89 54 40')?
                sublw   0x89                    ;
                btfsc   STATUS,Z                ;
                goto    _eq0                    ;
                btfsc   STATUS,C                ;
                goto    _repeat                 ;
                goto    _end

_eq0            movf    BROJ.1,W                ;
                sublw   0x54                    ;
                btfsc   STATUS,Z                ;
                goto    _eq1                    ;
                btfss   STATUS,C                ;
                goto    _end                    ;
                goto    _repeat                 ;

_eq1            movlw   0x40                    ;
                subwf   BROJ.2,W                ;
                btfss   STATUS,C                ;
                goto    _repeat                 ;

_end            nop                             ;



repeat BROJ - 5 until BROJ < 9000000
Code:

 repeat
   movlw   0x05;
   subwf   BROJ.2,F;
   btfsc   STATUS,C;
   goto    _until;
   decf    BROJ.1,F;
   movf    BROJ.1,W;
   xorlw   0xFF;
   btfsc   STATUS,Z;
   decf    BROJ.0,F;
 until BROJ < 9000000
nop;

_repeat         movlw   0x05            ;   // BROJ = BROJ-5
                subwf   BROJ.2,F        ;
                btfsc   STATUS,C        ;
                goto    _until          ;   // ovde se moze pisati i goto $+6
                decf    BROJ.1,F        ;
                movf    BROJ.1,W        ;
                xorlw   0xFF            ;
                btfsc   STATUS,Z        ;
                decf    BROJ.0,F        ;

_until          movlw   0x89            ;  // BROJ < 9000000 (h'89 54 40')?
                subwf   BROJ.0,W        ;
                btfsc   STATUS,Z        ;
                goto    _eq0            ;
                btfsc   STATUS,C        ;
                goto    _repeat         ;
                goto    _end            ;

_eq0            movlw   0x54            ;
                subwf   BROJ.1,W        ;
                btfsc   STATUS,Z        ;
                goto    _eq1            ;
                btfsc   STATUS,C        ;
                goto    _repeat         ;
                goto    _end            ;
        
_eq1            movlw   0x40            ;
                subwf   BROJ.2,W        ;
                btfsc   STATUS,C        ;
                goto    _repeat         ;

_end    nop                             ;



repeat BROJ - 5 until BROJ <= 9000000
Code:

 repeat
   movlw   0x05;
   subwf   BROJ.2,F;
   btfsc   STATUS,C;
   goto    _until;
   decf    BROJ.1,F;
   movf    BROJ.1,W;
   xorlw   0xFF;
   btfsc   STATUS,Z;
   decf    BROJ.0,F;
 until BROJ <= 9000000
nop;

_repeat         movlw   0x05            ;   // BROJ = BROJ-5
                subwf   BROJ.2,F        ;
                btfsc   STATUS,C        ;
                goto    _until          ;   // ovde se moze pisati i goto $+6
                decf    BROJ.1,F        ;
                movf    BROJ.1,W        ;
                xorlw   0xFF            ;
                btfsc   STATUS,Z        ;
                decf    BROJ.0,F        ;

_until          movlw   0x89            ;  // BROJ <= 9000000 (h'89 54 40')?
                subwf   BROJ.0,W        ;
                btfsc   STATUS,Z        ;
                goto    _eq0            ;
                btfsc   STATUS,C        ;
                goto    _repeat         ;
                goto    _end            ;

_eq0            movlw   0x54            ;
                subwf   BROJ.1,W        ;
                btfsc   STATUS,Z        ;
                goto    _eq1            ;
                btfsc   STATUS,C        ;
                goto    _repeat         ;
                goto    _end            ;
        
_eq1            movf    BROJ2,W         ;
                sublw   0x40            ;
                btfss   STATUS,C        ;
                goto    _repeat         ;

_end    nop                             ;



repeat BROJ + 1 until BROJ == 9000000
Code:

 repeat
   incf   BROJ.2,F;
   btfsc  STATUS,Z;
   goto   _until;
   incf   BROJ.1,F;
   btfss  STATUS,Z;
   incf    BROJ.0,F;
 until BROJ == 9000000
nop;

_repeat         incf   BROJ.2,F         ; BROJ = BROJ+1
                btfss  STATUS,Z         ;
                goto   _until           ;
                incf   BROJ.1,F         ;
                btfsc  STATUS,Z         ;
                incf   BROJ.0,F         ;

_until          movlw   0x89            ;  // BROJ == 9000000 (h'89 54 40')?
                xorwf   BROJ.0,W        ;
                btfss   STATUS,Z        ;
                goto    _repeat         ;

_eq0            movlw   0x54            ;
                xorwf   BROJ.1,W        ;
                btfss   STATUS,Z        ;
                goto    _repeat         ;

_eq1            movlw   0x40            ;
                xorwf   BROJ.2,W        ;
                btfss   STATUS,Z        ;
                goto    _repeat         ;       

_end    nop                             ;
[ korak @ 12.09.2008. 11:00 ] @
Stojane, vidim da si zagrejan za podizanje nivoa programiranja na asembleru. Kada sam ja to radio za MC908 prvo sam postavio neke principe kojih cu se drzati:

1. Jezik mora biti sto blizi asembleru, svaki iskaz treba da se prevodi u jednu asemblersku naredbu. Od ovoga se izuzimaju samo neki posebni slucajevi.
2. Nema prevodjenja izraza, svi izrazi su konstantni. To znaci da su svi operandi izraza konstante. Prema ovome, ako se u izrazu nadje varijabla, onda se u konstantnom izrazu ona zamenjuje svojom adresom. Tako izraz GODINA+5 daje adresu varijable GODINA uvecanu za 5. Ako ne bi bilo tako, onda bih usao u vode visih programskih jezika gde bi se sreo sa problemom optimizacije prevoda.
3. Maksimalno izbaciti potrebu za labelama.
4.Uvesti strukture podataka i struktuirati kod.
5. Osloboditi programera svih poslova koje moze da uradi kompajler.

Mozda je najbolje da ti posaljem uputstvo koje sam poceo da pisem. Ono nije zavrseno, niti sredjeno, pa nemoj da zameris. Ako ti je interesantno procitaj ga. U njemu nisam opisao case..of, taj deo sam dodao u verziji uputstva koje pisem kuci.

[Ovu poruku je menjao korak dana 12.09.2008. u 12:11 GMT+1]
[ Stojan Trifunovic @ 12.09.2008. 23:20 ] @
Ideja sa makroima koji se razlicito ponasaju u odnosu na lokaciju varijable u memoriji i njihovo kasnije objedinjavanje zbirnim makroom je jednostavno odlicna. Sam sam pokusavao izvesti nesto slicno makroima MPLAB asemblera, ali nisam uspeo jer u njemu ne postoji odgovarajuca direktiva za odredjivanje maksimalne vrednosti "SizeOf(a)" parametara.

U relokativnom asemblerskom modu MPLAB-a mogu na primer zadati da se za varijablu GODINA rezervisu dva bajta, ali kasnije uslovnim asembliranjem nema nacina na koji mogu proveriti koliko je bajtova rezervisano. Tako moram koristiti posebne makroe, i pamtiti njihove nazive (interesantno, ali naziv mog makroa za inkrementaciju dvobajtne varijable je incf2b, odnosno, od Vaseg MMA se razlikuje u jednom jedinom slovu).

Isto tako, ukoliko su u makrou definisana tri parametra, sva tri se moraju navesti. U protivnom ce kompajler prijaviti gresku, i nece zavrsiti kompajliranje. Zato ni ne postoji mogucnost testa da li je odredjeni parametar makroa prisutan (kao exist u MMA) ili ne.

Uopste, makroi i direktive originalnog MPLAB asemblera su najslabija strana inace dobrog asemblera. Cak ne postoji nacin unosa visebajtnih vrednosti u makro, osim bajt po bajt. Na srecu, ovo se moze odredjenim (nedokumentovanim) trikovima zaobici, pa je cak moguc i unos labele ili jedne instrukcije kao parametra.


Sajt http://cablemodem.fibertel.com.ar/atferrari/ pod PIC dao mi je ideju o mogucoj upotrebi makroa za testiranje izraza (npr. u IF GODINA < 2008 THEN ili u REPEAT...UNTIL strukturi). Umesto da se deo koda koji ce biti izvrsen u slucaju ispravnog testa ubaci UNUTAR programske strukture (kao incf pa goto instrukcija u dosadasnjim primerima), makro ce u zavisnosti od rezultata testa preskociti (ili ne) sledecu instrukciju. Preskok sledece instrukcije je inace standardan nacin na koji se kod PIC16 serije realizuje grananje. To moze biti lakse za implementaciju u okviru MMA (stavise, mogu se lako napraviti takvi makroi), ali na mestu koje ce biti preskoceno ce se najcesce naci GOTO instrukcija, pa ce takav nacin imati jednu (goto) instrukciju vise, i trajace 3 instrukcijska ciklusa duze (2 zbog GOTO instrukcije i jedan zbog duzeg izvrsavanja preskoka te GOTO instrukcije). Osim toga ostale programske strukture (npr. case of) nece biti moguce lako realizovati na taj nacin. Javite mi da li Vam se takvo resenje cini prihvatljivijim.
[ korak @ 13.09.2008. 12:28 ] @
Evo na brzinu,
posto 16-tica nema uslovnih granjanja, sem preskoka, moze se uvesti makro za uslovno granjanje, i da se uz pomoc njih ima sve kao i kod 18-tice. Jeste da ce trositi 2 naredbe ali ce funkcionisati. Cak, nisu potrebni ni makroi, moze kompajler to da generise ako se uvedu pseudo naredbe uslovnih granjanja, a sam kompajler ce generisati kod kao i sto bi ga generisao makro namenjen tome.

Na primer (ako ne gresim)

beq labela; //beq je pseudo naredba

bi se prevelo kompajlerom bez problema kao:

btfsc STATUS,Z;
GoTo labela;

Pozdrav.
[ barum @ 13.09.2008. 15:50 ] @
Ove dve rečenice su u kontradikciji jedna s drugom:
Citat:
Stojan Trifunovic
...
Cak ne postoji nacin unosa visebajtnih vrednosti u makro, osim bajt po bajt. Na srecu, ovo se moze odredjenim (nedokumentovanim) trikovima zaobici, pa je cak moguc i unos labele ili jedne instrukcije kao parametra.
...

Znači ipak kažeš da postoji način.

Assembler direktno podržava maksimum trobajtne (24bitne) vrednosti:
Citat:

Syntax
high <operand>
low <operand>
upper <operand>
Description
These operators are used to return one byte of a multi-byte label value.


[ Stojan Trifunovic @ 14.09.2008. 07:30 ] @
@korak
U redu. Znaci ubuduce primenjujem takav princip.

@barum
Pazi, stvarno sam prolupao! Medjutim, i u Vasem citatu stoji kljucna rec LABEL. U datasheetu (Assembler/Linker/Librarian User�s Guide) se navodi da oni sluze za prenos sledecih parametara:
section start address
section end address
section size
address
kao i da je upper operand ogranicen na 6 bitova, sto efektno daje 21 bit.
Code:
If upper is used, only bits 16 through 21 of the expression will be used.

Medjutim, uvek bez problema dobijam svih 24 bitova.

Uopste se ne moze pronaci podatak ili primer da se ovi operandi uopste mogu koristiti za prenos parametara makrou.

Zato je upravo upotreba low, high i upper parametara nedovoljno dokumentovana, jer se eto mogu mnogo prakticnije upotrebljavati i za druge stvari, a ne samo za laksi prelazak strana programske memorije (PAGE) sto im je izgleda osnovna funkcija.

Ipak, moguce je unutar makroa procitrati kompletne 32-bitne parametre, po sledecem:
Code:

ime macro Var
   movlw Var & H'FF'        ; bajt najmanje tezine
   ...
   movlw Var >>D'08' & H'FF'
   ...
   movlw Var >>D'16' & H'FF'
   ...
   movlw Var >>D'24' & H'FF'     ; bajt najvece tezine.
   ...
 endm

Pogresio sam kada sam naveo da to (ni prenos labele kao parametra) nije dokumentovano. Ima ga u poglavlju 7 (Macro Language - ko mi je kriv kada retko kada citam priloge). Pre nego sto sam to video koristio sam istu takvu rotaciju, ali nad low, high i upper parametrima.

Ipak, u makro se moze dodati i jedna (ne vise zbog nemogucnosti ubacivanja ENTER karaktera) instrukcija BEZ ZAREZA. Tacnije, moglo bi se ubaciti i vise instrukcija, ali moraju biti odvojene zarezom ili ostalim parametrima. To takodje nije dokumentovano, a moglo bi se iskoristiti.

Nazalost, asembler ima jos mana. Iako je znaci moguce (mada ne i prakticno ispisivati Var >>D'24' & H'FF' bas bi mu falila jedna superupper direktiva) prenositi tridesetdvobitne parametre, iako ih i simulator podrzava, uslovno poredjenje (if direktiva) moze porediti samo oko 28 bitova (nisam tacno proveravao, mozda moze i koji bit vise, ali sigurno ne svih 32 bita).

To znaci da ce uslovno poredjenje ispravno raditi pri
if BROJ == h'F FF FF FF'
ali ne i prilikom
if BROJ == h'FF FF FF FF'.

Naravno i ovo se moze resiti testiranjem trobajtne varijable AND bajta najvece tezine, ali to usporava razvoj programa i cini kod nerazumljivijim nego sto jeste.

Jeste, nacin uvek postoji (ko me uopste tera da koristim makroe), ali ukoliko iziskuje borbu sa asemblerom, cemu sve to.

[Ovu poruku je menjao Stojan Trifunovic dana 15.09.2008. u 17:48 GMT+1]
[ barum @ 14.09.2008. 11:50 ] @
Citat:
Stojan Trifunovic:
U datasheetu (Assembler/Linker/Librarian User�s Guide) se navodi da oni sluze za prenos sledecih parametara:
section start address
section end address
section size
address
kao i da je upper operand ogranicen na 6 bitova, sto efektno daje 21 bit.



Ne piše da je upper ograničen već
Citat:
only bits 16 through 21 of the expression will be used

znači od onog što vrati koriste se samo ovi bitovi u adresnim registrima jer su najviši bitovi neimplementirani u osmobitnjacima.

Piše da služe za prenos navedenih sdresa i to ne isključuje upotrebu ovih operatora za druge potrebe.
U stvari za
Citat:

section start address
section end address
section size

treba koristiti operatore sa prefiksima:
scnstart_
scnend_
scnsz_

Citat:
Stojan Trifunovic:
Nazalost, asembler ima jos mana. Iako je znaci moguce (mada ne i prakticno ispisivati Var >>D'24' & H'FF' bas bi mu falila jedna superupper direktiva) prenositi tridesetdvobitne parametre, iako ih i simulator podrzava, uslovno poredjenje (if direktiva) moze porediti samo oko 28 bitova (nisam tacno proveravao, mozda moze i koji bit vise, ali sigurno ne svih 32 bita).

Da ste proverili sa 32bitnom vrednošću, nešto bi ste saznali o onome ko vam je to rekao.

Direktiva koja fali nije problem:
#define superupper(value) ((value>>D'24') & 0xFF)
i problem rešen.


Citat:
Stojan Trifunovic:
Ideja sa makroima koji se razlicito ponasaju u odnosu na lokaciju varijable u memoriji i njihovo kasnije objedinjavanje zbirnim makroom je jednostavno odlicna. Sam sam pokusavao izvesti nesto slicno makroima MPLAB asemblera, ali nisam uspeo jer u njemu ne postoji odgovarajuca direktiva za odredjivanje maksimalne vrednosti "SizeOf(a)" parametara.

U relokativnom asemblerskom modu MPLAB-a mogu na primer zadati da se za varijablu GODINA rezervisu dva bajta, ali kasnije uslovnim asembliranjem nema nacina na koji mogu proveriti koliko je bajtova rezervisano.

Hm, otkud to da nema načina?
Evo na primer kako može da se napravi za relokabilni objekt

Code:

Allocate   macro  var,size
var#v(0)section  UDATA
var          RES size
     endm

#define SizeOf(var)  scnsz_low var#v(0)section

Jedan makro "to rule them all". :)
a koristio bi se ovako:

Code:

            UDATA
mulcnd      RES 1 ; 8 bit multiplicand
mulplr      RES 1 ; 8 bit multiplier
H_byte      RES 1 ; High byte of the 16 bit result
L_byte      RES 1 ; Low byte of the 16 bit result
count       RES 1 ; loop counter

            Allocate  test_variable, 0x1C
            Allocate  buffer, 0x5E

    GLOBAL mulcnd, mulplr, H_byte, L_byte


      CODE
mpy
    GLOBAL mpy
    movlw SizeOf(test_variable)


ili ako treba veće strukture od 256 bajtova onda
#define SizeOf(var) (((scnsz_high var#v(0)section)<<8) +scnsz_low var#v(0)section)

Edit, za uslovno asembliranje može i samo ovako:

Code:

Allocate     macro  var,size
var          RES size
var#v(0)sizeof EQU size
             endm

#define SizeOf(var)  var#v(0)sizeof




Pozdrav,
Bojan


[Ovu poruku je menjao barum dana 14.09.2008. u 13:39 GMT+1]
[ Stojan Trifunovic @ 14.09.2008. 19:37 ] @
Cek cek! Za uslovno asembliranje sam sam proveravao! Koliko se secam trebao sam unutar makroa proveriti da li je parametar koji se spolja ubacuje u njega u dozvoljenim granicama, pa sam ga testirao na vrennost 0x00 i na vrednost vecu od 0xFF FF FF FF. Hm ! Pa jeste. Nije ni cudo sto to nisam uspeo proveriti. Za reg > 0xFF FF FF FF bi asembler morao raditi sa vise od 32 bita.

U pravu ste za scnsz_low parametar. Do sada sam (naveden datasheetom i porukom koja se javlja pri koriscenju HIGH operanda u slucaju da je vrednost parametra veca od 0xFFFF) pretpostavljao da deluje jedino nad programskom memorijom. Pa nista. Covek se uci dok je ziv. Hvala Vam sto ste mi prosirili vidike.
[ Stojan Trifunovic @ 15.09.2008. 19:20 ] @
@barum
Ne vredi. Ne uspevam ni na koji nacin upotrebiti scnsz_low. Probao sam najjednostavniji moguci slucaj:
Code:

WORD        UDATA
DVA_BAJTA   RES 2

            CODE
            movlw scnsz_low WORD
            i
            movlw scnsz_low DVA_BAJTA

i u oba slucaja dobio gresku linkera. Onda sam probao i imenovane code sekcije, pa cak i default imena svih sekcija po linkerskoj skripti i opet nista.
Google mi za upotrebu scnsz_low operacije daje samo dva linka (osim datasheeta). Oba bezvredna.

Ni vas primer sa njom, eto ne radi.

Vas kraci primer (za uslovno asembliranje) naravno radi, ali to nije to. Mogao sam isto tako rucno EQU direktivom definisati velicinu varijable (iako Vas makro za alokaciju svakako ubrzava posao). Ono sto sam svojevremeno hteo je da asembler sam prepozna velicinu odredjene varijable (4 bajta bi bila dovoljna), i da u zavisnosti od velicine rezervisanih bajtova res direktivom uslovnim asembliranjem izvrsavam razlicite kodove (kao primer za inkrementaciju u korakovom kompajleru).

Jeste, moguce je preko EQU, ali opet, Korakov kompajler to po defaultu omogucava, a MPLAB-ov izgleda ne. Upravo zbog toga sam isticao borbu sa asemblerom.

Koristim MPLINK 4.14 pa mi mozda zbog njegove starosti ne radi scnsz_low. Skinucu za par dana novi MPLAB, pa cu probati opet.
[ barum @ 15.09.2008. 23:01 ] @
Moguće da je verzija u pitanju.
Ja trenutno koristim MPLINK 4.21, 12. Jun 2008., koji stiže sa MPLAB-C18-StudentEdition-v3_21.

Evo u atačmentu i primera koji se kod mene bez greške kompajlira i linkuje.

Edit, evo ovde kažu da 2005 godine isto nije bila naročito nova stvar
http://forum.microchip.com/tm.aspx?m=83637&mpage=1&#83658
i da je on line manual ima još odavno a da nije ubačeno u štampano izdanje (pdf).
I ovaj moj manual (33014J) je iz 2005 godine.
Zanimljivo, gde li im je taj online manual???

[Ovu poruku je menjao barum dana 16.09.2008. u 00:17 GMT+1]

[Ovu poruku je menjao barum dana 16.09.2008. u 00:19 GMT+1]
[ obranko @ 16.09.2008. 06:46 ] @
Pozdrav svim diskutantima.
Koliko vidim, kolega Korak pravi svoj programski jezik za pic, nesto izmedju asemblera i c. Ako je cilj toga seminarski ili diplomski rad u nekoj skoli/fakultetu to je jako dobro. ako to radi iz cistog hobija i to je jako dobro. ali ako to radi da bi koristio kao alatku za projekte koje naplacuje, to je ekonomski ne opravdano. da bi se napravio asembler (narocito ako ima optimizaciju), linker i simulator potrebno je relativno dosta vremena - recimo da je kolega izvaredan u tome i da ce ceo projekat da zavrsi (zajedno sa testiranjem) za 4 nedelje. to je 150 sati rada. dobar c kompajler se moze kupiti za oko 200-250usd. to znaci da kolega zaradjuje nesto preko 1usd na sat.
jos nesto, danas se jako mali deo koda pise u asembleru. obicno su to rutime za obradu prekida i rutine koje bitno uticu na brzinu rada. razlog za to je opet cena. razviti jedan program u c je mnogo brze nego razviti ga u asembleru, znaci manje kosta.
ja se slazem da je dobro napisan kod u c nesto veci i nesto sporiji od dobro napisanog koda u asembleru. ako kod nije dovoljno brz, jedno od mogucih resenja je uzeti brzi procesor.
u dobra stara vremena kada sam radio u bgd-u i ja sam koristio najjeftinije moguce procesor. razlog za to je bio da je tada rad bio jako jeftin tako da je dodatnih par sati rada na asembleru bilo mnogo jeftinije nego kupovina c kompajlera ili koriscenje brzih, sam tim i skupljih, procesora.
jos dva moguca problema su:
ako kolega korak jednog dana odluci ili bude primoran da portuje svoj kod za procesor drugog proizvodjaca,
ili ako program treba odrzavati ili menjati.

[ korak @ 16.09.2008. 11:36 ] @
@obrenko,

prerastao sam seminarske radove, diplomske i magistarske, ovo radim kako iz hobija, tako i zbog toga sto nisam jos video dobar asembler. Inace prvi asembler tog tipa sam napisao pre 10 godina za HC11, sada sam ga prepravio za MC908, sto mi nije oduzelo mnogo vremena. Inace, profesionalni C kompajleri ne mogu da se kupe bez par hiljada dolara. To mi je mnogo za jedan tako nesavrsen jezik, bez obzira na njegovu siroku zastupljenost i prenosivost. Nemam potrene za ovim drugim jer koristim samo jednu familiju mikrokontrolera. Naravno bilo bi lepo da mogu koristiti vise familija i da za svaku mogu da odvojim po nekoliko hiljada dolara za razvojni sistem, ali ne mogu.

Osim toga, imam malu firmu koja se bavi proizvodnjom uredjaja sa MCU-ovima, i ja u njoj radim razvoj, a placam usluge drugim firmama koje mi proizvode, pune ozivljavaju, testiraju i asembliraju uredjaje. Tako ispada da imam dosta slobodnog vremena i za ovakve poslove.

Pozdrav.
[ obranko @ 17.09.2008. 02:51 ] @
Pozdrav,

da li si pogledao c kompajler firme CSS (http://www.ccsinfo.com/content.php?page=compilers). Ja sam kupio M verziju (za familiju 16xxx) pre par godina. Cena mu je bila 150usd. radio sam tada neke male projekte za jednu malu firmu. cesto su izbacivali nove proizvode koji su bili bazirani na starim proizvodima. u pocetku sam koristio asembler, a onda sam zakljucio da previse vremena trosim pisuci i modifikujuci kod pa sam presao na c (cisto ekonomski razlozi). Mana kompajlera je sto trosi previse memorije, a dobra strana sto moze da se poveze sa mplab-om i sto znatno ubrzava razvoj program jer ima biblioteke za sve. mislim da imaju demo koji se moze besplatno skinuti (nadam se da imas dovoljno brzu internet vezu).
[ korak @ 17.09.2008. 12:13 ] @
@obrenko,

nisam. Imao sam prilike da pogledam i testiram Metrowerks CodeWarrior za MC908 i MC9S08, kao i Keil za 8051. Ovaj prvi je ogranicen na generisanje koda od 4KB, a drugi je legalna verzija koju mi je dala neka firma kada sam za nju radio neki projekat. Pogledao sam sajtove proizvodjaca oba C kompajlera. I sta sam video, kao da su podelili trziste, ne postoji ni jedan MCU za koji su obe firme napisale kompajler. Dogovorili se da drze monopol profesionalnih kompajlera i da medjusobno ne konkurisu, zato su im i cene visoke.

Oba kompajlera su po mojoj oceni vrhunska. Optimizacije koje vrse su raznovrsne i slozene. Prevode odjednom vise iskaza optimizujuci kod. Efikasno optimizuju petlje obzirom na brojacku varijablu i t. d.

Ako si pogledao prikaceni fajl, u nekom mom predhodnom odgovoru, koji je nedovrseni uputstvo za asembler koji sam napisao za MC908 mogao si da vidis sta mi je bio cilj. Sa njim radim vec 10 godina (zajedno sa ranijim verzijama) i mislim da sam postigao produktivnost koja se priblizava produktivnosti programiranja u C-u. Mana mu je neprenosivost, ali ja za tim nemam potrebe.

Pozdrav.

[ Odin D. @ 17.09.2008. 13:05 ] @
Ja mislim da je Motorola vec odavno preuzela Metrowerks, vjerovanto je kasnije potpao pod Freescale kad je doslo do odvajanja, tako da se nije ni cuditi sto ne razvijaju kompajlere za procesore drugih firmi sa kojima je Freescale u konkurenciji.
A Keil je pravio kompajlere za ARM, 8051, XC16x i ST10 procesore, ali cini mi se da je i njih prije par godina kupio ARM, tako da je pitanje sta ce i od njihove proizvodne palete ostati u buducnosti.
Mada, IAR jos ima prilicno sarolik izbor kompajlera:
http://www.iar.com/website1/1.0.1.0/50/1/index.php?



[Ovu poruku je menjao Odin D. dana 17.09.2008. u 14:15 GMT+1]
[ korak @ 17.09.2008. 14:10 ] @
Pogledao sam pazljivije, da u pravu si.
Zahvaljujem.
pozdrav.
[ Stojan Trifunovic @ 18.09.2008. 10:26 ] @
Hm! Ipak sam bio u pravu za uslovno asembliranje i maksimalan broj bitova. Danas sam pokusavao da objedinim neke makroe, i naleteo na nelogicnu gresku upravo prilikom uslovnog asembliranja.

Otkrio sam da je nemoguce bilo kakvoj asemblerskoj varijabli testirati 32-bitnu vrednost. Jedino 31-bitnu.

Najpre sam pomislio da je problem do drugacijeg formata zapisa heksadecimalnih brojeva (sa 0x umesto h'), ali greska se reprodukovala i prilikom decimalnih, pa cak i binarnih brojeva.

Onda sam pomislio da bi test uslovnog asembliranja mozda bio moguc dodelom varijable na drugaciji nacin, ali ni to nije pomoglo.

Pokusao sam i da varijabli dodelim dozvoljenu vrednost pa da je saberem sa drugom vrednoscu i tako izazovem prekoracenje 31-bitne granice. Bezuspesno.

Uglavnom, izgleda da je nemoguce u MPLAB-ovom asembleru na bilo koji testirati 32-bitne vrednosti odjednom. Testiranje bi moralo ici preko test (low_high_upper) && superupper.

Varijable ovde nisu problem (njihove vrednosti su ispravno dodeljene sto dokazuje ispravan Var >> D'24' & H'FF' oblik), ali uslovni test eto nije.

Evo testa koji to dokazuje.

Code:

;br = 0x7fffffff ; 31 bit
;br = 0x80000000 ; 32 bita

;br = d'2147483647' ; 31 bit
;br = d'2147483648' ; 32 bita

;br = .2147483647 ; 31 bit
;br = .2147483648 ; 32 bita

;br = b'1111111111111111111111111111111' ; 31 bit
br = b'10000000000000000000000000000000' ; 32 bita

;br = 0x80000000 ; 32 bita
;       variable br = 0x80000000 ; 32 bita
;       constant br = 0x80000000 ; 32 bita
;br     set  0x80000000 ; 32 bita
;br     equ 0x80000000 ; 32 bita


        if br <= 0xFF
        error "Greska"
        endif

; Ispravan nacin testiranja bi bio

        if (br & 0xFF) <= 0xFF && ((br >> .8) & 0xFF) == .0 && ((br >> .16) & 0xFF) == .0 && ((br >> .24) & 0xFF) == .0
        error "Ispravno testiranje"
        endif
[ barum @ 18.09.2008. 12:58 ] @
Nije greška sa maksimalnim brojem bitova već pretpostavka da su unsigned.
Tip "int" je uobičajeno signed.
[ Stojan Trifunovic @ 18.09.2008. 14:24 ] @
Pazi stvarno!

Znaci ako testiram (sa if) jednobajtnu vrednost, ona je unsigned. 2 i 3-bajtna takodje, a samo ako koristim test sa 4 bajta (svih 32 bita) onda je ona signed. E to stvarno nisam ocekivao!
[ korak @ 18.09.2008. 16:37 ] @
Ovo je nedopustivo za asembler. Unositi predpostavku da je 32-o bitni broj oznacen, u izracunavanju konstantnih izraza, upucuje na to da kompajler izracunava konstantne izraza sa 32-o bitnom tacnoscu. Ja sam u svom kompajleru uveo za izracunavanje konstantnih izraza 64-o bitnu tacnost, bas iz tih razloga.

Medjutim ostaje problem da kada definicete konstantu kompajler mora da joj odredi tip. Ja sam to resio tako da svaki broj bez znaka ima neoznacen tip. No, to ne mora da bude. Na primer:

Konstanta1 = 100;
Konstanta2 = shortint(100);

gde sam uveo eksplicitnu dodelu tipa. Tako i

Konstanta1 = 200000000;
Konstanta2 = longint(200000000);

Konstanta1 je neoznacena, a Konstanta2 oznacena.

Ima u svemu tome puno stvari koje trebaju da se sagledaju pre nego sto pocne da se pise kompajler.

Pozdrav.

[ barum @ 18.09.2008. 18:05 ] @
Citat:
Stojan Trifunovic: Pazi stvarno!

Znaci ako testiram (sa if) jednobajtnu vrednost, ona je unsigned. 2 i 3-bajtna takodje, a samo ako koristim test sa 4 bajta (svih 32 bita) onda je ona signed. E to stvarno nisam ocekivao!


Sve vrednosti su istog tipa (int) i kao takve se mogu i videti u SYMBOL TABLE u .lst fajlu.

@korak
"Pretpostavka" nije posebno unesena za asembler, već je jednostavno odraz programskog jezika C u kome je MPASM pisan.
[ korak @ 18.09.2008. 18:32 ] @
Da, ali se u C-u mogu deklarisati i 8-o bajtne celobrojne vrednosti. Dakle, sve je zavisilo od onog koji je pisao kompajler.

Pozdrav.