I tako, malo po malo mi dođosmo do glavnog programa. U asembleru je on principielno postavljen gotovo na isti način kao i kod viših programskih jezika. Uglavnom se pozivaju funkcionalne cjeline (potprogrami) jedan za drugim do kraja glavnog programa. 
Većina glavnih programa kao i potprograma i rutina nema kraj u klasičnom smislu te riječi. Glavni program se uvijek vraća na svoj početak zatvoren u bezuvjetnu petlju ili uvjetnu s grananjem na njegov početak kao jednom od opcija. Ja se ne sjećam ni jednog programa koji je imao klasičan kraj, osim nekih koji su služili testiranju.
To nam govori jednu veoma važnu stvar, da se glavna bitka kod izrade programa pa tako i srukturiranje vrši u potprogramima, rutinama, driverima itd... No ipak, on nam govori, struktura glavnog programa, koliko smo dobro segmentirali program i jesmo li dobro odvagali funkcionalne cjeline. Kao što nevalja previše rascjepkat glavni program tako nevalja ni nagurat hrpu stvari u dva-tri funkcionalana bloka. 
Glavni program je naš prvi korak, ulaz, u strukturiranje programa bez obzira što će najveći teret podnijeti potprogrami a počesto male rutine. Najvažnije je da se ne upustimo u beskrajno cjepaknje potprograma kao ni pretjerano sabijanje u jednu nefunkcionalnu, bolje reć teško funkcionalnu, cjelinu. 
Na primjerima koje slijede pokušati ću vam pokazati kako gore rečeno i nemora uvijek biti ispravno.
Naravno nemora uvijek glavni program biti samo niz poziva na veće potprograme. Dobar primjer za to jesu emulatori pay-tv kartica. Njihovi glavni programi su prilično dugački i nerjetko kompleksni. Ali to je samo radi specifičnosti problema koji se njima rješavaju a ne nepoznavanja programiranja u asembleru.
Primjer jednog glavnog programa takvog emulatora:
Code: Select all
; main:
avr00BF:  clr    r17          ; 00BF 2711
          clr    XH
          sts    0x0062, r17  ; 00C0 9310 0062 upisi 00
          sts    0x0063, r17  ; 00C2 9310 0063
          clr    r8           ; 00C4 2488 
          clr    r7
          clr    r21
          rcall  avr0046      ; 00C5 DF80
bbg:      ldi    ZH, 0x02     ; 00C6 E0F2        Load a config in @ 0x02FE (0xFF80)
          clr     r17
          ldi    XL, 0x61     ; 00CE E6A1    
          ld     r17, X       ; 00CF 911C
          cpi    r17, 0x05    ; 00D0 3015
           brne  avr00D3      ; 00D1 F409
          rjmp   avr01C1      ; 00D2 C0EE        Handle ECM, interesting part!!!!
avr00D3:  cpi    r17, 0x01    ; 00D4 3011     01     EMM
           brne  avr00EE 
          rjmp   EMM          ; 00D6 CFBF        rutina EMM bio 0096  0062 sig wrong!
avr00D7:  ld     r17, X+      ; 00D7 911D
          cpi    r17, 0x0A    ; 00D8 301A
           brne  avr00E6      ; 00D9 F461
          ld     r17, X+      ; 00DA 911D
          cpi    r17, 0x05    ; 00DB 3015
           brne  avr00E6      ; 00DC F449
          ld     r17, X+      ; 00DD 911D
          subi   r17, 0x02    ; 00DE 5012 12-2=10h
          ld     ZH, X+       ; 00DF 91FD
          ld     ZL, X+       ; 00E0 91ED
          clt
avr00E1:  ld     r18, X+      ; 00E1 912D
          rcall  avr02FD      ; 00E2 D21A
          dec    r17          ; 00E3 951A
          brne  avr00E1       ; 00E4 F7E1
          set
          rjmp   avr018C      ; 00E5 C0A6
