500 likes | 676 Views
Övning 5. Parallellport, Timer. Datorteknik övning 5. Repris: Minnesdisposition. Gles adressrymd Endast en liten del av minnet är utbyggt. (vanligt för inbyggda system). code motsvarar .text. Mellan adresserna 0x800 till 0xA20 finns I/O-kretsar – med allt det roliga på DE2-kortet.
E N D
Övning 5 Parallellport, Timer William Sandqvist william@kth.se
Datorteknik övning 5 William Sandqvist william@kth.se
Repris: Minnesdisposition Gles adressrymd Endast en liten del av minnet är utbyggt. (vanligt för inbyggda system) code motsvarar.text Mellan adresserna 0x800 till 0xA20 finns I/O-kretsar – med allt det roliga på DE2-kortet William Sandqvist william@kth.se
IO-adresserna är speciella Även om IO-enheternas register adresseras som vanligt minne så har dom ju helt andra egenskaper än vad vanligt minne har! Om man skriver talet 17 till DE2-kortets toggle-switchar, så är det ingen magisk kraft som förflyttar dom till ett läge som motsvarar talet 17! Om Du däremot ställer switcharna för hand så att det motsvarar talet 17 så kommer man att kunna läsa talet 17 på denna minnesadress. I C-program bör man använda ordet volatile (flyktigt) om sådana minnesadresser. Då talar man om för kompilatorn att den inte kan räkna med att ett lagrat tal på en sådan minnesadress är det man får tillbaka om man senare läser adressen! William Sandqvist william@kth.se
volatile ? Periferienheter, I/O, ansluts ofta till en CPU som om dom vore minneskretsar (fast med bara ett fåtal ”minnesceller”). Ex. en realtidsklock-krets – håller reda på tid och datum. Den styrs/avläses från 8 inbyggda register. Eftersom I/O-enheter inte är riktiga minnen – det kan verka som om innehållet kan ändras ”av sig självt” – så kan man vid programmeringen av processorn behöva ”hjälpa” kompilatorn att förstå detta genom att deklarera dem som volatile( = flyktiga ) i sina C-program. Har till exempel processorn ett cache-minne är det viktigt att man läser klock-kretsen direkt och inte några äldre ”cachade” tider! William Sandqvist william@kth.se
5.1 de2_pio_toggles18 IO är mappade till minnesadresser. 0x850 … 0x85C William Sandqvist william@kth.se
5.1 inmatning från ”toggles” Get_Data() int Get_Data( void ); .equ toggles18, 0x850 # toggles18’s adress .text # Datasegmentet .align 2 .global Get_Data # label synligt utanför filenGet_Data: movia r8,toggles18 # adressen till toggles i R8 ldw r2,0(r8) # läs toggles till R2 movia r8,0x3ffff # mask med 18 ettor (movia) and r2,r2,r8 # maska bort oanvända bitar ret William Sandqvist william@kth.se
5.1b Get_Data() i C int Get_Data( void ); #define TOGGLES18 ( (unsigned int *) 0x850 ) int Get_Data( void ) { volatileunsignedint * toggles18 = TOGGLES18 ; unsignedint tmp = *toggles18; return( tmp & 0x3ffff ); } William Sandqvist william@kth.se
5.2 de2_pio_geenled9 IO är mappade till minnesadresser. 0xA10 … 0xA1C William Sandqvist william@kth.se
5.2 Utmatning till ”greenled” Green_Light() void Green_Light( int ); .equ greenled9, 0xA10 # greenled9’s adress .text # Datasegmentet .align 2 .global Green_Light # label synligt utanför filenGreen_Light: andi r4,r4,0x1ff # 0:ställ oanvända bitar movia r8,greenled9 # adressen till greenled i R8 stw r4,0(r8) # skriv till LED ret ( stwio r4, 0(r8) om processorn har cacheminne ) William Sandqvist william@kth.se
5.2 b C-kod Green_Light() void Green_Light( int ); #define GREENLED9 ( (unsignedint *)0xa10 )void Green_Light(int lightbits){volatileunsignedint * greenled9 = GREENLED9;unsignedint temp = lightbits & 0x1ff; * greenled = temp;return;} William Sandqvist william@kth.se
de2_pio_redled18 IO är mappade till minnesadresser. 0x810 … 0x81C William Sandqvist william@kth.se
5.3 Sjusegmentdisplayer IO är mappade till minnesadresserna 0xA00 och 0x9F0 William Sandqvist william@kth.se
5.3 Segmentöversikt William Sandqvist william@kth.se
5.3 Teckenöversikt William Sandqvist william@kth.se
Kan Du nu gissa varför simulatorn redovisar att alla oanvända register innehåller ”deadbeef” (dökött)? nörd-humor … William Sandqvist william@kth.se
5.3 Siffran ”0” William Sandqvist william@kth.se
5.3 Siffran ”1” William Sandqvist william@kth.se
5.3a omvandling hex7seg() ASM-funktion som omvandlar en hex-siffra till motsvarande 7-bitskod (för utmatning på 7-segmentdisplay). .data .align 2 # ev. praktiskt att börja på adress delbar med 4 TABLE: # gör en tabell som anger tända och släckta segment noll: .byte 0b00111111 ett: .byte 0b00000110 tvaa: .byte 0b01011011 tre: .byte 0b01001111 fyra: .byte 0b01100110 fem: .byte 0b01101101 sex: .byte 0b01111101 sju: .byte 0b00000111 atta: .byte 0b01111111 nio: .byte 0b01100111 A: .byte 0b01110111 b: .byte 0b01111100 c: .byte 0b01011000 d: .byte 0b01011110 E: .byte 0b01111001 F: .byte 0b01110001 Tabellen gäller aktivt hög lysdiodsdisplay - För den elektronikintresserade … William Sandqvist william@kth.se
5.3a omvandling hex7seg() .text .align 2 .global hex7seg hex7seg: movia r2, TABLE # nu pekar r2 på 0(TABLE) andi r8, r4, 0xF # maska fram 4 LSBits add r2, r2, r8 # nu pekar r2 på ”byte-offset”(TABLE) ldb r2, 0(r2) # nu innehåller r2 koden! # andi r2, r2, 0x7F # onödigt ety LDB gör SignExtend av 0 ret # men det här blev ju lätt! William Sandqvist william@kth.se
5.3b omvandling hex7seg() C-funktion som omvandlar en hex-siffra till motsvarande 7-bitskod (för utmatning på 7-segmentdisplay). Tabellen gäller aktivt låg lysdiodsdisplay int tabell[] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0e };int hex7seg( int hex){registerint tmp = hex & 0xf;return tabell[ tmp ];} - För den elektronikintresserade … William Sandqvist william@kth.se
5.4 Utmatning 4 st 7-segment siffror void PutLow7SegDisp( int ); .equ hex_low28,0x9f0 # adressen till hex_low28 .text # Datasegmentet .align 2 .global PutLow7SegmDisp # label synligt i andra filerPutLow7SegmDisp: movia r8,hex_low28 # adressen till hex_low i R8 stw r4,0(r8) # skriv till 4 st 7-segm siffror ret William Sandqvist william@kth.se
Simulatorn har inga 7-segmentdisplayer? Ett hjälpmedel kan vara att låta utskriften i console-fönstret efterlikna 7-segmentdisplayen! Programmet: put_hexsim(in_value)är skrivet för att uppföra sig exakt som displayen kommer att göra vid laborationen. – Fungerar det med simulatorn, är chansen stor att ditt program även fungerar vid laborationen! William Sandqvist william@kth.se
5.5 toggles 4 7-Segment display William Sandqvist william@kth.se
5.5 toggles 4 7-Segment display main: # main kör evighetsloop – returnerar ej call GetData # hämta värde från toggles, R2 mov r16,r2 # spara värdet i R16 mov r4,r2 # kopiera värdet till R4 call hex7seg # kodomvandling 1:a siffran (C-funktion) mov r17,r2 # spara resultat i R17 srli r4,r16,4 # skifta fram andra hex-siffran call hex7seg # kodomvandling 2:a siffran slli r8,r2,7 # skifta fram till nästa 7 bitar or r17,r17,r8 # lägg till 7 skiftade bitar # fortsättning följer ... William Sandqvist william@kth.se
5.5 toggles 4 7-Seg forts. srli r4,r16,8 # skifta fram tredje hex-siffrancall hex7seg # kodomvandling 3:e siffranslli r8,r2,14 # skifta fram till nästa 7 bitaror r17,r17,r8 # lägg till de skiftade 7 bitarnasrli r4,r16,12 # skifta fram fjärde hex-siffrancall hex7seg # kodomvandling 4:e siffran slli r8,r2,21 # skifta fram till nästa 7 bitaror r17,r17,r8 # lägg till de skiftade 7 bitarnamov r4,r17 # kopiera till R4, parametercall PutLow7SegmDisp # skriv på displayenbr main # main är evighets-loop William Sandqvist william@kth.se
+ call hex7seg William Sandqvist william@kth.se
+ << 7 >> 4 call hex7seg William Sandqvist william@kth.se
+ << 14 >> 8 call hex7seg William Sandqvist william@kth.se
+ << 21 >> 12 Klart! call hex7seg William Sandqvist william@kth.se
5.5 b C-kod 4 7-Segment int main( void ){unsignedint temp;while( 1 ) { temp = Get_Data(); Red_Light( temp ); fixandshow( temp ); }} void fixandshow( unsigned int bitstoshow){unsignedint hexresult; hexresult = hex7seg( bitstoshow ); hexresult = hexresult | hex7seg( bitstoshow >> 4 ) << 7); hexresult = hexresult | hex7seg( bitstoshow >> 8 ) << 14); hexresult = hexresult | hex7seg( bitstoshow >> 12 ) << 21); PutLow7SegDisp( hexresult ) } William Sandqvist william@kth.se
5.6 Nios II Timer William Sandqvist william@kth.se
timer_1 IO är mappade till minnesadresser. 0x920 … 0x934 William Sandqvist william@kth.se
5.7 Delay-rutin med timer Delay: starta timer Loop: läs timer-status registret undersök timeout biten inget ”timeout” loopa igen om det var ”timeout” nollställ timeout biten gör retur från subrutinen Huvudprogram: klock-tick huvudprogrammet skriver ut tiden huvudprogrammet anropar delay huvudprogrammet går i en evighetsslinga William Sandqvist william@kth.se
5.7 Problem med ”enkel” delay William Sandqvist william@kth.se
5.7 Lösning: continuous mode • Timern startar om sig själv vid timeout • Om programmet hinner läsa och 0-ställa timeout biten (inom nedräkningstiden) blir tidmätningen perfekt • Det är med bit 1 i control –registret (0x924) som man väljer continuous mode William Sandqvist william@kth.se
5.7 Körning continuous mode Perfekt tidmätning. William Sandqvist william@kth.se
5.6 inittimer() Att räkna ner från 49999 till timeout (0) tar 1 ms (50 Mhz klocka). Detta tal skall skrivas till de två periodregistren. Continuous biten måste ”1” ställas. Start biten måste ”1” ställas. William Sandqvist william@kth.se
5.6 periodh periodl Att räkna ner från 49999 till timeout (0) tar 1 ms (50 Mhz klocka). Detta tal skall skrivas till de två 16-bitars period-registren. 4999910 = 0000C34F16 peridh = 0x0000periodl =0xC34F William Sandqvist william@kth.se
5.6 inittimer() void inittimer( void ); .equ timer, 0x920 .text .align 2 .global inittimer # synlig i andra filerinittimer: movia r8,timer # basadressen till timern movia r9,0xC34F # R9 = 0xC34F stw r0,12(r8) # periodh = 0x0000 stw r9,8(r8) # periodl = R9 (=0xC34F) movi r9,0b0110 # R9 = 0b0110 (continuous=1 start=1) stw r9,4(r8) # skriv till control ret William Sandqvist william@kth.se
5.6 inittimer() Generell metod att sätta periodregistren till godtyckligt värde: void inittimer( void ); .equ timer, 0x920 .text .align 2 .global inittimer # synlig i andra filerinittimer: movia r8,timer # basadressen till timern movia r9,49999 # R9 = 49999 srli r10,r9,16 # 16 höga bitar kvar stw r10,12(r8) # periodh 16 höga bitar andi r9,r9,0xFFFF # behåll 16 låga bitar stw r9,8(r8) # periodl 16 låga bitar movi r9,0b0110 # R9 = 0b0110 (continuous=1 start=1) stw r9,4(r8) # skriv till control ret William Sandqvist william@kth.se
5.6 C-kod inittimer() void inittimer( void ); #define TIMER1 ( (unsigned int *) 0x920 )#define PERIOD (49999)void inittimer( void ){ volatile unsigned int * Timer1Base = TIMER1; Timer1Base[2] = ( PERIOD & 0xFFFF ); Timer1Base[3] = PERIOD >> 16; Timer1Base[1] = 0x6; /* Start + Continuous */ Timer1Base[0] = 0; } William Sandqvist william@kth.se
5.6 checktimer() int checktimer( void ); .global checktimerchecktimer: movi r2, -1 # defaultvärde till R2 movia r8, Timer1Base # R8 pekar på timerkretsen ldwio r9,0(r8) # status till R9 andi r9, r9, 1 # Bara TimeOut-biten i R9 beq r9,r0,NoTimeOut # hoppa om ingen timeout stwio r0,0(r8) # nollställ TimeOut-biten movi r2,17 # 0-ställ returvärdetNoTimeOut: ret # retur med 0 eller -1 Kvittera efter timeout, 0-ställ timeoutbiten, genom att skriva vad som helst till control registret! William Sandqvist william@kth.se
5.6 C-kod checktimer() int checktimer( void ); int checktimer( void ){volatileunsignedint * Timer1Base = TIMER1;if (Timer1Base[0] & 1) == 0) return (-1);else { Timer1Base[0] = 0;return (0); }} William Sandqvist william@kth.se
5.6 delayt() void delayt( unsigned int millisek); .global delaytdelayt: ble r4,r0,done # klart om R4< 0, negativt push r31 # skydda returadressen ”sub i sub”wait: call checktimer # loopa tills 0-retur blt r2,r0,wait subi r4,r4,1 # minska med 1 (millisekund) bgt r4,r0,wait # fortsätt så länge R4 > 0 pop r31done: ret William Sandqvist william@kth.se
5.6 C-kod delayt() void delayt( unsignedint millisek); void delayt( unsigned int millisek){unsigned int i;for(i = millisek; i>0; i--) { while( checktimer() ) /* do nothing */ ; {} William Sandqvist william@kth.se
5.7 de2_pio_keys4 William Sandqvist william@kth.se
5.7 Get_button() unsigned int Get_Button( void ); .equ keys4,0x840.text.align 2.global Get_ButtonGet_Button: movia r8,keys4 # nu pekar R8 på Knapp-enheten ldwio r2,0(r8) # läs data andi r2,r2,0xF # nollställ bit 31 ... 04 ret William Sandqvist william@kth.se
5.7 C-kod Get_button() unsigned int Get_Button( void ); #define KEYS4 ( (unsignedint *) 0x840unsignedint Get_Button( void ){volatileunsignedint * keys4 = KEYS4;unsignedint temp = * keys4;return( temp & 0xf );} William Sandqvist william@kth.se
Registeranvändning William Sandqvist william@kth.se