Institutionen för data- och elektroteknik 2004-02-22 Inledning En statisk modul bevaras i programminnet mellan bootsidor genom att länkaren ser till att den hamnar i en del av programminnet som inte skrivs över då vi bootar in en ny bootsida. Modulen kan alltså anropas från flera bootsidor. Kom dock ihåg att den statiska modulen läses in tillsammans med den bootsida där den är deklarerad, innan dess finns inte modulen i minnet och kan alltså inte anropas. Det betyder att vill vi från bootsida 2 anropa en statisk modul som finns deklarerad på bootsida 3 så måste bootsida tre ha varit inbootad (inläst) innan bootsida 2 bootas in om vi skall kunna anropa den statiska modulen från bootsida 2. Dock kan bootsida 2 vara inbootad före bootsida 3 om vi ser till att inte anropa den statiska modulen förrän bootsida 3 har varit inläst. På samma sätt bevaras en statisk buffer mellan bootsidor och gör att variabler och data kan överföras mellan bootsidor. Länkaren ser alltså till att denna buffer inte skrivs över då en ny bootsida laddas in. Skall en statisk buffer från början vara initierad med värden så måste den bootsida där allokering och initiering sker läsas in innan bufferten kan användas på andra bootsidor. Vi skall bekanta oss med statiska moduler och variabler samtidigt som vi ser på hur vi kan hantera flera bootsidor genom att studera ett förenklat exempel som inte har annan funktion än att illustrera hanterandet av flera bootsidor och statiska moduler och buffrar, den programkod som finns i olika moduler saknar alltså direkt funktion och är närmast utfyllnad. Vi ser dock till att modulerna har lite olika längd för att se hur länkaren hanterar detta.. Vi ser också på skillnader i allokering mellan linjära (raka) och cirkulära buffrar. På samma gång tar vi tillfället i akt att studera vilken information en minnesallokeringsfil, en MAP-fil, ger. CHALMERS LINDHOLMEN Sida 1 Institutionen för data- och elektroteknik Sven Knutsson Box 8873 402 72 Göteborg Besöksdress: Hörselgången 4 Telefon: 31-772 57 27 Fax: 31-772 57 31 E-mail: svenk@chl.chalmers.se Web: www.chl.chalmers.se/ svenk
Exempel Förutsättningar Vi antar att vi har ett system som skall bestå av tre bootsidor, bootsida 0, 1 och 2. På bootida 0 har vi en submodul (subrutin) kallad sub_0_0 som är deklarerad som statisk. Denna modul anropas även från bootsida 2. Vi har dessutom på bootsida 0 en lokal submodul sub_0_1 som bara anropas från det egna huvudprogrammet. På bootsida 1 har vi en statisk modul, sub_1, som även den anropas från bootsida 2. På bootsida 0 har vi ett antal buffrar enligt nedan Buffertnamn Längd Cirkulär Statisk Minnestyp dm_x 10 ja ja DM dm_0_0 30 ja nej DM dm_0 15 nej nej DM dm_y 8 nej ja DM dm_0_1 6 nej nej DM pm_x 22 nej ja PM Bootsida 1 har buffrarna Buffertnamn Längd Cirkulär Statisk Minnestyp dm_1_0 7 ja nej DM dm_x 10 ja nej DM dm_z 19 ja ja DM dm_0 15 nej nej DM dm_1_1 14 nej nej DM pm_1_0 12 nej nej PM Även bootsida 2 har ett antal buffrar Buffertnamn Längd Cirkulär Statisk Minnestyp dm_2_0 13 nej nej DM dm_2_1 27 ja nej DM dm_x 10 ja ja DM (från bootsida 0) dm_y 8 nej ja DM (från bootsida 0) dm_z 19 ja ja DM (från bootsida 1) Lägg märke till att vi i dataminnet har tre buffrar som är statiska. Av dessa skall två vara synliga på bootsida 0 och 2 (dm_x och dm_y) och en (dm_z) som skall vara synlig på bootsida 1 och 2. I programminnet finns en statiskt deklarerad buffer, denna skall bara vara synlig på bootsida 0. Att denna buffer är statisk betyder här då inte att vi vill nå den från flera bootsidor utan att den skall behålla sina värden mellan de gånger då vi bootar in bootsida 0. Sida 2
Observera också att det även på bootsida 1 finns en buffer med namnet dm_x i dataminne men denna är inte deklarerad som statisk och den är inte synlig från andra bootsidor och då gör det inget att den har samma namn som en buffert på bootsida 0. Lägg dessutom märke till att på både bootsida 0 och 1 har vi deklarerat en buffer i dataminnet med namnet dm_0 men ingen av dessa buffrar är deklarerad som statisk och var och en av de två buffrarna är då en separat buffer som är lokal för sin bootsida. Övriga buffrar är helt skilda, även vad gäller namn, mellan de tre bootsidorna. För att undersöka hur länkaren hanterar minnet så är buffrarna medvetet lagda i en ordning som blandar olika typer av buffrar. Eftersom minnesallokeringen sker på olika sätt i program- och dataminne så finns en buffer deklarerad i programminne. Det som skiljer mellan minnestyperna är buffertarnas placering i minne. Vad som sägs om synlighet etc gäller båda minnestyperna. För att illustrera förloppet så lägger vi upp en arkitekturfil samt en enkel huvudmodul och några submoduler för respektive bootsida. Vi länkar resultatet och låter länkaren generera en MAP-fil där vi kan se minnestilldelningen. Arkitekturfil Vi skriver en enkel arkitekturfil för ett system som bara har internt data- och programminne. Filen måste deklarera tre bootminnesareor, en per bootsida. Dessa areor måste ha olika namn. Vi får {ADSP2105-system med bara internt minne}.system minimalt_2105_system; {system name}.adsp2105; {2105 system}.mmap0; {boot load enable}.seg/rom/boot=0 boot_mem0[1024]; {boot page 0}.SEG/ROM/BOOT=1 boot_mem1[1024]; {boot page 1}.SEG/ROM/BOOT=2 boot_mem2[1024]; {boot page 2}.SEG/PM/RAM/ABS=0/CODE/DATA int_pm[1024]; {internal program memory}.seg/dm/ram/abs=14336/data int_dm[512]; {internal data memory}.endsys; Observera alltså att minnesareorna för de tre bootsidorna måste ges olika namn. Assemblerfiler Bootsida 0 Vi gör ett enkelt program som bara deklarerar ett antal buffrar anropar ett par submoduler och sedan lägger sig i IDLE-läge. {ADSP-2105 Huvudprogram för test av statiska} {cirkulära variabler och moduler } {bootsida 0}.MODULE/RAM/BOOT=0/ABS=0 mainmodul_0;.var/dm/ram/static/circ dm_x[10];.var/dm/ram/circ dm_0_0[30];.var/dm/ram dm_0[15]; {statisk cirkulär buffer} {synlig på bootsida } {0 och 2 } {lokal cirkulär buffer} {lokal buffer} Sida 3
.VAR/DM/RAM/STATIC dm_y[8];.var/dm/ram dm_0_1[6];.var/pm/ram/static pm_x[22];.global dm_x,dm_y;.external sub_0_0,sub_0_1; JUMP start; nop; nop; nop; start: CALL sub_0_0; CALL sub_0_1; wait: IDLE; JUMP wait;.endmod; {statisk buffer synlig} {på bootsida 0 och 2 } {lokal buffer} {statisk buffer synlig} {på bootsida 0 } {dm_x och dm_y synliga} {på andra bootsidor } {submoduler} {restart interrupt} {sampling interrupt IRQ2} {SPORT0 transmit} {SPORT0 receive} {SPORT1 transmit} {SPORT1 receive} {TIMER interrupt} {anropa statisk submodul} {anropa submodul} {wait for interrupt} Lägg märke till att de buffrar som skall vara synliga på andra bootsidor måste deklareras som globala via direktivet.global. Eftersom vi inte vill nå den statiska bufferten pm_x i programminnet från andra moduler så är denna inte deklarerad som GLOBAL. Bufferten är deklarerad som statisk för att variabelvärdena i denna buffer skall ligga kvar om vi efter att vi har låtit programmet boota in en annan bootsida åter vill läsa in bootsida 0 via en ny mjukvarustyrd bootning. Programmet anropar de två submodulerna sub_0_0 och sub_0_1, där den första är statisk medan den andra är dynamisk. Submodul 0_0 På bootsida 0 har vi en statisk submodul som anropas med labeln sub_0_0. Modulen har programkoden {ADSP-2105 Submodul för test av statiska} {icke-cirkulära variabler och moduler } {bootsida 0}.MODULE/RAM/BOOT=0/STATIC submodul_0_0;.external dm_y;.entry sub_0_0; sub_0_0:ax0=dm(dm_y); AR=NOT AX0; DM(dm_y)=AR; RTS;.ENDMOD; Sida 4
Submodul 0_1 På bootsida 0 har vi också en submodul som inte är statisk utan dynamisk och som anropas med labeln sub_0_1. Modulen har programkoden {ADSP-2105 Submodul för test av statiska} {cirkulära variabler och moduler } {bootsida 0}.MODULE/RAM/BOOT=0 submodul_0_1;.external dm_y;.entry sub_0_1; sub_0_1:ax0=ay0; AY0=MX1; RTS;.ENDMOD; Bootsida 1 Bootsida 1 får i princip samma enkla program som bootsida 0, men med sina variabler och submoduler naturligtvis. {ADSP-2105 Huvudprogram för test av statiska} {cirkulära variabler och moduler } {bootsida 1}.MODULE/RAM/BOOT=1/ABS=0 mainmodul_1;.var/dm/ram/circ dm_1_0[7];.var/dm/ram/circ dm_x[10];.var/dm/ram/static/circ dm_z[19];.var/dm/ram dm_0[15];.var/dm/ram dm_1_1[14];.var/pm/ram pm_1_0[12];.global dm_z;.external sub_1; JUMP start; nop; nop; nop; {lokal cirkulär buffer} {lokal cirkulär buffer} {statisk cirkulär buffer} {synlig på bootsida } {1 och 2 } {lokal buffer} {lokal buffer} {lokal buffer} {dm_z synlig på andra} {bootsidor } {anropa statisk submodul} {restart interrupt} {sampling interrupt IRQ2} {SPORT0 transmit} {SPORT0 receive} {SPORT1 transmit} {SPORT1 receive} {TIMER interrupt} start: wait: IDLE; JUMP wait;.endmod; {wait for interrupt} Sida 5
Eftersom vi inte behöver se de statiska buffrarna som deklarerats på bootsida 0 på denna sida så finns inga.external-direktiv, däremot deklareras den nya statiska bufferten (dm_z) som global via direktivet.global för att denna skall kunna nås från andra bootsidor, närmare bestämt från bootsida 2. Denna sida saknar egentlig programkod men den fyller ändå sin funktion vad gäller att illustrera delningen av moduler och buffrar mellan bootsidor. Submodul 1 Även här har vi en statisk submodul. Den anropas med labeln sub_1 och kommer att anropas från bootsida 2. Modulen har programkoden {ADSP-2105 Submodul för test av statiska} {cirkulära variabler och moduler } {bootsida 1}.MODULE/RAM/BOOT=0/STATIC submodul_1;.external dm_y;.entry sub_1; sub_1: SR=ASHIFT SI BY 2 (LO); RTS;.ENDMOD; Bootsida 2 Även här gör vi ett mycket enkelt program men lägger in lite kod som hanterar de statiska buffrar som finns deklarerade på bootsida 0 för att se vad som händer. Eftersom de statiska moduler och buffrar som vi vill nå från denna bootsida är deklarerade på andra bootsidor så skall de inte deklareras på denna bootsida. Vi måste däremot använda.external-direktivet för att kunna se dessa statiska moduler och buffrar även på denna bootsida. {ADSP-2105 Huvudprogram för test av statiska} {cirkulära variabler och moduler } {bootsida 2}.MODULE/RAM/BOOT=2/ABS=0 mainmodul_2;.var/dm/ram dm_2_0[13]; {lokal buffer}.var/dm/ram/circ dm_2_1[27]; {lokal cirkulär buffer}.external dm_x,dm_y,dm_z; {buffertar från } {andra bootsidor}.external sub_0_0,sub_1; {submoduler på } {bootsida 0 och 1} JUMP start; nop; nop; nop; {restart interrupt} {sampling interrupt IRQ2} {SPORT0 transmit} {SPORT0 receive} {SPORT1 transmit} {SPORT1 receive} Sida 6
start: CALL sub_0_0; CALL sub_1; AX0=DM(dm_x); AY0=1; AR=AX0+AY0; DM(dm_y)=AR; AR=AR+AY0; DM(dm_z)=ar; wait: IDLE; JUMP wait;.endmod; {TIMER interrupt} {anropa submodul på} {bootsida 0 } {anropa submodul på} {bootsida 1 } {wait for interrupt} Länkning De tre bootsidorna måste länkas samman till samma EXE-fil. Detta för att länkaren skall klara av tilldelningen av minnesareor (moduler och buffrar). Detta hade varit nödvändigt även om vi hade haft en enda bootsida och om statiska moduler och buffrar hade saknats. Länkning måste ske om så vårt program består av en enda modul. För att se minnestilldelningen så låter vi länkaren generera en MAP-fil. Minnestilldelning Vi ser minnesallokeringen genom nedanstående MAP-fil som länkaren har genererat vid länkningen. Filen är något redigerad för att eliminera oönskade radbrytningar. ADSP-2100 Family Development Tools, Release 6.0.1 Analog Devices, Inc. : ADSP-2100 Family Linker Version 3.1 Copyright 1997 static (static.exe) mapped according to MINIMALT_2105_SYSTEM (static.ach) xref for module: MAINMODUL_0 boot memory page(s) 0, MAINMODUL_0 pm 0:0000 [0020] module(global) DM_X dm 0:3800 [000A] variable(global) DM_0_0 dm 0:3840 [001E] variable DM_0 dm 0:385E [000F] variable DM_Y dm 0:380A [0008] variable(global) DM_0_1 dm 0:3812 [0006] variable PM_X pm 0:0030 [0016] variable START pm 0:001C label WAIT pm 0:001E label SUB_0_0 0:03FC [0000] extern(submodul_0_0) SUB_0_1 0:0020 [0000] extern(submodul_0_1) xref for module: MAINMODUL_1 boot memory page(s) 1, MAINMODUL_1 DM_1_0 pm 1:0000 [001E] module(global) dm 1:3818 [0007] variable Sida 7
DM_X dm 1:3840 [000A] variable DM_Z dm 1:3820 [0013] variable(global) DM_0 dm 1:384A [000F] variable DM_1_1 dm 1:3859 [000E] variable PM_1_0 pm 1:001E [000C] variable START pm 1:001C label WAIT pm 1:001C label SUB_1 1:03FA [0000] extern(submodul_1) xref for module: MAINMODUL_2 boot memory page(s) 2, MAINMODUL_2 pm 2:0000 [0026] module(global) DM_2_0 dm 2:3812 [000D] variable DM_2_1 dm 2:3840 [001B] variable START pm 2:001C label WAIT pm 2:0024 label SUB_0_0 2:03FC [0000] extern(submodul_0_0) DM_X 2:3800 [000A] extern(mainmodul_0) DM_Y 2:380A [0008] extern(mainmodul_0) DM_Z 2:3820 [0013] extern(mainmodul_1) SUB_1 2:03FA [0000] extern(submodul_1) xref for module: SUBMODUL_0_0 boot memory page(s) 0, SUBMODUL_0_0 pm 0:03FC [0004] module(global) SUB_0_0 pm 0:03FC label(global) DM_Y 0:380A [0008] extern(mainmodul_0) xref for module: SUBMODUL_0_1 boot memory page(s) 0, SUBMODUL_0_1 pm 0:0020 [0003] module(global) SUB_0_1 pm 0:0020 label(global) DM_Y 0:380A [0008] extern(mainmodul_0) xref for module: SUBMODUL_1 boot memory page(s) 0, SUBMODUL_1 pm 0:03FA [0002] module(global) SUB_1 pm 0:03FA label DM_Y 0:380A [0008] extern(mainmodul_0) 210x memory per MINIMALT_2105_SYSTEM (static.ach) internal 2105 pm ram mapped to 0000-07ff (auto booted at reset) internal 2105 dm ram mapped to 3800-3BFF 0000-03FF [ 1024.] external bm rom code BOOT_MEM0 0800-0BFF [ 1024.] external bm rom code BOOT_MEM1 1000-13FF [ 1024.] external bm rom code BOOT_MEM2 0000-03FF [ 1024.] internal pm ram data/code INT_PM 3800-39FF [ 512.] internal dm ram data INT_DM boot memory and bootable run time program memory map: boot page 0 (auto boot) bm: 0000-001F (x8rom: 0000-007F) 0000-001F [32.] ram module MAINMODUL_0 bm: 0020-0022 (x8rom: 0080-008B) 0020-0022 [ 3.] ram module SUBMODUL_0_1 boot page 1 Sida 8
bm: 0800-081D (x8rom: 2000-2077) 0000-001D [30.] ram module AINMODUL_1 bm: 081E - 0829 (x8rom: 2078-20A7) 001E - 0029 [12.] ram variable PM_1_0 of MAINMODUL_1 boot page 2 bm: 1000-1025 (x8rom: 4000-4097) 0000-0025 [38.] ram module MAINMODUL_2 24k of boot memory rom space required for this bootable run time map. Most convenient boot memory rom size is 24k bytes (192k bits). fixed program memory map: 0030-0045 [ 22.] pm ram static variable PM_X of MAINMODUL_0 03FA - 03FB [ 2.] pm ram page(s) 0,static module SUBMODUL_1 03FC - 03FF [ 4.] pm ram page(s) 0,static module SUBMODUL_0_0 fixed program memory rom: 0. fixed program memory ram: 28. dynamic data memory map: boot page 0 3812-3817 [ 6.] ram variable DM_0_1 of MAINMODUL_0 3840-385D [ 30.] ram circ variable DM_0_0 of MAINMODUL_0 385E - 386C [ 15.] ram variable DM_0 of MAINMODUL_0 dynamic data memory rom page 0: 0 dynamic data memory ram page 0: 51 boot page 1 3818-381E [ 7.] ram circ variable DM_1_0 of MAINMODUL_1 3840-3849 [ 10.] ram circ variable DM_X of MAINMODUL_1 384A - 3858 [ 15.] ram variable DM_0 of MAINMODUL_1 3859-3866 [ 14.] ram variable DM_1_1 of MAINMODUL_1 dynamic data memory rom page 1: 0 dynamic data memory ram page 1: 46 boot page 2 3812-381E [ 13.] ram variable DM_2_0 of MAINMODUL_2 3840-385A [ 27.] ram circ variable DM_2_1 of MAINMODUL_2 dynamic data memory rom page 2: 0 dynamic data memory ram page 2: 40 fixed data memory map: 3800-3809 [ 10.] dm ram circ variable static DM_X of MAINMODUL_0 380A - 3811 [ 8.] dm ram variable static DM_Y of MAINMODUL_0 3820-3832 [ 19.] dm ram circ variable static DM_Z of MAINMODUL_1 fixed data memory rom: 0. fixed data memory ram: 37. Sida 9
Vad visar MAP-filen MAP-filen inleds med en beskrivning av hur olika minnesareor utnyttjas på de tre bootsidorna. Här kan vi se att programkoden hamnar från adress noll (0) i programminnet för att börja köras vid inläsning av respektive bootsida. Vi ser också programkodens längd. Vi ser därefter hur variablerna är placerade i minnet. Vi ser att statiska variabler är angivna som variable(global) medan övriga variabler bara anges som variable. Vi återkommer till variabelallokeringen. Vi hittar här också namn och adress för de lablar som används på olika bootsidor samt de namn på allokerade minnesareor som används. De modullablar och namn på minnesareor som ligger i en annan modul anges som extern, där vi också kan se namnet på den modul där labeln eller minnesdeklarationen finns. De tre submodulerna är beskrivna var för sig på samma sätt som ovan. Efter detta följer en del som sammanfattar adresser och namn på alla tillgängliga minnesareor. Lägg märke till att de tre bootminnesareorna ligger i adressintervallen 0 1k, 2k 3k respektive 4k 5k i bootminne. Areorna är alltså 1k långa med en lucka på 1k mellan respektive area. Denna lucka beror på kompabiliteten med processorn ADSP-2101 som har 2k stora bootareor. Med outnyttjade minnesareor blir bootminnet då 6k stort men eftersom varje intruktion upptar fyra positioner i ett 8 bitars minne (tre positioner med 8 bitar av instruktionen plus en tom position) så anger MAP-filen att vi behöver ett 24k stort minne. MAP-filen avslutas med ytterligare en beskrivning av minnesallokeringen för variablerna på de olika bootsidorna. Här anges variabelnamn, minnestyp samt vilka adresser som variabeln upptar. Variabler som skall användas på flera bootsidor och därför är statiska anges som låsta (fixed memory map) medan variabler som kan skrivas över då en ny bootsida läses in anges som dynamiska (dynamic memory map). Buffrar i programminne Eftersom vi har deklarerat dessa buffrar i programminne så kommer naturligtvis minne att allokeras i detta minne. Vi har bara internt programminne och detta startar på adress 0x0000. Även om vi hade haft externt programminne så skulle länkaren ha börjat med att fylla internt programminne om vi inte via segment- eller absolutdirektiv (SEG respektive ABS) hade angivit att vissa buffrar skulle ligga i externt minne. Det interna programminnet ligger alltså i adressintervallet 0x0000-0x03FF och program och programminnesbuffrar måste placeras i detta intervall. Ur MAP-filen får vi följande karta över programminnet Sida 10
. Figur 1 Karta över programminnet För att avbrottstabellen skall komma på rätt adresser så skall huvudprogrammet placeras från adress 0x0000 på varje bootsida. Vi har säkerställt detta genom att ange direktivet ABS=0 i huvudmodulens inledningsrad. Sida 11
Vi ser att den dynamiska submodulen sub_0_1 på bootsida 0 placeras direkt efter huvudprogrammet och att både huvudprogram och submodul kommer att skrivas över då en ny bootsida laddas in. De två statiska submodulerna, sub_0_0 och sub_1, däremot placeras sist i det interna programminnet för att undvika att de skrivs över vid byte av bootsida. Om vi övergår till buffrarna så ser vi att den statiska bufferten pm_x placeras så högt i programminnet att ingen dynamisk programudul eller buffer kommer att skriva över den vid byte av bootsida. Den dynamiska bufferten pm_1_0 på bootsida 1 placeras däremot direkt efter programkoden eftersom vi tillåter att den skrivs över vid byte av bootsida. Buffrar i dataminne På samma sätt ger MAP-filen följande bild av dataminnet. Sida 12
Figur 2 Dataminnskarta med cirkulära buffrar Minneskartan kan synas rörig och onödigt splittrad i smådelar men det finns en logik i röran. I normala fall skulle länkaren tilldela minne i den ordning som buffrarna dyker upp i assemblerfilen och därmed lägga dom i denna ordning efter varandra i minnet. Nu när vi har statiska buffrar så ser vi att länkaren i stället inleder med att allokera minne för dessa. Detta verkar ju logiskt eftersom de statiska buffrarna då kommer i minnesareans början och inte låser upp areor någonstans mitt i det interna dataminnet. Varken dessa eller de dynamiska buffrarna ligger dock i en följd på efterföljande adresser. Detta beror på att vissa av buffrarna är cirkulära och skall adresseringen av dessa fungera så måste buffertens basadress vara en heltalsmultipel av det tal vi får om vi avrundar den aktuella bufferlängden till nästa tvåpotens. En 9 positioner lång Sida 13
4 buffer måste alltså ha basadressen på en heltalsmultipel av 2 = 1610 = 1016.Detta leder till exempel till att den cirkulära (och statiska) bufferten dm_z hamnar på adress 0x3820 och inte på den tomma adressen 0x381F som finns direkt efter bufferten dm_1_0. Lägg märke till att den minnesarea som innehåller de tre statiska buffrarna inte täcks av nya buffrar då en ny bootsida läses in utan bufferternas innehåll finns kvar i minnet. Observera dock att de statiska buffrarna bara är tillgängliga från den bootsida där de är deklarerade (bootsida 0 respektive bootsida 1) och den bootsida (eller de bootsidor) där de är deklarerade som EXTERNAL (bootsida 2). På bootsida 1 kan vi inte nå buffrarna dm_x och dm_y och på bootsida 0 kan vi inte nå bufferten dm_z. Lägg dessutom märke till att de buffrar som har deklarerats med samma namn och längd på bootsida 0 och 1 (dm_0), men som inte är statiska, inte ligger på samma adresser och då en ny bootsida läses in kommer dessa areor att upptas av andra variabler. Dessa två buffrar är alltså inte samma buffer på de två bootsidorna utan två skilda buffrar. På bootsida 1 finns dessutom bufferten dm_x deklarerad. Bufferten har alltså samma namn och även samma storlek som den statiska bufferten dm_x som är synlig på bootsida 0 och 2, men eftersom bootsida 1 saknar något EXTERNAL-direktiv för bufferten dm_x så är bufferten med detta namn på bootsida 1 en annan buffer än den statiska globala bufferten med namnet dm_x och den ligger därför på en annan adress. Skulle vi ha försökt att göra den statiska bufferten synlig på bootsida 1 så skulle vi ha fått ett assembleringsfel. Vi kan inte ha två buffrar med samma namn synliga samtidigt. Hade vi inte använt cirkulära buffrar så hade vi inte fått luckorna i ovanstående minneskarta utan vi hade fått nedanstående bild där alla minnesbuffrar ligger på efterföljande adresser. Sida 14
Figur 3 Dataminneskarta utan cirkulära buffrar Sida 15