avr00E6:  ldi    r17, 0x69    ; 00E6 E619
          ldi    XL, 0x02     ; 00E7 E6A2
          st     X+, r17      ; 00E8 931D
          ldi    r17, 0x00    ; 00E9 E010
          st     X+, r17      ; 00EA 931D
          ldi    XL, 0x67     ; 00EB E6A7
          st     X+, r17      ; 00EC 931D
          rjmp   avr018C      ; 00ED C09E
avr00EE:  ldi    XL, 0x64     ; 00F2 E6A4 --------- pocinje klasa 02 prijavna rutina ------------------------
          ld     r17, X+      ; 00F3 911D  ext eeprom  write 
          cpi    r17, 0xFF    ; 00F4 3F1F
           breq  avr00D7      ; 00F5 F309
          set                 ; 00F6 9468 
          cpi    r17, 0x00    ; 00F7 3010
           brne  avr00FE      ; 00F8 F429
          ldi    ZL, 0x15     ; 00F9 E1E5 serial num
          ldi    r17, 0x14    ; 00FA E114
          sts    0x0067, r17  ; 00FB 9310 0067
          rjmp   avr018B      ; 00FD C08D         
avr00FE:  cpi    r17, 0x01    ; 00FE 3011    P1 01 (card serial num HEX)
           brne  avr0107      ; 00FF F439 
           ldi    r17, 0x10    ; 0101 E110
          sts    0x0067, r17  ; 0102 9310 0067
          ldi    ZL, 0xF0
          rcall  avr02F2
          mov    r18, r0
          cpi    r18, 0x01
          brne   vlki
          ldi    ZL,0x8A
          rjmp   avr018B      ; -- bio wfc  hex ser iz flasa
vlki:     ldi    ZL, 0x2A     ; 0100 E2EA   trebalo biti od providera tekuceg !:)bio A2
          rjmp   avr010A      ; 0106 C085  salje u cam 
avr0107:  cpi    r17, 0x02    ; 0107 3012   P1 02 (country code + COCO string)
           brne  avr0110      ; 0108 F439
          ldi    ZL, 0x3B     ; 0109 E3EB  treba bit od tekuceg providera (a moze i ALL)
avr010A:  ldi    r17, 0x10    ; 010A E110
avr010D:  sts    0x0067, r17  ; 010B 9310 0067 len
          rjmp   avr018B      ; 010F C07C
avr0110:  cpi    r17, 0x0B    ; 0110 301B   P1 0B (country code other way)
           brne  avr0114      ; 0111 F411
          ldi    ZL, 0x3B     ; 0112 E4E8 coco
          rjmp   avr010A      ; 0113 CFF6
avr0114:  cpi    r17, 0x03    ; 0114 3013   P1 03  (get PID ) 
           brne  avr0125      ; 0115 F479
          ldi    r17, 0x18    ; 0116 E118 14 + 4 =18
          ldi    ZL, 0x4C     ; 0119 E4EC PW 0315 za P00
          lds    r25, 0x0066  ; 011B 919D   uzima provider num iz srama ! 
          cpi    r25, 0x00    ; 011C 3090   P2 00 (provider 00) ako ne 10 !! :)
           breq  avr010D      ; 011D F021
          ldi    ZL, 0x65     ; 011E E6E5  za P 10  0318 (PW)    
          rjmp   avr010D      ; 0121 C06A uzima config u obzir i trazi u eepromu
avr0125:  cpi    r17, 0x0E    ; 0125 301E  P1 0E (read card file)
           brne  avr013D      ; 0126 F429   staviti CF umjesto kljuceva za secu u eeprom 00
           ldi   XL, 0x65     ;
           ldi   ZH, 0x00     ;
           ld    r22, X+      ;
           cpi   r22, 0x02    ;
           breq  avr0126      ;
           cpi   r22, 0x03    ;
           breq  avr0127      ;
avr0126:  ldi    ZL, 0x00     ; CF 1 begin
          rjmp   avr0128      ; 
avr0127:  ldi    ZL, 0x40     ; CF 2 begin 
avr0128:  ldi    r17, 0x40    ; 0128 E410
          sts    0x0067, r17  ; 0129 9310 0067 sve sto izbacuje prema camu pocinje od 60
          rjmp   avr018B      ; 012B C05F  sa rutinom avr018B :)
avr013D:  cpi    r17, 0xEF    ; 013D 3E1F
           brne   avr012C        ; 013E F441
          ldi    XL, 0x68     ; 013F E6A8
          ld     ZH, X+       ; 0140 91FD
          ld     ZL, X+       ; 0141 91ED
          ldi    r17, 0x12    ; 0142 E112
          sts    0x0067, r17  ; 0143 9310 0067
          rcall  avr02E1      ; 0145 D19B
          rjmp   avr018C      ; 0146 C045  bio 018C
avr012C:  cpi    r17, 0x08    ; 012C 3018  P1 08 (20h baytes from buffer ??)
           brne  avr0133      ; 012D F429
          ldi    ZL, 0xA0     ; 012E E8E0 bio 80
          ldi    r17, 0x20    ; 012F E210 FF00000000000000000000000000000000000000 32 bayt
          sts    0x0067, r17  ; 0130 9310 0067
          rjmp   avr018B      ; 0132 C058
avr0133:  cpi    r17, 0x11    ; 0133 3111 P1 11 (????) nije mi trebao 
           brne  avr0147      ; 0134 F441
          ldi    ZL, 0x00     ; 0135 EAE0   never use it 
          ldi    ZH, 0x00 
          ldi    r17, 0x58    ; 0136 E518
          sts    0x0062, r17  ; 0137 9310 0062
          ldi    r17, 0x40    ; 0139 E410
          sts    0x0067, r17  ; 013A 9310 0067
          rjmp   avr018B      ; 013C C04E
avr0147:  cpi    r17, 0x09    ; 0147 3019 P1 09 (cam key)
           brne  avr0166      ; 0148 F4E9
          ld     r17, X+      ; 0149 911D
          cpi    r17, 0x03    ; 014A 3013
           brne  avr0165      ; 014B F4C9
          ldi    r17, 0x55    ; 014C E515
          ldi    XL, 0x62     ; 014D E6A2
          st     X+, r17      ; 014E 931D
          ldi    r17, 0x00    ; 014F E010
          st     X+, r17      ; 0150 931D
          sts    0x0067, r17  ; 0151 E6A7
          lds    r17, 0x0066   ; 0153 E6A6
          lsl    r17          ; 0155 0F11
          lsl    r17          ; 0156 0F11
          lsl    r17          ; 0157 0F11
          ldi    r25, 0x68    ; 0158 E698 08
          add    r17, r25     ; 0159 0F19
          mov    XL, r17      ; 015A 2FA1 pozicija cam keya
          ldi    r17, 0x08   ; 015B E017 bio 07
          ldi    YH, 0x01     ; 015C E0F1 stog 01c5--- 8 bayta za cam key c6----last byt c5
          ldi    YL, 0xCD 
avr015E:  ld     r18, X+      ; 015E 912D
          st     -Y, r18      ; 015F 9321 reversno spremanje
          dec    r17          ; 0160 951A
           brne  avr015E      ; 0161 F7E1 
          rcall  CKP    
avr0165:   rjmp   avr018C   
avr0166:  cpi    r17, 0x0A    ; 0166 301A
           breq  avr0169      ; 0167 F009
          rjmp   avr00E6      ; 0168 CF7D
avr0169:  ld     r17, X+      ; 0169 911D
          cpi    r17, 0x01    ; 016A 3011
           brne  avr0180      ; 016B F4A1
          ld     r17, X+      ; 016C 911D
          cpi    r17, 0x02    ; 016D 3012
           brne  avr0180      ; 016E F489
          ld     r17, X+      ; 016F 911D  
          cpi    r17, 0x04    ; 0170 3014
           brne  avr0180      ; 0171 F471
          ld     r17, X+      ; 0172 911D
          cpi    r17, 0x47    ; 0173 3417
           brne  avr0180      ; 0174 F459
          ld     r17, X+      ; 0175 911D
          cpi    r17, 0x11    ; 0176 3111
           brne  avr0180      ; 0177 F441
          ldi    ZH, 0x02     ; 0178 E0F2
          ldi    ZL, 0x40     ; 0179 E4E0
          ld     r18, X+      ; 017A 912D
          clt                 ; 017B 94E8
          rcall  avr02FD      ; 017C D180
          ld     r18, X+      ; 017D 912D
          rcall  avr02FD      ; 017E D17E
          set                 ; 017F 9468
avr0180:  ldi    r17, 0x00    ; 0180 E010
          sts    0x0067, r17  ; 0181 9310 0067
          lds    r17, 0x0065  ; 0183 9110 0065
          ldi    r25, 0x5E    ; 0185 E59E
          sbrs   r17, 1       ; 0186 FF11          pin answer 
          ldi    r25, 0x50    ; 0187 E590
          sts    0x0062, r25  ; 0188 9390 0062
          rjmp   avr018C      ; 018A C001
avr018B:  rcall  avr002D      ; 018B DEA1 citanje eeproma i slanje u cam odgovora
avr018C:  ldi    r21, 0x00    ; 018C E050
avr018D:  rcall  avr007B      ; 018D DEED  upis u cam
          rjmp   avr00BF      ; 018E CF30  Kao što vidite ide u bezuvjetnu petlju na svoj početak
Primjer jednog kasičnog glavnog programa:
 
Code: Select all
MAIN:    rcall  TASTS         ; bivsi TASTE
         clr  TMARK           ; marker za operaciju umanji TIMER skutera
         clr  COUNT           ; brojac prolaska 6S [timer mode] * 10 == 60S // 1min
         ldi  r17, 4          ; bio 80
         out  TIMSK, r17      ; ukljuci timer1 16bitni na OVFL mode 
         clr  YL
TAS1:    sbrc  TMARK, 0
         rcall  TMDOW         ; umanji vrijeme skuterima za jedan
         sbrc  TMARK, 7
         rcall  BLINK         ; rutina za upozorenje da je vrijeme isteklo
         rcall  ANIM1         ; poziva potprogram za animaciju, generira pokretnu sliku na LCD
         rcall  DEL87mS      ; ovi dely-i od 87mS su dodani radi usporavanja zbog animacije.
         Gore                ; UP taster
         rcall  UPMD
         Dolje               ; Ova naredba je jedan od primjera macro naredbe // DOWN taster 
         rcall  DOWMD
         rcall  DEL87mS
         OK                   ; OK taster
         rjmp  TAS2
         Stop                 ; STOP taster
         rjmp  TAS4
         rjmp  TAS1         ; kao što vidimo ovaj glavni program vrti od starta TAS1 to je stvarni glavni program
Donji glavni program je veoma jednostavan. Poziva direktno tri veća potprograma i uvjetno, ovisi o stisnutom tasteru, četiri jednostavnija potprograma. I ovdje je kao i u gornjem primjeru izvšeno, na neki način, uvjetno grananje na početak iako je naredba za direktno grananje 
rjmp korištena no njoj prethodi macro naredba Stop u kojoj se testira bit i određuje gdje će program ići. To je jedan od najčešćih načina vraćanja na početak.
U primjerima, pogotovo donjem, vidjeli smo da možemo definirati i svoje vlastite naredbe, 
macro naredbe. Naravno assembler će ih uredno prevesi u jedini skup naredbi kojeg mikroračunalo razumije, objektni kod. Za razliku od C-a, VB-a... mi ćemo točno znati strukturu te virtualne naredbe jer ćemo je morati napisati s naredbama iz skupa naredbi s liste MCU-a. 
Primjer one naše macro naredbe:
.macro  Gore
   sbis  PIND, 1
.endm
Iz ovog primjera je jasno da ona ne skraćuje postupak niti išta pojednostavljuje već nam samo omogučava da preimenujemo naredbu 
sbis PIND, 1 u nama razumljiviji oblik. Takve se vrste macro definicija koriste kad imate puno toga za definirati pa da vam bude lakše pamtiti. Pogotovo na primjerima kompleksnijih upotreba pinova MCU-a. Kad radite s hrpom pinova kojima su dodjeljene određene funkcije na HW-skom layeru. HW-ski layer je maska (nešto složenije) koja se koristi kod spajanja nekog sklopa, IC-a, komunikacije, itd... na MCU. Npr. CS, WE, RD, Vpp... signali koji se koriste kod programiranja 
recimo UV-eeproma a realno su pinovi našeg MCU-a. Njih je tad dobro nazvati funkcionalnim imenima.
Na računalu, u stvarnosti, nema varanja. Kako god dubili na glavi nećete uštedit vrijeme nikakvim macro, i sličnim virtualnim, naredbama. To je jedino moguće pažljivim postavljanjem strukture programa i samih načina riješavanja problema. Pisanjem što jednostavnijeg algoritma. 
Ja u početku gotovo da uopće nisam koristio macro naredbe upravo zbog navedenih razloga. Kasnije sam ipak, kako su dolazili složeniji programi, počeo i njih koristiti. Zato one i postoje. 
Primjer macro naredbe, malo složeniji:
.macro  set_Vpp1        ; PG 4 // 12V6 pin 13 TSOP48 pin Vpp
    
 lds  r17, PORTG
     ori  r17, 0x10
     sts  PORTG, r17
     nop
.endm
Ovaj primjer nam štedi "papir" tj. pisanje programa čini nešto jednostavnijim i lakše razumljivim. U primjeru vidite da je 
PORTG pozvan naredbom 
lds. U ATm128, ATm104 i sličnim taj port je dio polja skupa registara specijalne namijene i to čiji bitovi nemogu biti direktno pročitani ni upisani. Pa je korištenje macro naredbe tu zaista dobro došlo. 
Kao što vidimo definiranje macro naredbe uvijek počine s 
.macro  IME NAREDBE po našoj želji, slijedi neka naredba ili skup naredbi i obezno završava s 
.endm 
Primjer jednostavnog no nestandardnog glavnog programa:
Code: Select all
MAIN:    call KRENI         ;--- cita status slota -----
         cp r19, r17
          breq maia          ; 
         sts SLOTO, r17      
mair:    rcall AUTOMD         ; ide na auto detekciju stanja slota
maia:    sbis PIND, 5              ;  --- citamo taster rotary SW  
         jmp SBMENU          ;tu je info menu , settingsi i manual mode 
mali:     jmp DBXCOM          ;--!! TESTP za standardni multicam DBXCOM ---- s impulsom
         rjmp MAIN
Ovaj primjer govori da su dva potprograma funkcionalno i stukturno prilično složena (
jmp SBMENU i 
jmp DBXCOM) pa se i vraćanje iz njih obavlja naredbom direktnog skoka ( 
jmp MAIN).  Takvi potprogrami se obično ne pozivaju naredbama 
call, icall, rcall već 
jmp ili ijmp. Iako je i potprogram 
rcall AUTOMD dosta kompleksan ipak njegova struktura dozvoljava standardni poziv i vraćanje. 
Iz same strukture glavnog programa se vidi da se na neki načnim modus glavnog programa preselio u potprogram DBXCOM. Ovo je primjer kad potprogram preuzima funkciju glavnog programa (u većini), a za koje naravno postoje realni razlozi.
Mislim da su ova tri primjera glavnih programa pokazala kako situacija, bolje reći problem, ponekad od nas traže drugačije pristupe postavljanju strukture programa. Sva tri primjera su drastično različita. Najtipični i najčešći je onaj srednji primjer postavljanja glavnog programa.
Uskoro ulazimo u "zonu sumraka", potprograme i rutine, drivere itd.... Tamo gdje se zaista odvija pravi posao.
Today's scientists have substituted mathematics for experiments, and they wander off through equation after equation, and eventually build a structure which has no relation to reality.
- Nikola Tesla